Merge branch 'for-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq

Pull workqueue changes from Tejun Heo:
 "This contains only one commit which cleans up UP allocation path a
  bit."

* 'for-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq:
  workqueue: use percpu allocator for cwq on UP
diff --git a/Documentation/ABI/removed/devfs b/Documentation/ABI/removed/devfs
index 8ffd28b..0020c49 100644
--- a/Documentation/ABI/removed/devfs
+++ b/Documentation/ABI/removed/devfs
@@ -1,6 +1,6 @@
 What:		devfs
 Date:		July 2005 (scheduled), finally removed in kernel v2.6.18
-Contact:	Greg Kroah-Hartman <gregkh@suse.de>
+Contact:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 Description:
 	devfs has been unmaintained for a number of years, has unfixable
 	races, contains a naming policy within the kernel that is
diff --git a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
index 9a75fb2..23a43b8 100644
--- a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
+++ b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
@@ -1,7 +1,7 @@
 What:		/sys/bus/usb/drivers/usbtmc/devices/*/interface_capabilities
 What:		/sys/bus/usb/drivers/usbtmc/devices/*/device_capabilities
 Date:		August 2008
-Contact:	Greg Kroah-Hartman <gregkh@suse.de>
+Contact:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 Description:
 		These files show the various USB TMC capabilities as described
 		by the device itself.  The full description of the bitfields
@@ -15,7 +15,7 @@
 What:		/sys/bus/usb/drivers/usbtmc/devices/*/usb488_interface_capabilities
 What:		/sys/bus/usb/drivers/usbtmc/devices/*/usb488_device_capabilities
 Date:		August 2008
-Contact:	Greg Kroah-Hartman <gregkh@suse.de>
+Contact:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 Description:
 		These files show the various USB TMC capabilities as described
 		by the device itself.  The full description of the bitfields
@@ -29,7 +29,7 @@
 
 What:		/sys/bus/usb/drivers/usbtmc/devices/*/TermChar
 Date:		August 2008
-Contact:	Greg Kroah-Hartman <gregkh@suse.de>
+Contact:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 Description:
 		This file is the TermChar value to be sent to the USB TMC
 		device as described by the document, "Universal Serial Bus Test
@@ -42,7 +42,7 @@
 
 What:		/sys/bus/usb/drivers/usbtmc/devices/*/TermCharEnabled
 Date:		August 2008
-Contact:	Greg Kroah-Hartman <gregkh@suse.de>
+Contact:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 Description:
 		This file determines if the TermChar is to be sent to the
 		device on every transaction or not.  For more details about
@@ -53,7 +53,7 @@
 
 What:		/sys/bus/usb/drivers/usbtmc/devices/*/auto_abort
 Date:		August 2008
-Contact:	Greg Kroah-Hartman <gregkh@suse.de>
+Contact:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 Description:
 		This file determines if the the transaction of the USB TMC
 		device is to be automatically aborted if there is any error.
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index b4f5487..7c22a53 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -182,3 +182,14 @@
 		USB2 hardware LPM is enabled for the device. Developer can
 		write y/Y/1 or n/N/0 to the file to enable/disable the
 		feature.
+
+What:		/sys/bus/usb/devices/.../removable
+Date:		February 2012
+Contact:	Matthew Garrett <mjg@redhat.com>
+Description:
+		Some information about whether a given USB device is
+		physically fixed to the platform can be inferred from a
+		combination of hub decriptor bits and platform-specific data
+		such as ACPI. This file will read either "removable" or
+		"fixed" if the information is available, and "unknown"
+		otherwise.
\ No newline at end of file
diff --git a/Documentation/ABI/testing/sysfs-class b/Documentation/ABI/testing/sysfs-class
index 4b0cb89..676530f 100644
--- a/Documentation/ABI/testing/sysfs-class
+++ b/Documentation/ABI/testing/sysfs-class
@@ -1,6 +1,6 @@
 What:		/sys/class/
 Date:		Febuary 2006
-Contact:	Greg Kroah-Hartman <gregkh@suse.de>
+Contact:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 Description:
 		The /sys/class directory will consist of a group of
 		subdirectories describing individual classes of devices
diff --git a/Documentation/ABI/testing/sysfs-devices b/Documentation/ABI/testing/sysfs-devices
index 6a25671..5fcc943 100644
--- a/Documentation/ABI/testing/sysfs-devices
+++ b/Documentation/ABI/testing/sysfs-devices
@@ -1,6 +1,6 @@
 What:		/sys/devices
 Date:		February 2006
-Contact:	Greg Kroah-Hartman <gregkh@suse.de>
+Contact:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 Description:
 		The /sys/devices tree contains a snapshot of the
 		internal state of the kernel device tree.  Devices will
diff --git a/Documentation/ABI/testing/sysfs-devices-soc b/Documentation/ABI/testing/sysfs-devices-soc
new file mode 100644
index 0000000..6d9cc25
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-soc
@@ -0,0 +1,58 @@
+What:		/sys/devices/socX
+Date:		January 2012
+contact:	Lee Jones <lee.jones@linaro.org>
+Description:
+		The /sys/devices/ directory contains a sub-directory for each
+		System-on-Chip (SoC) device on a running platform. Information
+		regarding each SoC can be obtained by reading sysfs files. This
+		functionality is only available if implemented by the platform.
+
+		The directory created for each SoC will also house information
+		about devices which are commonly contained in /sys/devices/platform.
+		It has been agreed that if an SoC device exists, its supported
+		devices would be better suited to appear as children of that SoC.
+
+What:		/sys/devices/socX/machine
+Date:		January 2012
+contact:	Lee Jones <lee.jones@linaro.org>
+Description:
+		Read-only attribute common to all SoCs. Contains the SoC machine
+		name (e.g. Ux500).
+
+What:		/sys/devices/socX/family
+Date:		January 2012
+contact:	Lee Jones <lee.jones@linaro.org>
+Description:
+		Read-only attribute common to all SoCs. Contains SoC family name
+		(e.g. DB8500).
+
+What:		/sys/devices/socX/soc_id
+Date:		January 2012
+contact:	Lee Jones <lee.jones@linaro.org>
+Description:
+		Read-only attribute supported by most SoCs. In the case of
+		ST-Ericsson's chips this contains the SoC serial number.
+
+What:		/sys/devices/socX/revision
+Date:		January 2012
+contact:	Lee Jones <lee.jones@linaro.org>
+Description:
+		Read-only attribute supported by most SoCs. Contains the SoC's
+		manufacturing revision number.
+
+What:		/sys/devices/socX/process
+Date:		January 2012
+contact:	Lee Jones <lee.jones@linaro.org>
+Description:
+		Read-only attribute supported ST-Ericsson's silicon. Contains the
+		the process by which the silicon chip was manufactured.
+
+What:		/sys/bus/soc
+Date:		January 2012
+contact:	Lee Jones <lee.jones@linaro.org>
+Description:
+		The /sys/bus/soc/ directory contains the usual sub-folders
+		expected under most buses. /sys/bus/soc/devices is of particular
+		interest, as it contains a symlink for each SoC device found on
+		the system. Each symlink points back into the aforementioned
+		/sys/devices/socX devices.
diff --git a/Documentation/ABI/testing/sysfs-driver-samsung-laptop b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
index 0a81023..e82e7c2 100644
--- a/Documentation/ABI/testing/sysfs-driver-samsung-laptop
+++ b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
@@ -1,7 +1,7 @@
 What:		/sys/devices/platform/samsung/performance_level
 Date:		January 1, 2010
 KernelVersion:	2.6.33
-Contact:	Greg Kroah-Hartman <gregkh@suse.de>
+Contact:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 Description:	Some Samsung laptops have different "performance levels"
 		that are can be modified by a function key, and by this
 		sysfs file.  These values don't always make a whole lot
diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt
index c43460d..7c1dfb1 100644
--- a/Documentation/RCU/RTFP.txt
+++ b/Documentation/RCU/RTFP.txt
@@ -1,9 +1,10 @@
-Read the F-ing Papers!
+Read the Fscking Papers!
 
 
 This document describes RCU-related publications, and is followed by
 the corresponding bibtex entries.  A number of the publications may
-be found at http://www.rdrop.com/users/paulmck/RCU/.
+be found at http://www.rdrop.com/users/paulmck/RCU/.  For others, browsers
+and search engines will usually find what you are looking for.
 
 The first thing resembling RCU was published in 1980, when Kung and Lehman
 [Kung80] recommended use of a garbage collector to defer destruction
@@ -160,7 +161,26 @@
 [MathieuDesnoyersPhD].  TINY_RCU [PaulEMcKenney2009BloatWatchRCU] made
 its appearance, as did expedited RCU [PaulEMcKenney2009expeditedRCU].
 The problem of resizeable RCU-protected hash tables may now be on a path
-to a solution [JoshTriplett2009RPHash].
+to a solution [JoshTriplett2009RPHash].  A few academic researchers are now
+using RCU to solve their parallel problems [HariKannan2009DynamicAnalysisRCU].
+
+2010 produced a simpler preemptible-RCU implementation
+based on TREE_RCU [PaulEMcKenney2010SimpleOptRCU], lockdep-RCU
+[PaulEMcKenney2010LockdepRCU], another resizeable RCU-protected hash
+table [HerbertXu2010RCUResizeHash] (this one consuming more memory,
+but allowing arbitrary changes in hash function, as required for DoS
+avoidance in the networking code), realization of the 2009 RCU-protected
+hash table with atomic node move [JoshTriplett2010RPHash], an update on
+the RCU API [PaulEMcKenney2010RCUAPI].
+
+2011 marked the inclusion of Nick Piggin's fully lockless dentry search
+[LinusTorvalds2011Linux2:6:38:rc1:NPigginVFS], an RCU-protected red-black
+tree using software transactional memory to protect concurrent updates
+(strange, but true!) [PhilHoward2011RCUTMRBTree], yet another variant of
+RCU-protected resizeable hash tables [Triplett:2011:RPHash], the 3.0 RCU
+trainwreck [PaulEMcKenney2011RCU3.0trainwreck], and Neil Brown's "Meet the
+Lockers" LWN article [NeilBrown2011MeetTheLockers].
+
 
 Bibtex Entries
 
@@ -173,6 +193,14 @@
 ,volume="5"
 ,number="3"
 ,pages="354-382"
+,note="Available:
+\url{http://portal.acm.org/citation.cfm?id=320619&dl=GUIDE,}
+[Viewed December 3, 2007]"
+,annotation={
+	Use garbage collector to clean up data after everyone is done with it.
+	.
+	Oldest use of something vaguely resembling RCU that I have found.
+}
 }
 
 @techreport{Manber82
@@ -184,6 +212,31 @@
 ,number="82-01-01"
 ,month="January"
 ,pages="28"
+,annotation={
+	.
+	Superseded by Manber84.
+	.
+	Describes concurrent AVL tree implementation.  Uses a
+	garbage-collection mechanism to handle concurrent use and deletion
+	of nodes in the tree, but lacks the summary-of-execution-history
+	concept of read-copy locking.
+	.
+	Keeps full list of processes that were active when a given
+	node was to be deleted, and waits until all such processes have
+	-terminated- before allowing this node to be reused.  This is
+	not described in great detail -- one could imagine using process
+	IDs for this if the ID space was large enough that overlapping
+	never occurred.
+	.
+	This restriction makes this algorithm unsuitable for use in
+	systems comprised of long-lived processes.  It also produces
+	completely unacceptable overhead in systems with large numbers
+	of processes.  Finally, it is specific to AVL trees.
+	.
+	Cites Kung80, so not an independent invention, but the first
+	RCU-like usage that does not rely on an automatic garbage
+	collector.
+}
 }
 
 @article{Manber84
@@ -195,6 +248,74 @@
 ,volume="9"
 ,number="3"
 ,pages="439-455"
+,annotation={
+	Describes concurrent AVL tree implementation.  Uses a
+	garbage-collection mechanism to handle concurrent use and deletion
+	of nodes in the tree, but lacks the summary-of-execution-history
+	concept of read-copy locking.
+	.
+	Keeps full list of processes that were active when a given
+	node was to be deleted, and waits until all such processes have
+	-terminated- before allowing this node to be reused.  This is
+	not described in great detail -- one could imagine using process
+	IDs for this if the ID space was large enough that overlapping
+	never occurred.
+	.
+	This restriction makes this algorithm unsuitable for use in
+	systems comprised of long-lived processes.  It also produces
+	completely unacceptable overhead in systems with large numbers
+	of processes.  Finally, it is specific to AVL trees.
+}
+}
+
+@Conference{RichardRashid87a
+,Author="Richard Rashid and Avadis Tevanian and Michael Young and
+David Golub and Robert Baron and David Black and William Bolosky and
+Jonathan Chew"
+,Title="Machine-Independent Virtual Memory Management for Paged
+Uniprocessor and Multiprocessor Architectures"
+,Booktitle="{2\textsuperscript{nd} Symposium on Architectural Support
+for Programming Languages and Operating Systems}"
+,Publisher="Association for Computing Machinery"
+,Month="October"
+,Year="1987"
+,pages="31-39"
+,Address="Palo Alto, CA"
+,note="Available:
+\url{http://www.cse.ucsc.edu/~randal/221/rashid-machvm.pdf}
+[Viewed February 17, 2005]"
+,annotation={
+	Describes lazy TLB flush, where one waits for each CPU to pass
+	through a scheduling-clock interrupt before reusing a given range
+	of virtual address.  Does not describe how one determines that
+	all CPUs have in fact taken such an interrupt, though there are
+	no shortage of straightforward methods for accomplishing this.
+	.
+	Note that it does not make sense to just wait a fixed amount of
+	time, since a given CPU might have interrupts disabled for an
+	extended amount of time.
+}
+}
+
+@article{BarbaraLiskov1988ArgusCACM
+,author = {Barbara Liskov}
+,title = {Distributed programming in {Argus}}
+,journal = {Commun. ACM}
+,volume = {31}
+,number = {3}
+,year = {1988}
+,issn = {0001-0782}
+,pages = {300--312}
+,doi = {http://doi.acm.org/10.1145/42392.42399}
+,publisher = {ACM}
+,address = {New York, NY, USA}
+,annotation= {
+	At the top of page 307: "Conflicts with deposits and withdrawals
+	are necessary if the reported total is to be up to date.  They
+	could be avoided by having total return a sum that is slightly
+	out of date."  Relies on semantics -- approximate numerical
+	values sometimes OK.
+}
 }
 
 @techreport{Hennessy89
@@ -216,6 +337,13 @@
 ,year="1990"
 ,number="CS-TR-2222.1"
 ,month="June"
+,annotation={
+	Concurrent access to skip lists.  Has both weak and strong search.
+	Uses concept of ``garbage queue'', but has no real way of cleaning
+	the garbage efficiently.
+	.
+	Appears to be an independent invention of an RCU-like mechanism.
+}
 }
 
 @Book{Adams91
@@ -223,20 +351,15 @@
 ,title="Concurrent Programming, Principles, and Practices"
 ,Publisher="Benjamin Cummins"
 ,Year="1991"
+,annotation={
+	Has a few paragraphs describing ``chaotic relaxation'', a
+	numerical analysis technique that allows multiprocessors to
+	avoid synchronization overhead by using possibly-stale data.
+	.
+	Seems like this is descended from yet another independent
+	invention of RCU-like function -- but this is restricted
+	in that reclamation is not necessary.
 }
-
-@phdthesis{HMassalinPhD
-,author="H. Massalin"
-,title="Synthesis: An Efficient Implementation of Fundamental Operating
-System Services"
-,school="Columbia University"
-,address="New York, NY"
-,year="1992"
-,annotation="
-	Mondo optimizing compiler.
-	Wait-free stuff.
-	Good advice: defer work to avoid synchronization.
-"
 }
 
 @unpublished{Jacobson93
@@ -244,7 +367,13 @@
 ,title="Avoid Read-Side Locking Via Delayed Free"
 ,year="1993"
 ,month="September"
-,note="Verbal discussion"
+,note="private communication"
+,annotation={
+	Use fixed time delay to approximate grace period.  Very simple,
+	but subject to random memory corruption under heavy load.
+	.
+	Independent invention of RCU-like mechanism.
+}
 }
 
 @Conference{AjuJohn95
@@ -256,6 +385,17 @@
 ,Year="1995"
 ,pages="11-23"
 ,Address="New Orleans, LA"
+,note="Available:
+\url{https://www.usenix.org/publications/library/proceedings/neworl/full_papers/john.a}
+[Viewed October 1, 2010]"
+,annotation={
+	Age vnodes out of the cache, and have a fixed time set by a kernel
+	parameter.  Not clear that all races were in fact correctly handled.
+	Used a 20-minute time by default, which would most definitely not
+	be suitable during DoS attacks or virus scans.
+	.
+	Apparently independent invention of RCU-like mechanism.
+}
 }
 
 @conference{Pu95a,
@@ -301,31 +441,47 @@
 ,institution="US Patent and Trademark Office"
 ,address="Washington, DC"
 ,year="1995"
-,number="US Patent 5,442,758 (contributed under GPL)"
+,number="US Patent 5,442,758"
 ,month="August"
+,annotation={
+	Describes the parallel RCU infrastructure.  Includes NUMA aspect
+	(structure of bitmap can reflect bus structure of computer system).
+	.
+	Another independent invention of an RCU-like mechanism, but the
+	"real" RCU this time!
+}
 }
 
 @techreport{Slingwine97
 ,author="John D. Slingwine and Paul E. McKenney"
-,title="Method for maintaining data coherency using thread
-activity summaries in a multicomputer system"
+,title="Method for Maintaining Data Coherency Using Thread Activity
+Summaries in a Multicomputer System"
 ,institution="US Patent and Trademark Office"
 ,address="Washington, DC"
 ,year="1997"
-,number="US Patent 5,608,893 (contributed under GPL)"
+,number="US Patent 5,608,893"
 ,month="March"
+,pages="19"
+,annotation={
+	Describes use of RCU to synchronize data between a pair of
+	SMP/NUMA computer systems.
+}
 }
 
 @techreport{Slingwine98
 ,author="John D. Slingwine and Paul E. McKenney"
-,title="Apparatus and method for achieving reduced overhead
-mutual exclusion and maintaining coherency in a multiprocessor
-system utilizing execution history and thread monitoring"
+,title="Apparatus and Method for Achieving Reduced Overhead Mutual
+Exclusion and Maintaining Coherency in a Multiprocessor System
+Utilizing Execution History and Thread Monitoring"
 ,institution="US Patent and Trademark Office"
 ,address="Washington, DC"
 ,year="1998"
-,number="US Patent 5,727,209 (contributed under GPL)"
+,number="US Patent 5,727,209"
 ,month="March"
+,annotation={
+	Describes doing an atomic update by copying the data item and
+	then substituting it into the data structure.
+}
 }
 
 @Conference{McKenney98
@@ -337,6 +493,15 @@
 ,Year="1998"
 ,pages="509-518"
 ,Address="Las Vegas, NV"
+,note="Available:
+\url{http://www.rdrop.com/users/paulmck/RCU/rclockpdcsproof.pdf}
+[Viewed December 3, 2007]"
+,annotation={
+	Describes and analyzes RCU mechanism in DYNIX/ptx.  Describes
+	application to linked list update and log-buffer flushing.
+	Defines 'quiescent state'.  Includes both measured and analytic
+	evaluation.
+}
 }
 
 @Conference{Gamsa99
@@ -349,18 +514,76 @@
 ,Year="1999"
 ,pages="87-100"
 ,Address="New Orleans, LA"
+,note="Available:
+\url{http://www.usenix.org/events/osdi99/full_papers/gamsa/gamsa.pdf}
+[Viewed August 30, 2006]"
+,annotation={
+	Use of RCU-like facility in K42/Tornado.  Another independent
+	invention of RCU.
+	See especially pages 7-9 (Section 5).
+}
+}
+
+@unpublished{RustyRussell2000a
+,Author="Rusty Russell"
+,Title="Re: modular net drivers"
+,month="June"
+,year="2000"
+,day="23"
+,note="Available:
+\url{http://oss.sgi.com/projects/netdev/archive/2000-06/msg00250.html}
+[Viewed April 10, 2006]"
+,annotation={
+	Proto-RCU proposal from Phil Rumpf and Rusty Russell.
+	Yet another independent invention of RCU.
+	Outline of algorithm to unload modules...
+	.
+	Appeared on net-dev mailing list.
+}
+}
+
+@unpublished{RustyRussell2000b
+,Author="Rusty Russell"
+,Title="Re: modular net drivers"
+,month="June"
+,year="2000"
+,day="24"
+,note="Available:
+\url{http://oss.sgi.com/projects/netdev/archive/2000-06/msg00254.html}
+[Viewed April 10, 2006]"
+,annotation={
+	Proto-RCU proposal from Phil Rumpf and Rusty Russell.
+	.
+	Appeared on net-dev mailing list.
+}
+}
+
+@unpublished{McKenney01b
+,Author="Paul E. McKenney and Dipankar Sarma"
+,Title="Read-Copy Update Mutual Exclusion in {Linux}"
+,month="February"
+,year="2001"
+,note="Available:
+\url{http://lse.sourceforge.net/locking/rcu/rcupdate_doc.html}
+[Viewed October 18, 2004]"
+,annotation={
+	Prototypical Linux documentation for RCU.
+}
 }
 
 @techreport{Slingwine01
 ,author="John D. Slingwine and Paul E. McKenney"
-,title="Apparatus and method for achieving reduced overhead
-mutual exclusion and maintaining coherency in a multiprocessor
-system utilizing execution history and thread monitoring"
+,title="Apparatus and Method for Achieving Reduced Overhead Mutual
+Exclusion and Maintaining Coherency in a Multiprocessor System
+Utilizing Execution History and Thread Monitoring"
 ,institution="US Patent and Trademark Office"
 ,address="Washington, DC"
 ,year="2001"
-,number="US Patent 5,219,690 (contributed under GPL)"
+,number="US Patent 6,219,690"
 ,month="April"
+,annotation={
+	'Change in mode' aspect of RCU.  Can be thought of as a lazy barrier.
+}
 }
 
 @Conference{McKenney01a
@@ -372,14 +595,61 @@
 ,Year="2001"
 ,note="Available:
 \url{http://www.linuxsymposium.org/2001/abstracts/readcopy.php}
-\url{http://www.rdrop.com/users/paulmck/rclock/rclock_OLS.2001.05.01c.pdf}
+\url{http://www.rdrop.com/users/paulmck/RCU/rclock_OLS.2001.05.01c.pdf}
 [Viewed June 23, 2004]"
-annotation="
-Described RCU, and presented some patches implementing and using it in
-the Linux kernel.
+,annotation={
+	Described RCU, and presented some patches implementing and using
+	it in the Linux kernel.
+}
+}
+
+@unpublished{McKenney01f
+,Author="Paul E. McKenney"
+,Title="{RFC:} patch to allow lock-free traversal of lists with insertion"
+,month="October"
+,year="2001"
+,note="Available:
+\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=100259266316456&w=2}
+[Viewed June 23, 2004]"
+,annotation="
+	Memory-barrier and Alpha thread.  100 messages, not too bad...
 "
 }
 
+@unpublished{Spraul01
+,Author="Manfred Spraul"
+,Title="Re: {RFC:} patch to allow lock-free traversal of lists with insertion"
+,month="October"
+,year="2001"
+,note="Available:
+\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=100264675012867&w=2}
+[Viewed June 23, 2004]"
+,annotation="
+	Suggested burying memory barriers in Linux's list-manipulation
+	primitives.
+"
+}
+
+@unpublished{LinusTorvalds2001a
+,Author="Linus Torvalds"
+,Title="{Re:} {[Lse-tech]} {Re:} {RFC:} patch to allow lock-free traversal of lists with insertion"
+,month="October"
+,year="2001"
+,note="Available:
+\url{http://lkml.org/lkml/2001/10/13/105}
+[Viewed August 21, 2004]"
+}
+
+@unpublished{Blanchard02a
+,Author="Anton Blanchard"
+,Title="some RCU dcache and ratcache results"
+,month="March"
+,year="2002"
+,note="Available:
+\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=101637107412972&w=2}
+[Viewed October 18, 2004]"
+}
+
 @Conference{Linder02a
 ,Author="Hanna Linder and Dipankar Sarma and Maneesh Soni"
 ,Title="Scalability of the Directory Entry Cache"
@@ -387,6 +657,10 @@
 ,Month="June"
 ,Year="2002"
 ,pages="289-300"
+,annotation="
+	Measured scalability of Linux 2.4 kernel's directory-entry cache
+	(dcache), and measured some scalability enhancements.
+"
 }
 
 @Conference{McKenney02a
@@ -400,49 +674,76 @@
 ,note="Available:
 \url{http://www.linux.org.uk/~ajh/ols2002_proceedings.pdf.gz}
 [Viewed June 23, 2004]"
-}
-
-@conference{Michael02a
-,author="Maged M. Michael"
-,title="Safe Memory Reclamation for Dynamic Lock-Free Objects Using Atomic
-Reads and Writes"
-,Year="2002"
-,Month="August"
-,booktitle="{Proceedings of the 21\textsuperscript{st} Annual ACM
-Symposium on Principles of Distributed Computing}"
-,pages="21-30"
 ,annotation="
-	Each thread keeps an array of pointers to items that it is
-	currently referencing.	Sort of an inside-out garbage collection
-	mechanism, but one that requires the accessing code to explicitly
-	state its needs.  Also requires read-side memory barriers on
-	most architectures.
+	Presented and compared a number of RCU implementations for the
+	Linux kernel.
 "
 }
 
-@conference{Michael02b
-,author="Maged M. Michael"
-,title="High Performance Dynamic Lock-Free Hash Tables and List-Based Sets"
-,Year="2002"
-,Month="August"
-,booktitle="{Proceedings of the 14\textsuperscript{th} Annual ACM
-Symposium on Parallel
-Algorithms and Architecture}"
-,pages="73-82"
+@unpublished{Sarma02a
+,Author="Dipankar Sarma"
+,Title="specweb99: dcache scalability results"
+,month="July"
+,year="2002"
+,note="Available:
+\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=102645767914212&w=2}
+[Viewed June 23, 2004]"
 ,annotation="
-	Like the title says...
+	Compare fastwalk and RCU for dcache.  RCU won.
 "
 }
 
-@InProceedings{HerlihyLM02
-,author={Maurice Herlihy and Victor Luchangco and Mark Moir}
-,title="The Repeat Offender Problem: A Mechanism for Supporting Dynamic-Sized,
-Lock-Free Data Structures"
-,booktitle={Proceedings of 16\textsuperscript{th} International
-Symposium on Distributed Computing}
-,year=2002
+@unpublished{Barbieri02
+,Author="Luca Barbieri"
+,Title="Re: {[PATCH]} Initial support for struct {vfs\_cred}"
+,month="August"
+,year="2002"
+,note="Available:
+\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=103082050621241&w=2}
+[Viewed: June 23, 2004]"
+,annotation="
+	Suggested RCU for vfs\_shared\_cred.
+"
+}
+
+@unpublished{Dickins02a
+,author="Hugh Dickins"
+,title="Use RCU for System-V IPC"
+,year="2002"
 ,month="October"
-,pages="339-353"
+,note="private communication"
+}
+
+@unpublished{Sarma02b
+,Author="Dipankar Sarma"
+,Title="Some dcache\_rcu benchmark numbers"
+,month="October"
+,year="2002"
+,note="Available:
+\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=103462075416638&w=2}
+[Viewed June 23, 2004]"
+,annotation="
+	Performance of dcache RCU on kernbench for 16x NUMA-Q and 1x,
+	2x, and 4x systems.  RCU does no harm, and helps on 16x.
+"
+}
+
+@unpublished{LinusTorvalds2003a
+,Author="Linus Torvalds"
+,Title="Re: {[PATCH]} small fixes in brlock.h"
+,month="March"
+,year="2003"
+,note="Available:
+\url{http://lkml.org/lkml/2003/3/9/205}
+[Viewed March 13, 2006]"
+,annotation="
+	Linus suggests replacing brlock with RCU and/or seqlocks:
+	.
+	'It's entirely possible that the current user could be replaced
+	by RCU and/or seqlocks, and we could get rid of brlocks entirely.'
+	.
+	Steve Hemminger responds by replacing them with RCU.
+"
 }
 
 @article{Appavoo03a
@@ -457,6 +758,20 @@
 ,volume="42"
 ,number="1"
 ,pages="60-76"
+,annotation="
+	Use of RCU to enable hot-swapping for autonomic behavior in K42.
+"
+}
+
+@unpublished{Seigh03
+,author="Joseph W. {Seigh II}"
+,title="Read Copy Update"
+,Year="2003"
+,Month="March"
+,note="email correspondence"
+,annotation="
+	Described the relationship of the VM/XA passive serialization to RCU.
+"
 }
 
 @Conference{Arcangeli03
@@ -470,6 +785,27 @@
 ,year="2003"
 ,month="June"
 ,pages="297-310"
+,note="Available:
+\url{http://www.rdrop.com/users/paulmck/RCU/rcu.FREENIX.2003.06.14.pdf}
+[Viewed November 21, 2007]"
+,annotation="
+	Compared updated RCU implementations for the Linux kernel, and
+	described System V IPC use of RCU, including order-of-magnitude
+	performance improvements.
+"
+}
+
+@Conference{Soules03a
+,Author="Craig A. N. Soules and Jonathan Appavoo and Kevin Hui and
+Dilma {Da Silva} and Gregory R. Ganger and Orran Krieger and
+Michael Stumm and Robert W. Wisniewski and Marc Auslander and
+Michal Ostrowski and Bryan Rosenburg and Jimi Xenidis"
+,Title="System Support for Online Reconfiguration"
+,Booktitle="Proceedings of the 2003 USENIX Annual Technical Conference"
+,Publisher="USENIX Association"
+,year="2003"
+,month="June"
+,pages="141-154"
 }
 
 @article{McKenney03a
@@ -481,6 +817,22 @@
 ,volume="1"
 ,number="114"
 ,pages="18-26"
+,note="Available:
+\url{http://www.linuxjournal.com/article/6993}
+[Viewed November 14, 2007]"
+,annotation="
+	Reader-friendly intro to RCU, with the infamous old-man-and-brat
+	cartoon.
+"
+}
+
+@unpublished{Sarma03a
+,Author="Dipankar Sarma"
+,Title="RCU low latency patches"
+,month="December"
+,year="2003"
+,note="Message ID: 20031222180114.GA2248@in.ibm.com"
+,annotation="dipankar/ct.2004.03.27/RCUll.2003.12.22.patch"
 }
 
 @techreport{Friedberg03a
@@ -489,9 +841,14 @@
 ,institution="US Patent and Trademark Office"
 ,address="Washington, DC"
 ,year="2003"
-,number="US Patent 6,662,184 (contributed under GPL)"
+,number="US Patent 6,662,184"
 ,month="December"
 ,pages="112"
+,annotation="
+	Applies RCU to a wildcard-search Patricia tree in order to permit
+	synchronization-free lookup.  RCU is used to retain removed nodes
+	for a grace period before freeing them.
+"
 }
 
 @article{McKenney04a
@@ -503,6 +860,12 @@
 ,volume="1"
 ,number="118"
 ,pages="38-46"
+,note="Available:
+\url{http://www.linuxjournal.com/node/7124}
+[Viewed December 26, 2010]"
+,annotation="
+	Reader friendly intro to dcache and RCU.
+"
 }
 
 @Conference{McKenney04b
@@ -514,8 +877,83 @@
 ,Address="Adelaide, Australia"
 ,note="Available:
 \url{http://www.linux.org.au/conf/2004/abstracts.html#90}
-\url{http://www.rdrop.com/users/paulmck/rclock/lockperf.2004.01.17a.pdf}
+\url{http://www.rdrop.com/users/paulmck/RCU/lockperf.2004.01.17a.pdf}
 [Viewed June 23, 2004]"
+,annotation="
+	Compares performance of RCU to that of other locking primitives
+	over a number of CPUs (x86, Opteron, Itanium, and PPC).
+"
+}
+
+@unpublished{Sarma04a
+,Author="Dipankar Sarma"
+,Title="{[PATCH]} {RCU} for low latency (experimental)"
+,month="March"
+,year="2004"
+,note="\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=108003746402892&w=2}"
+,annotation="Head of thread: dipankar/2004.03.23/rcu-low-lat.1.patch"
+}
+
+@unpublished{Sarma04b
+,Author="Dipankar Sarma"
+,Title="Re: {[PATCH]} {RCU} for low latency (experimental)"
+,month="March"
+,year="2004"
+,note="\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=108016474829546&w=2}"
+,annotation="dipankar/rcuth.2004.03.24/rcu-throttle.patch"
+}
+
+@unpublished{Spraul04a
+,Author="Manfred Spraul"
+,Title="[RFC] 0/5 rcu lock update"
+,month="May"
+,year="2004"
+,note="Available:
+\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=108546407726602&w=2}
+[Viewed June 23, 2004]"
+,annotation="
+	Hierarchical-bitmap patch for RCU infrastructure.
+"
+}
+
+@unpublished{Steiner04a
+,Author="Jack Steiner"
+,Title="Re: [Lse-tech] [RFC, PATCH] 1/5 rcu lock update:
+Add per-cpu batch counter"
+,month="May"
+,year="2004"
+,note="Available:
+\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=108551764515332&w=2}
+[Viewed June 23, 2004]"
+,annotation={
+	RCU runs reasonably on a 512-CPU SGI using Manfred Spraul's patches,
+	which may be found at:
+	https://lkml.org/lkml/2004/5/20/49 (split vars into cachelines)
+	https://lkml.org/lkml/2004/5/22/114 (cpu_quiet() patch)
+	https://lkml.org/lkml/2004/5/25/24 (0/5)
+	https://lkml.org/lkml/2004/5/25/23 (1/5)
+		https://lkml.org/lkml/2004/5/25/265 (works for Jack)
+	https://lkml.org/lkml/2004/5/25/20 (2/5)
+	https://lkml.org/lkml/2004/5/25/22 (3/5)
+	https://lkml.org/lkml/2004/5/25/19 (4/5)
+	https://lkml.org/lkml/2004/5/25/21 (5/5)
+}
+}
+
+@Conference{Sarma04c
+,Author="Dipankar Sarma and Paul E. McKenney"
+,Title="Making {RCU} Safe for Deep Sub-Millisecond Response
+Realtime Applications"
+,Booktitle="Proceedings of the 2004 USENIX Annual Technical Conference
+(FREENIX Track)"
+,Publisher="USENIX Association"
+,year="2004"
+,month="June"
+,pages="182-191"
+,annotation="
+	Describes and compares a number of modifications to the Linux RCU
+	implementation that make it friendly to realtime applications.
+"
 }
 
 @phdthesis{PaulEdwardMcKenneyPhD
@@ -529,17 +967,118 @@
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU/RCUdissertation.2004.07.14e1.pdf}
 [Viewed October 15, 2004]"
+,annotation="
+	Describes RCU implementations and presents design patterns
+	corresponding to common uses of RCU in several operating-system
+	kernels.
+"
 }
 
-@Conference{Sarma04c
-,Author="Dipankar Sarma and Paul E. McKenney"
-,Title="Making RCU Safe for Deep Sub-Millisecond Response Realtime Applications"
-,Booktitle="Proceedings of the 2004 USENIX Annual Technical Conference
-(FREENIX Track)"
-,Publisher="USENIX Association"
+@unpublished{PaulEMcKenney2004rcu:dereference
+,Author="Dipankar Sarma"
+,Title="{Re: RCU : Abstracted RCU dereferencing [5/5]}"
+,month="August"
 ,year="2004"
-,month="June"
-,pages="182-191"
+,note="Available:
+\url{http://lkml.org/lkml/2004/8/6/237}
+[Viewed June 8, 2010]"
+,annotation="
+	Introduce rcu_dereference().
+"
+}
+
+@unpublished{JimHouston04a
+,Author="Jim Houston"
+,Title="{[RFC\&PATCH] Alternative {RCU} implementation}"
+,month="August"
+,year="2004"
+,note="Available:
+\url{http://lkml.org/lkml/2004/8/30/87}
+[Viewed February 17, 2005]"
+,annotation="
+	Uses active code in rcu_read_lock() and rcu_read_unlock() to
+	make RCU happen, allowing RCU to function on CPUs that do not
+	receive a scheduling-clock interrupt.
+"
+}
+
+@unpublished{TomHart04a
+,Author="Thomas E. Hart"
+,Title="Master's Thesis: Applying Lock-free Techniques to the {Linux} Kernel"
+,month="October"
+,year="2004"
+,note="Available:
+\url{http://www.cs.toronto.edu/~tomhart/masters_thesis.html}
+[Viewed October 15, 2004]"
+,annotation="
+	Proposes comparing RCU to lock-free methods for the Linux kernel.
+"
+}
+
+@unpublished{Vaddagiri04a
+,Author="Srivatsa Vaddagiri"
+,Title="Subject: [RFC] Use RCU for tcp\_ehash lookup"
+,month="October"
+,year="2004"
+,note="Available:
+\url{http://marc.theaimsgroup.com/?t=109395731700004&r=1&w=2}
+[Viewed October 18, 2004]"
+,annotation="
+	Srivatsa's RCU patch for tcp_ehash lookup.
+"
+}
+
+@unpublished{Thirumalai04a
+,Author="Ravikiran Thirumalai"
+,Title="Subject: [patchset] Lockfree fd lookup 0 of 5"
+,month="October"
+,year="2004"
+,note="Available:
+\url{http://marc.theaimsgroup.com/?t=109144217400003&r=1&w=2}
+[Viewed October 18, 2004]"
+,annotation="
+	Ravikiran's lockfree FD patch.
+"
+}
+
+@unpublished{Thirumalai04b
+,Author="Ravikiran Thirumalai"
+,Title="Subject: Re: [patchset] Lockfree fd lookup 0 of 5"
+,month="October"
+,year="2004"
+,note="Available:
+\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=109152521410459&w=2}
+[Viewed October 18, 2004]"
+,annotation="
+	Ravikiran's lockfree FD patch.
+"
+}
+
+@unpublished{PaulEMcKenney2004rcu:assign:pointer
+,Author="Paul E. McKenney"
+,Title="{[PATCH 1/3] RCU: \url{rcu_assign_pointer()} removal of memory barriers}"
+,month="October"
+,year="2004"
+,note="Available:
+\url{http://lkml.org/lkml/2004/10/23/241}
+[Viewed June 8, 2010]"
+,annotation="
+	Introduce rcu_assign_pointer().
+"
+}
+
+@unpublished{JamesMorris04a
+,Author="James Morris"
+,Title="{[PATCH 2/3] SELinux} scalability - convert {AVC} to {RCU}"
+,day="15"
+,month="November"
+,year="2004"
+,note="Available:
+\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=110054979416004&w=2}
+[Viewed December 10, 2004]"
+,annotation="
+	James Morris posts Kaigai Kohei's patch to LKML.
+"
 }
 
 @unpublished{JamesMorris04b
@@ -550,6 +1089,85 @@
 ,note="Available:
 \url{http://www.livejournal.com/users/james_morris/2153.html}
 [Viewed December 10, 2004]"
+,annotation="
+	RCU helps SELinux performance.  ;-)  Made LWN.
+"
+}
+
+@unpublished{PaulMcKenney2005RCUSemantics
+,Author="Paul E. McKenney and Jonathan Walpole"
+,Title="{RCU} Semantics: A First Attempt"
+,month="January"
+,year="2005"
+,day="30"
+,note="Available:
+\url{http://www.rdrop.com/users/paulmck/RCU/rcu-semantics.2005.01.30a.pdf}
+[Viewed December 6, 2009]"
+,annotation="
+	Early derivation of RCU semantics.
+"
+}
+
+@unpublished{PaulMcKenney2005e
+,Author="Paul E. McKenney"
+,Title="Real-Time Preemption and {RCU}"
+,month="March"
+,year="2005"
+,day="17"
+,note="Available:
+\url{http://lkml.org/lkml/2005/3/17/199}
+[Viewed September 5, 2005]"
+,annotation="
+	First posting showing how RCU can be safely adapted for
+	preemptable RCU read side critical sections.
+"
+}
+
+@unpublished{EsbenNeilsen2005a
+,Author="Esben Neilsen"
+,Title="Re: Real-Time Preemption and {RCU}"
+,month="March"
+,year="2005"
+,day="18"
+,note="Available:
+\url{http://lkml.org/lkml/2005/3/18/122}
+[Viewed March 30, 2006]"
+,annotation="
+	Esben Neilsen suggests read-side suppression of grace-period
+	processing for crude-but-workable realtime RCU.  The downside
+	is indefinite grace periods...But this is OK for experimentation
+	and testing.
+"
+}
+
+@unpublished{TomHart05a
+,Author="Thomas E. Hart and Paul E. McKenney and Angela Demke Brown"
+,Title="Efficient Memory Reclamation is Necessary for Fast Lock-Free
+Data Structures"
+,month="March"
+,year="2005"
+,note="Available:
+\url{ftp://ftp.cs.toronto.edu/csrg-technical-reports/515/}
+[Viewed March 4, 2005]"
+,annotation="
+	Comparison of RCU, QBSR, and EBSR.  RCU wins for read-mostly
+	workloads.  ;-)
+"
+}
+
+@unpublished{JonCorbet2005DeprecateSyncKernel
+,Author="Jonathan Corbet"
+,Title="API change: synchronize_kernel() deprecated"
+,month="May"
+,day="3"
+,year="2005"
+,note="Available:
+\url{http://lwn.net/Articles/134484/}
+[Viewed May 3, 2005]"
+,annotation="
+	Jon Corbet describes deprecation of synchronize_kernel()
+	in favor of synchronize_rcu() and synchronize_sched().
+"
 }
 
 @unpublished{PaulMcKenney05a
@@ -568,7 +1186,7 @@
 
 @conference{PaulMcKenney05b
 ,Author="Paul E. McKenney and Dipankar Sarma"
-,Title="Towards Hard Realtime Response from the Linux Kernel on SMP Hardware"
+,Title="Towards Hard Realtime Response from the {Linux} Kernel on {SMP} Hardware"
 ,Booktitle="linux.conf.au 2005"
 ,month="April"
 ,year="2005"
@@ -578,6 +1196,103 @@
 [Viewed May 13, 2005]"
 ,annotation="
 	Realtime turns into making RCU yet more realtime friendly.
+	http://lca2005.linux.org.au/Papers/Paul%20McKenney/Towards%20Hard%20Realtime%20Response%20from%20the%20Linux%20Kernel/LKS.2005.04.22a.pdf
+"
+}
+
+@unpublished{PaulEMcKenneyHomePage
+,Author="Paul E. McKenney"
+,Title="{Paul} {E.} {McKenney}"
+,month="May"
+,year="2005"
+,note="Available:
+\url{http://www.rdrop.com/users/paulmck/}
+[Viewed May 25, 2005]"
+,annotation="
+	Paul McKenney's home page.
+"
+}
+
+@unpublished{PaulEMcKenneyRCUPage
+,Author="Paul E. McKenney"
+,Title="Read-Copy Update {(RCU)}"
+,month="May"
+,year="2005"
+,note="Available:
+\url{http://www.rdrop.com/users/paulmck/RCU}
+[Viewed May 25, 2005]"
+,annotation="
+	Paul McKenney's RCU page.
+"
+}
+
+@unpublished{JosephSeigh2005a
+,Author="Joseph Seigh"
+,Title="{RCU}+{SMR} (hazard pointers)"
+,month="July"
+,year="2005"
+,note="Personal communication"
+,annotation="
+	Joe Seigh announcing his atomic-ptr-plus project.
+	http://sourceforge.net/projects/atomic-ptr-plus/
+"
+}
+
+@unpublished{JosephSeigh2005b
+,Author="Joseph Seigh"
+,Title="Lock-free synchronization primitives"
+,month="July"
+,day="6"
+,year="2005"
+,note="Available:
+\url{http://sourceforge.net/projects/atomic-ptr-plus/}
+[Viewed August 8, 2005]"
+,annotation="
+	Joe Seigh's atomic-ptr-plus project.
+"
+}
+
+@unpublished{PaulMcKenney2005c
+,Author="Paul E.McKenney"
+,Title="{[RFC,PATCH] RCU} and {CONFIG\_PREEMPT\_RT} sane patch"
+,month="August"
+,day="1"
+,year="2005"
+,note="Available:
+\url{http://lkml.org/lkml/2005/8/1/155}
+[Viewed March 14, 2006]"
+,annotation="
+	First operating counter-based realtime RCU patch posted to LKML.
+"
+}
+
+@unpublished{PaulMcKenney2005d
+,Author="Paul E. McKenney"
+,Title="Re: [Fwd: Re: [patch] Real-Time Preemption, -RT-2.6.13-rc4-V0.7.52-01]"
+,month="August"
+,day="8"
+,year="2005"
+,note="Available:
+\url{http://lkml.org/lkml/2005/8/8/108}
+[Viewed March 14, 2006]"
+,annotation="
+	First operating counter-based realtime RCU patch posted to LKML,
+	but fixed so that various unusual combinations of configuration
+	parameters all function properly.
+"
+}
+
+@unpublished{PaulMcKenney2005rcutorture
+,Author="Paul E. McKenney"
+,Title="{[PATCH]} {RCU} torture testing"
+,month="October"
+,day="1"
+,year="2005"
+,note="Available:
+\url{http://lkml.org/lkml/2005/10/1/70}
+[Viewed March 14, 2006]"
+,annotation="
+	First rcutorture patch.
 "
 }
 
@@ -591,22 +1306,39 @@
 ,year="2006"
 ,day="25-29"
 ,address="Rhodes, Greece"
+,note="Available:
+\url{http://www.rdrop.com/users/paulmck/RCU/hart_ipdps06.pdf}
+[Viewed April 28, 2008]"
 ,annotation="
-	Compares QSBR (AKA "classic RCU"), HPBR, EBR, and lock-free
-	reference counting.
+	Compares QSBR, HPBR, EBR, and lock-free reference counting.
+	http://www.cs.toronto.edu/~tomhart/perflab/ipdps06.tgz
+"
+}
+
+@unpublished{NickPiggin2006radixtree
+,Author="Nick Piggin"
+,Title="[patch 3/3] radix-tree: {RCU} lockless readside"
+,month="June"
+,day="20"
+,year="2006"
+,note="Available:
+\url{http://lkml.org/lkml/2006/6/20/238}
+[Viewed March 25, 2008]"
+,annotation="
+	RCU-protected radix tree.
 "
 }
 
 @Conference{PaulEMcKenney2006b
 ,Author="Paul E. McKenney and Dipankar Sarma and Ingo Molnar and
 Suparna Bhattacharya"
-,Title="Extending RCU for Realtime and Embedded Workloads"
+,Title="Extending {RCU} for Realtime and Embedded Workloads"
 ,Booktitle="{Ottawa Linux Symposium}"
 ,Month="July"
 ,Year="2006"
 ,pages="v2 123-138"
 ,note="Available:
-\url{http://www.linuxsymposium.org/2006/index_2006.php}
+\url{http://www.linuxsymposium.org/2006/view_abstract.php?content_key=184}
 \url{http://www.rdrop.com/users/paulmck/RCU/OLSrtRCU.2006.08.11a.pdf}
 [Viewed January 1, 2007]"
 ,annotation="
@@ -614,6 +1346,37 @@
 "
 }
 
+@unpublished{WikipediaRCU
+,Author="Paul E. McKenney and Chris Purcell and Algae and Ben Schumin and
+Gaius Cornelius and Qwertyus and Neil Conway and Sbw and Blainster and
+Canis Rufus and Zoicon5 and Anome and Hal Eisen"
+,Title="Read-Copy Update"
+,month="July"
+,day="8"
+,year="2006"
+,note="Available:
+\url{http://en.wikipedia.org/wiki/Read-copy-update}
+[Viewed August 21, 2006]"
+,annotation="
+	Wikipedia RCU page as of July 8 2006.
+"
+}
+
+@Conference{NickPiggin2006LocklessPageCache
+,Author="Nick Piggin"
+,Title="A Lockless Pagecache in Linux---Introduction, Progress, Performance"
+,Booktitle="{Ottawa Linux Symposium}"
+,Month="July"
+,Year="2006"
+,pages="v2 249-254"
+,note="Available:
+\url{http://www.linuxsymposium.org/2006/view_abstract.php?content_key=184}
+[Viewed January 11, 2009]"
+,annotation="
+	Uses RCU-protected radix tree for a lockless page cache.
+"
+}
+
 @unpublished{PaulEMcKenney2006c
 ,Author="Paul E. McKenney"
 ,Title="Sleepable {RCU}"
@@ -637,29 +1400,301 @@
 ,day="18"
 ,year="2006"
 ,note="Available:
-\url{http://www.nada.kth.se/~snilsson/public/papers/trash/trash.pdf}
-[Viewed February 24, 2007]"
+\url{http://www.nada.kth.se/~snilsson/publications/TRASH/trash.pdf}
+[Viewed March 4, 2011]"
 ,annotation="
 	RCU-protected dynamic trie-hash combination.
 "
 }
 
-@unpublished{ThomasEHart2007a
-,Author="Thomas E. Hart and Paul E. McKenney and Angela Demke Brown and Jonathan Walpole"
-,Title="Performance of memory reclamation for lockless synchronization"
-,journal="J. Parallel Distrib. Comput."
-,year="2007"
-,note="To appear in J. Parallel Distrib. Comput.
-       \url{doi=10.1016/j.jpdc.2007.04.010}"
+@unpublished{ChristophHellwig2006RCU2SRCU
+,Author="Christoph Hellwig"
+,Title="Re: {[-mm PATCH 1/4]} {RCU}: split classic rcu"
+,month="September"
+,day="28"
+,year="2006"
+,note="Available:
+\url{http://lkml.org/lkml/2006/9/28/160}
+[Viewed March 27, 2008]"
+}
+
+@unpublished{PaulEMcKenneyRCUusagePage
+,Author="Paul E. McKenney"
+,Title="{RCU} {Linux} Usage"
+,month="October"
+,year="2006"
+,note="Available:
+\url{http://www.rdrop.com/users/paulmck/RCU/linuxusage.html}
+[Viewed January 14, 2007]"
+,annotation="
+	Paul McKenney's RCU page showing graphs plotting Linux-kernel
+	usage of RCU.
+"
+}
+
+@unpublished{PaulEMcKenneyRCUusageRawDataPage
+,Author="Paul E. McKenney"
+,Title="Read-Copy Update {(RCU)} Usage in {Linux} Kernel"
+,month="October"
+,year="2006"
+,note="Available:
+\url{http://www.rdrop.com/users/paulmck/RCU/linuxusage/rculocktab.html}
+[Viewed January 14, 2007]"
+,annotation="
+	Paul McKenney's RCU page showing Linux usage of RCU in tabular
+	form, with links to corresponding cscope databases.
+"
+}
+
+@unpublished{GauthamShenoy2006RCUrwlock
+,Author="Gautham R. Shenoy"
+,Title="[PATCH 4/5] lock\_cpu\_hotplug: Redesign - Lightweight implementation of lock\_cpu\_hotplug"
+,month="October"
+,year="2006"
+,day=26
+,note="Available:
+\url{http://lkml.org/lkml/2006/10/26/73}
+[Viewed January 26, 2009]"
+,annotation="
+	RCU-based reader-writer lock that allows readers to proceed with
+	no memory barriers or atomic instruction in absence of writers.
+	If writer do show up, readers must of course wait as required by
+	the semantics of reader-writer locking.  This is a recursive
+	lock.
+"
+}
+
+@unpublished{JensAxboe2006SlowSRCU
+,Author="Jens Axboe"
+,Title="Re: [patch] cpufreq: mark \url{cpufreq_tsc()} as
+\url{core_initcall_sync}"
+,month="November"
+,year="2006"
+,day=17
+,note="Available:
+\url{http://lkml.org/lkml/2006/11/17/56}
+[Viewed May 28, 2007]"
+,annotation="
+	SRCU's grace periods are too slow for Jens, even after a
+	factor-of-three speedup.
+	Sped-up version of SRCU at http://lkml.org/lkml/2006/11/17/359.
+"
+}
+
+@unpublished{OlegNesterov2006QRCU
+,Author="Oleg Nesterov"
+,Title="Re: [patch] cpufreq: mark {\tt cpufreq\_tsc()} as
+{\tt core\_initcall\_sync}"
+,month="November"
+,year="2006"
+,day=19
+,note="Available:
+\url{http://lkml.org/lkml/2006/11/19/69}
+[Viewed May 28, 2007]"
+,annotation="
+	First cut of QRCU.  Expanded/corrected versions followed.
+	Used to be OlegNesterov2007QRCU, now time-corrected.
+"
+}
+
+@unpublished{OlegNesterov2006aQRCU
+,Author="Oleg Nesterov"
+,Title="Re: [RFC, PATCH 1/2] qrcu: {"quick"} srcu implementation"
+,month="November"
+,year="2006"
+,day=30
+,note="Available:
+\url{http://lkml.org/lkml/2006/11/29/330}
+[Viewed November 26, 2008]"
+,annotation="
+	Expanded/corrected version of QRCU.
+	Used to be OlegNesterov2007aQRCU, now time-corrected.
+"
+}
+
+@unpublished{EvgeniyPolyakov2006RCUslowdown
+,Author="Evgeniy Polyakov"
+,Title="Badness in postponing work"
+,month="December"
+,year="2006"
+,day=05
+,note="Available:
+\url{http://www.ioremap.net/node/41}
+[Viewed October 28, 2008]"
+,annotation="
+	Using RCU as a pure delay leads to a 2.5x slowdown in skbs in
+	the Linux kernel.
+"
+}
+
+@inproceedings{ChrisMatthews2006ClusteredObjectsRCU
+,author = {Matthews, Chris and Coady, Yvonne and Appavoo, Jonathan}
+,title = {Portability events: a programming model for scalable system infrastructures}
+,booktitle = {PLOS '06: Proceedings of the 3rd workshop on Programming languages and operating systems}
+,year = {2006}
+,isbn = {1-59593-577-0}
+,pages = {11}
+,location = {San Jose, California}
+,doi = {http://doi.acm.org/10.1145/1215995.1216006}
+,publisher = {ACM}
+,address = {New York, NY, USA}
 ,annotation={
-	Compares QSBR (AKA "classic RCU"), HPBR, EBR, and lock-free
-	reference counting.  Journal version of ThomasEHart2006a.
+	Uses K42's RCU-like functionality to manage clustered-object
+	lifetimes.
+}}
+
+@article{DilmaDaSilva2006K42
+,author = {Silva, Dilma Da and Krieger, Orran and Wisniewski, Robert W. and Waterland, Amos and Tam, David and Baumann, Andrew}
+,title = {K42: an infrastructure for operating system research}
+,journal = {SIGOPS Oper. Syst. Rev.}
+,volume = {40}
+,number = {2}
+,year = {2006}
+,issn = {0163-5980}
+,pages = {34--42}
+,doi = {http://doi.acm.org/10.1145/1131322.1131333}
+,publisher = {ACM}
+,address = {New York, NY, USA}
+,annotation={
+	Describes relationship of K42 generations to RCU.
+}}
+
+# CoreyMinyard2007list_splice_rcu
+@unpublished{CoreyMinyard2007list:splice:rcu
+,Author="Corey Minyard and Paul E. McKenney"
+,Title="{[PATCH]} add an {RCU} version of list splicing"
+,month="January"
+,year="2007"
+,day=3
+,note="Available:
+\url{http://lkml.org/lkml/2007/1/3/112}
+[Viewed May 28, 2007]"
+,annotation="
+	Patch for list_splice_rcu().
+"
+}
+
+@unpublished{PaulEMcKenney2007rcubarrier
+,Author="Paul E. McKenney"
+,Title="{RCU} and Unloadable Modules"
+,month="January"
+,day="14"
+,year="2007"
+,note="Available:
+\url{http://lwn.net/Articles/217484/}
+[Viewed November 22, 2007]"
+,annotation="
+	LWN article introducing the rcu_barrier() primitive.
+"
+}
+
+@unpublished{PeterZijlstra2007SyncBarrier
+,Author="Peter Zijlstra and Ingo Molnar"
+,Title="{[PATCH 3/7]} barrier: a scalable synchonisation barrier"
+,month="January"
+,year="2007"
+,day=28
+,note="Available:
+\url{http://lkml.org/lkml/2007/1/28/34}
+[Viewed March 27, 2008]"
+,annotation="
+	RCU-like implementation for frequent updaters and rare readers(!).
+	Subsumed into QRCU.  Maybe...
+"
+}
+
+@unpublished{PaulEMcKenney2007BoostRCU
+,Author="Paul E. McKenney"
+,Title="Priority-Boosting {RCU} Read-Side Critical Sections"
+,month="February"
+,day="5"
+,year="2007"
+,note="Available:
+\url{http://lwn.net/Articles/220677/}
+Revised:
+\url{http://www.rdrop.com/users/paulmck/RCU/RCUbooststate.2007.04.16a.pdf}
+[Viewed September 7, 2007]"
+,annotation="
+	LWN article introducing RCU priority boosting.
+"
+}
+
+@unpublished{PaulMcKenney2007QRCUpatch
+,Author="Paul E. McKenney"
+,Title="{[PATCH]} {QRCU} with lockless fastpath"
+,month="February"
+,year="2007"
+,day=24
+,note="Available:
+\url{http://lkml.org/lkml/2007/2/25/18}
+[Viewed March 27, 2008]"
+,annotation="
+	Patch for QRCU supplying lock-free fast path.
+"
+}
+
+@article{JonathanAppavoo2007K42RCU
+,author = {Appavoo, Jonathan and Silva, Dilma Da and Krieger, Orran and Auslander, Marc and Ostrowski, Michal and Rosenburg, Bryan and Waterland, Amos and Wisniewski, Robert W. and Xenidis, Jimi and Stumm, Michael and Soares, Livio}
+,title = {Experience distributing objects in an SMMP OS}
+,journal = {ACM Trans. Comput. Syst.}
+,volume = {25}
+,number = {3}
+,year = {2007}
+,issn = {0734-2071}
+,pages = {6/1--6/52}
+,doi = {http://doi.acm.org/10.1145/1275517.1275518}
+,publisher = {ACM}
+,address = {New York, NY, USA}
+,annotation={
+	Role of RCU in K42.
+}}
+
+@conference{RobertOlsson2007Trash
+,Author="Robert Olsson and Stefan Nilsson"
+,Title="{TRASH}: A dynamic {LC}-trie and hash data structure"
+,booktitle="Workshop on High Performance Switching and Routing (HPSR'07)"
+,month="May"
+,year="2007"
+,note="Available:
+\url{http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?arnumber=4281239}
+[Viewed October 1, 2010]"
+,annotation="
+	RCU-protected dynamic trie-hash combination.
+"
+}
+
+@conference{PeterZijlstra2007ConcurrentPagecacheRCU
+,Author="Peter Zijlstra"
+,Title="Concurrent Pagecache"
+,Booktitle="Linux Symposium"
+,month="June"
+,year="2007"
+,address="Ottawa, Canada"
+,note="Available:
+\url{http://ols.108.redhat.com/2007/Reprints/zijlstra-Reprint.pdf}
+[Viewed April 14, 2008]"
+,annotation="
+	Page-cache modifications permitting RCU readers and concurrent
+	updates.
+"
+}
+
+@unpublished{PaulEMcKenney2007whatisRCU
+,Author="Paul E. McKenney"
+,Title="What is {RCU}?"
+,year="2007"
+,month="07"
+,note="Available:
+\url{http://www.rdrop.com/users/paulmck/RCU/whatisRCU.html}
+[Viewed July 6, 2007]"
+,annotation={
+	Describes RCU in Linux kernel.
 }
 }
 
 @unpublished{PaulEMcKenney2007QRCUspin
 ,Author="Paul E. McKenney"
-,Title="Using Promela and Spin to verify parallel algorithms"
+,Title="Using {Promela} and {Spin} to verify parallel algorithms"
 ,month="August"
 ,day="1"
 ,year="2007"
@@ -669,6 +1704,50 @@
 ,annotation="
 	LWN article describing Promela and spin, and also using Oleg
 	Nesterov's QRCU as an example (with Paul McKenney's fastpath).
+	Merged patch at: http://lkml.org/lkml/2007/2/25/18
+"
+}
+
+@unpublished{PaulEMcKenney2007WG21DDOatomics
+,Author="Paul E. McKenney and Hans-J. Boehm and Lawrence Crowl"
+,Title="C++ Data-Dependency Ordering: Atomics and Memory Model"
+,month="August"
+,day="3"
+,year="2007"
+,note="Preprint:
+\url{http://open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2664.htm}
+[Viewed December 7, 2009]"
+,annotation="
+	RCU for C++, parts 1 and 2.
+"
+}
+
+@unpublished{PaulEMcKenney2007WG21DDOannotation
+,Author="Paul E. McKenney and Lawrence Crowl"
+,Title="C++ Data-Dependency Ordering: Function Annotation"
+,month="September"
+,day="18"
+,year="2008"
+,note="Preprint:
+\url{http://open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2782.htm}
+[Viewed December 7, 2009]"
+,annotation="
+	RCU for C++, part 2, updated many times.
+"
+}
+
+@unpublished{PaulEMcKenney2007PreemptibleRCUPatch
+,Author="Paul E. McKenney"
+,Title="[PATCH RFC 0/9] {RCU}: Preemptible {RCU}"
+,month="September"
+,day="10"
+,year="2007"
+,note="Available:
+\url{http://lkml.org/lkml/2007/9/10/213}
+[Viewed October 25, 2007]"
+,annotation="
+	Final patch for preemptable RCU to -rt.  (Later patches were
+	to mainline, eventually incorporated.)
 "
 }
 
@@ -686,10 +1765,46 @@
 "
 }
 
+@article{ThomasEHart2007a
+,Author="Thomas E. Hart and Paul E. McKenney and Angela Demke Brown and Jonathan Walpole"
+,Title="Performance of memory reclamation for lockless synchronization"
+,journal="J. Parallel Distrib. Comput."
+,volume={67}
+,number="12"
+,year="2007"
+,issn="0743-7315"
+,pages="1270--1285"
+,doi="http://dx.doi.org/10.1016/j.jpdc.2007.04.010"
+,publisher="Academic Press, Inc."
+,address="Orlando, FL, USA"
+,annotation={
+	Compares QSBR, HPBR, EBR, and lock-free reference counting.
+	Journal version of ThomasEHart2006a.
+}
+}
+
+@unpublished{MathieuDesnoyers2007call:rcu:schedNeeded
+,Author="Mathieu Desnoyers"
+,Title="Re: [patch 1/2] {Linux} Kernel Markers - Support Multiple Probes"
+,month="December"
+,day="20"
+,year="2007"
+,note="Available:
+\url{http://lkml.org/lkml/2007/12/20/244}
+[Viewed March 27, 2008]"
+,annotation="
+	Request for call_rcu_sched() and rcu_barrier_sched().
+"
+}
+
+
 ########################################################################
 #
 #	"What is RCU?" LWN series.
 #
+#	http://lwn.net/Articles/262464/ (What is RCU, Fundamentally?)
+#	http://lwn.net/Articles/263130/ (What is RCU's Usage?)
+#	http://lwn.net/Articles/264090/ (What is RCU's API?)
 
 @unpublished{PaulEMcKenney2007WhatIsRCUFundamentally
 ,Author="Paul E. McKenney and Jonathan Walpole"
@@ -723,7 +1838,7 @@
 	3. RCU is a Bulk Reference-Counting Mechanism
 	4. RCU is a Poor Man's Garbage Collector
 	5. RCU is a Way of Providing Existence Guarantees
-	6. RCU is a Way of Waiting for Things to Finish 
+	6. RCU is a Way of Waiting for Things to Finish
 "
 }
 
@@ -747,20 +1862,96 @@
 #
 ########################################################################
 
+
+@unpublished{SteveRostedt2008dyntickRCUpatch
+,Author="Steven Rostedt and Paul E. McKenney"
+,Title="{[PATCH]} add support for dynamic ticks and preempt rcu"
+,month="January"
+,day="29"
+,year="2008"
+,note="Available:
+\url{http://lkml.org/lkml/2008/1/29/208}
+[Viewed March 27, 2008]"
+,annotation="
+	Patch that prevents preemptible RCU from unnecessarily waking
+	up dynticks-idle CPUs.
+"
+}
+
+@unpublished{PaulEMcKenney2008LKMLDependencyOrdering
+,Author="Paul E. McKenney"
+,Title="Re: [PATCH 02/22 -v7] Add basic support for gcc profiler instrumentation"
+,month="February"
+,day="1"
+,year="2008"
+,note="Available:
+\url{http://lkml.org/lkml/2008/2/2/255}
+[Viewed October 18, 2008]"
+,annotation="
+	Explanation of compilers violating dependency ordering.
+"
+}
+
+@Conference{PaulEMcKenney2008Beijing
+,Author="Paul E. McKenney"
+,Title="Introducing Technology Into {Linux} Or:
+Introducing your technology Into {Linux} will require introducing a
+lot of {Linux} into your technology!!!"
+,Booktitle="2008 Linux Developer Symposium - China"
+,Publisher="OSS China"
+,Month="February"
+,Year="2008"
+,Address="Beijing, China"
+,note="Available:
+\url{http://www.rdrop.com/users/paulmck/RCU/TechIntroLinux.2008.02.19a.pdf}
+[Viewed August 12, 2008]"
+}
+
+@unpublished{PaulEMcKenney2008dynticksRCU
+,Author="Paul E. McKenney and Steven Rostedt"
+,Title="Integrating and Validating dynticks and Preemptable RCU"
+,month="April"
+,day="24"
+,year="2008"
+,note="Available:
+\url{http://lwn.net/Articles/279077/}
+[Viewed April 24, 2008]"
+,annotation="
+	Describes use of Promela and Spin to validate (and fix!) the
+	dynticks/RCU interface.
+"
+}
+
 @article{DinakarGuniguntala2008IBMSysJ
 ,author="D. Guniguntala and P. E. McKenney and J. Triplett and J. Walpole"
 ,title="The read-copy-update mechanism for supporting real-time applications on shared-memory multiprocessor systems with {Linux}"
 ,Year="2008"
-,Month="April"
+,Month="April-June"
 ,journal="IBM Systems Journal"
 ,volume="47"
 ,number="2"
-,pages="@@-@@"
+,pages="221-236"
 ,annotation="
 	RCU, realtime RCU, sleepable RCU, performance.
 "
 }
 
+@unpublished{LaiJiangshan2008NewClassicAlgorithm
+,Author="Lai Jiangshan"
+,Title="[{RFC}][{PATCH}] rcu classic: new algorithm for callbacks-processing"
+,month="June"
+,day="3"
+,year="2008"
+,note="Available:
+\url{http://lkml.org/lkml/2008/6/2/539}
+[Viewed December 10, 2008]"
+,annotation="
+	Updated RCU classic algorithm.  Introduced multi-tailed list
+	for RCU callbacks and also pulling common code into
+	__call_rcu().
+"
+}
+
 @article{PaulEMcKenney2008RCUOSR
 ,author="Paul E. McKenney and Jonathan Walpole"
 ,title="Introducing technology into the {Linux} kernel: a case study"
@@ -778,6 +1969,52 @@
 }
 }
 
+@unpublished{ManfredSpraul2008StateMachineRCU
+,Author="Manfred Spraul"
+,Title="[{RFC}, {PATCH}] state machine based rcu"
+,month="August"
+,day="21"
+,year="2008"
+,note="Available:
+\url{http://lkml.org/lkml/2008/8/21/336}
+[Viewed December 8, 2008]"
+,annotation="
+	State-based RCU.  One key thing that this patch does is to
+	separate the dynticks handling of NMIs and IRQs.
+"
+}
+
+@unpublished{ManfredSpraul2008dyntickIRQNMI
+,Author="Manfred Spraul"
+,Title="Re: [{RFC}, {PATCH}] v4 scalable classic {RCU} implementation"
+,month="September"
+,day="6"
+,year="2008"
+,note="Available:
+\url{http://lkml.org/lkml/2008/9/6/86}
+[Viewed December 8, 2008]"
+,annotation="
+	Manfred notes a fix required to my attempt to separate irq
+	and NMI processing for hierarchical RCU's dynticks interface.
+"
+}
+
+@techreport{PaulEMcKenney2008cyclicRCU
+,author="Paul E. McKenney"
+,title="Efficient Support of Consistent Cyclic Search With Read-Copy Update"
+,institution="US Patent and Trademark Office"
+,address="Washington, DC"
+,year="2008"
+,number="US Patent 7,426,511"
+,month="September"
+,pages="23"
+,annotation="
+	Maintains an additional level of indirection to allow
+	readers to confine themselves to the desired snapshot of the
+	data structure.  Only permits one update at a time.
+"
+}
+
 @unpublished{PaulEMcKenney2008HierarchicalRCU
 ,Author="Paul E. McKenney"
 ,Title="Hierarchical {RCU}"
@@ -793,6 +2030,21 @@
 "
 }
 
+@unpublished{PaulEMcKenney2009BloatwatchRCU
+,Author="Paul E. McKenney"
+,Title="Re: [PATCH fyi] RCU: the bloatwatch edition"
+,month="January"
+,day="14"
+,year="2009"
+,note="Available:
+\url{http://lkml.org/lkml/2009/1/14/449}
+[Viewed January 15, 2009]"
+,annotation="
+	Small-footprint implementation of RCU for uniprocessor
+	embedded applications -- and also for exposition purposes.
+"
+}
+
 @conference{PaulEMcKenney2009MaliciousURCU
 ,Author="Paul E. McKenney"
 ,Title="Using a Malicious User-Level {RCU} to Torture {RCU}-Based Algorithms"
@@ -816,15 +2068,17 @@
 ,year="2009"
 ,note="Available:
 \url{http://lkml.org/lkml/2009/2/5/572}
-\url{git://lttng.org/userspace-rcu.git}
+\url{http://lttng.org/urcu}
 [Viewed February 20, 2009]"
 ,annotation="
 	Mathieu Desnoyers's user-space RCU implementation.
 	git://lttng.org/userspace-rcu.git
+	http://lttng.org/cgi-bin/gitweb.cgi?p=userspace-rcu.git
+	http://lttng.org/urcu
 "
 }
 
-@unpublished{PaulEMcKenney2009BloatWatchRCU
+@unpublished{PaulEMcKenney2009LWNBloatWatchRCU
 ,Author="Paul E. McKenney"
 ,Title="{RCU}: The {Bloatwatch} Edition"
 ,month="March"
@@ -852,14 +2106,29 @@
 "
 }
 
-@unpublished{JoshTriplett2009RPHash
+@unpublished{PaulEMcKenney2009fastRTRCU
+,Author="Paul E. McKenney"
+,Title="[{PATCH} {RFC} -tip 0/4] {RCU} cleanups and simplified preemptable {RCU}"
+,month="July"
+,day="23"
+,year="2009"
+,note="Available:
+\url{http://lkml.org/lkml/2009/7/23/294}
+[Viewed August 15, 2009]"
+,annotation="
+	First posting of simple and fast preemptable RCU.
+"
+}
+
+@InProceedings{JoshTriplett2009RPHash
 ,Author="Josh Triplett"
 ,Title="Scalable concurrent hash tables via relativistic programming"
 ,month="September"
 ,year="2009"
-,note="Linux Plumbers Conference presentation"
+,booktitle="Linux Plumbers Conference 2009"
 ,annotation="
 	RP fun with hash tables.
+	See also JoshTriplett2010RPHash
 "
 }
 
@@ -872,4 +2141,323 @@
 ,note="Available:
 \url{http://www.lttng.org/pub/thesis/desnoyers-dissertation-2009-12.pdf}
 [Viewed December 9, 2009]"
+,annotation={
+	Chapter 6 (page 97) covers user-level RCU.
+}
+}
+
+@unpublished{RelativisticProgrammingWiki
+,Author="Josh Triplett and Paul E. McKenney and Jonathan Walpole"
+,Title="Relativistic Programming"
+,month="September"
+,year="2009"
+,note="Available:
+\url{http://wiki.cs.pdx.edu/rp/}
+[Viewed December 9, 2009]"
+,annotation="
+	Main Relativistic Programming Wiki.
+"
+}
+
+@conference{PaulEMcKenney2009DeterministicRCU
+,Author="Paul E. McKenney"
+,Title="Deterministic Synchronization in Multicore Systems: the Role of {RCU}"
+,Booktitle="Eleventh Real Time Linux Workshop"
+,month="September"
+,year="2009"
+,address="Dresden, Germany"
+,note="Available:
+\url{http://www.rdrop.com/users/paulmck/realtime/paper/DetSyncRCU.2009.08.18a.pdf}
+[Viewed January 14, 2009]"
+}
+
+@unpublished{PaulEMcKenney2009HuntingHeisenbugs
+,Author="Paul E. McKenney"
+,Title="Hunting Heisenbugs"
+,month="November"
+,year="2009"
+,day="1"
+,note="Available:
+\url{http://paulmck.livejournal.com/14639.html}
+[Viewed June 4, 2010]"
+,annotation="
+	Day-one bug in Tree RCU that took forever to track down.
+"
+}
+
+@unpublished{MathieuDesnoyers2009defer:rcu
+,Author="Mathieu Desnoyers"
+,Title="Kernel RCU: shrink the size of the struct rcu\_head"
+,month="December"
+,year="2009"
+,note="Available:
+\url{http://lkml.org/lkml/2009/10/18/129}
+[Viewed December 29, 2009]"
+,annotation="
+	Mathieu proposed defer_rcu() with fixed-size per-thread pool
+	of RCU callbacks.
+"
+}
+
+@unpublished{MathieuDesnoyers2009VerifPrePub
+,Author="Mathieu Desnoyers and Paul E. McKenney and Michel R. Dagenais"
+,Title="Multi-Core Systems Modeling for Formal Verification of Parallel Algorithms"
+,month="December"
+,year="2009"
+,note="Submitted to IEEE TPDS"
+,annotation="
+	OOMem model for Mathieu's user-level RCU mechanical proof of
+	correctness.
+"
+}
+
+@unpublished{MathieuDesnoyers2009URCUPrePub
+,Author="Mathieu Desnoyers and Paul E. McKenney and Alan Stern and Michel R. Dagenais and Jonathan Walpole"
+,Title="User-Level Implementations of Read-Copy Update"
+,month="December"
+,year="2010"
+,url=\url{http://www.computer.org/csdl/trans/td/2012/02/ttd2012020375-abs.html}
+,annotation="
+	RCU overview, desiderata, semi-formal semantics, user-level RCU
+	usage scenarios, three classes of RCU implementation, wait-free
+	RCU updates, RCU grace-period batching, update overhead,
+	http://www.rdrop.com/users/paulmck/RCU/urcu-main-accepted.2011.08.30a.pdf
+	http://www.rdrop.com/users/paulmck/RCU/urcu-supp-accepted.2011.08.30a.pdf
+	Superseded by MathieuDesnoyers2012URCU.
+"
+}
+
+@inproceedings{HariKannan2009DynamicAnalysisRCU
+,author = {Kannan, Hari}
+,title = {Ordering decoupled metadata accesses in multiprocessors}
+,booktitle = {MICRO 42: Proceedings of the 42nd Annual IEEE/ACM International Symposium on Microarchitecture}
+,year = {2009}
+,isbn = {978-1-60558-798-1}
+,pages = {381--390}
+,location = {New York, New York}
+,doi = {http://doi.acm.org/10.1145/1669112.1669161}
+,publisher = {ACM}
+,address = {New York, NY, USA}
+,annotation={
+	Uses RCU to protect metadata used in dynamic analysis.
+}}
+
+@conference{PaulEMcKenney2010SimpleOptRCU
+,Author="Paul E. McKenney"
+,Title="Simplicity Through Optimization"
+,Booktitle="linux.conf.au 2010"
+,month="January"
+,year="2010"
+,address="Wellington, New Zealand"
+,note="Available:
+\url{http://www.rdrop.com/users/paulmck/RCU/SimplicityThruOptimization.2010.01.21f.pdf}
+[Viewed October 10, 2010]"
+,annotation="
+	TREE_PREEMPT_RCU optimizations greatly simplified the old
+	PREEMPT_RCU implementation.
+"
+}
+
+@unpublished{PaulEMcKenney2010LockdepRCU
+,Author="Paul E. McKenney"
+,Title="Lockdep-{RCU}"
+,month="February"
+,year="2010"
+,day="1"
+,note="Available:
+\url{https://lwn.net/Articles/371986/}
+[Viewed June 4, 2010]"
+,annotation="
+	CONFIG_PROVE_RCU, or at least an early version.
+"
+}
+
+@unpublished{AviKivity2010KVM2RCU
+,Author="Avi Kivity"
+,Title="[{PATCH} 37/40] {KVM}: Bump maximum vcpu count to 64"
+,month="February"
+,year="2010"
+,note="Available:
+\url{http://www.mail-archive.com/kvm@vger.kernel.org/msg28640.html}
+[Viewed March 20, 2010]"
+,annotation="
+	Use of RCU permits KVM to increase the size of guest OSes from
+	16 CPUs to 64 CPUs.
+"
+}
+
+@unpublished{HerbertXu2010RCUResizeHash
+,Author="Herbert Xu"
+,Title="bridge: Add core IGMP snooping support"
+,month="February"
+,year="2010"
+,note="Available:
+\url{http://kerneltrap.com/mailarchive/linux-netdev/2010/2/26/6270589}
+[Viewed March 20, 2011]"
+,annotation={
+	Use a pair of list_head structures to support RCU-protected
+	resizable hash tables.
+}}
+
+@article{JoshTriplett2010RPHash
+,author="Josh Triplett and Paul E. McKenney and Jonathan Walpole"
+,title="Scalable Concurrent Hash Tables via Relativistic Programming"
+,journal="ACM Operating Systems Review"
+,year=2010
+,volume=44
+,number=3
+,month="July"
+,annotation={
+	RP fun with hash tables.
+	http://portal.acm.org/citation.cfm?id=1842733.1842750
+}}
+
+@unpublished{PaulEMcKenney2010RCUAPI
+,Author="Paul E. McKenney"
+,Title="The {RCU} {API}, 2010 Edition"
+,month="December"
+,day="8"
+,year="2010"
+,note="Available:
+\url{http://lwn.net/Articles/418853/}
+[Viewed December 8, 2010]"
+,annotation="
+	Includes updated software-engineering features.
+"
+}
+
+@mastersthesis{AndrejPodzimek2010masters
+,author="Andrej Podzimek"
+,title="Read-Copy-Update for OpenSolaris"
+,school="Charles University in Prague"
+,year="2010"
+,note="Available:
+\url{https://andrej.podzimek.org/thesis.pdf}
+[Viewed January 31, 2011]"
+,annotation={
+	Reviews RCU implementations and creates a few for OpenSolaris.
+	Drives quiescent-state detection from RCU read-side primitives,
+	in a manner roughly similar to that of Jim Houston.
+}}
+
+@unpublished{LinusTorvalds2011Linux2:6:38:rc1:NPigginVFS
+,Author="Linus Torvalds"
+,Title="Linux 2.6.38-rc1"
+,month="January"
+,year="2011"
+,note="Available:
+\url{https://lkml.org/lkml/2011/1/18/322}
+[Viewed March 4, 2011]"
+,annotation={
+	"The RCU-based name lookup is at the other end of the spectrum - the
+	absolute anti-gimmick. It's some seriously good stuff, and gets rid of
+	the last main global lock that really tends to hurt some kernel loads.
+	The dentry lock is no longer a big serializing issue. What's really
+	nice about it is that it actually improves performance a lot even for
+	single-threaded loads (on an SMP kernel), because it gets rid of some
+	of the most expensive parts of path component lookup, which was the
+	d_lock on every component lookup. So I'm seeing improvements of 30-50%
+	on some seriously pathname-lookup intensive loads."
+}}
+
+@techreport{JoshTriplett2011RPScalableCorrectOrdering
+,author = {Josh Triplett and Philip W. Howard and Paul E. McKenney and Jonathan Walpole}
+,title = {Scalable Correct Memory Ordering via Relativistic Programming}
+,year = {2011}
+,number = {11-03}
+,institution = {Portland State University}
+,note = {\url{http://www.cs.pdx.edu/pdfs/tr1103.pdf}}
+}
+
+@inproceedings{PhilHoward2011RCUTMRBTree
+,author = {Philip W. Howard and Jonathan Walpole}
+,title = {A Relativistic Enhancement to Software Transactional Memory}
+,booktitle = {Proceedings of the 3rd USENIX conference on Hot topics in parallelism}
+,series = {HotPar'11}
+,year = {2011}
+,location = {Berkeley, CA}
+,pages = {1--6}
+,numpages = {6}
+,url = {http://www.usenix.org/event/hotpar11/tech/final_files/Howard.pdf}
+,publisher = {USENIX Association}
+,address = {Berkeley, CA, USA}
+}
+
+@techreport{PaulEMcKenney2011cyclicparallelRCU
+,author="Paul E. McKenney and Jonathan Walpole"
+,title="Efficient Support of Consistent Cyclic Search With Read-Copy Update and Parallel Updates"
+,institution="US Patent and Trademark Office"
+,address="Washington, DC"
+,year="2011"
+,number="US Patent 7,953,778"
+,month="May"
+,pages="34"
+,annotation="
+	Maintains an array of generation numbers to track in-flight
+	updates and keeps an additional level of indirection to allow
+	readers to confine themselves to the desired snapshot of the
+	data structure.
+"
+}
+
+@inproceedings{Triplett:2011:RPHash
+,author = {Triplett, Josh and McKenney, Paul E. and Walpole, Jonathan}
+,title = {Resizable, Scalable, Concurrent Hash Tables via Relativistic Programming}
+,booktitle = {Proceedings of the 2011 USENIX Annual Technical Conference}
+,month = {June}
+,year = {2011}
+,pages = {145--158}
+,numpages = {14}
+,url={http://www.usenix.org/event/atc11/tech/final_files/atc11_proceedings.pdf}
+,publisher = {The USENIX Association}
+,address = {Portland, OR USA}
+}
+
+@unpublished{PaulEMcKenney2011RCU3.0trainwreck
+,Author="Paul E. McKenney"
+,Title="3.0 and {RCU:} what went wrong"
+,month="July"
+,day="27"
+,year="2011"
+,note="Available:
+\url{http://lwn.net/Articles/453002/}
+[Viewed July 27, 2011]"
+,annotation="
+	Analysis of the RCU trainwreck in Linux kernel 3.0.
+"
+}
+
+@unpublished{NeilBrown2011MeetTheLockers
+,Author="Neil Brown"
+,Title="Meet the Lockers"
+,month="August"
+,day="3"
+,year="2011"
+,note="Available:
+\url{http://lwn.net/Articles/453685/}
+[Viewed September 2, 2011]"
+,annotation="
+	The Locker family as an analogy for locking, reference counting,
+	RCU, and seqlock.
+"
+}
+
+@article{MathieuDesnoyers2012URCU
+,Author="Mathieu Desnoyers and Paul E. McKenney and Alan Stern and Michel R. Dagenais and Jonathan Walpole"
+,Title="User-Level Implementations of Read-Copy Update"
+,journal="IEEE Transactions on Parallel and Distributed Systems"
+,volume={23}
+,year="2012"
+,issn="1045-9219"
+,pages="375-382"
+,doi="http://doi.ieeecomputersociety.org/10.1109/TPDS.2011.159"
+,publisher="IEEE Computer Society"
+,address="Los Alamitos, CA, USA"
+,annotation={
+	RCU overview, desiderata, semi-formal semantics, user-level RCU
+	usage scenarios, three classes of RCU implementation, wait-free
+	RCU updates, RCU grace-period batching, update overhead,
+	http://www.rdrop.com/users/paulmck/RCU/urcu-main-accepted.2011.08.30a.pdf
+	http://www.rdrop.com/users/paulmck/RCU/urcu-supp-accepted.2011.08.30a.pdf
+}
 }
diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
index bff2d8b..5c8d749 100644
--- a/Documentation/RCU/checklist.txt
+++ b/Documentation/RCU/checklist.txt
@@ -180,6 +180,20 @@
 	operations that would not normally be undertaken while a real-time
 	workload is running.
 
+	In particular, if you find yourself invoking one of the expedited
+	primitives repeatedly in a loop, please do everyone a favor:
+	Restructure your code so that it batches the updates, allowing
+	a single non-expedited primitive to cover the entire batch.
+	This will very likely be faster than the loop containing the
+	expedited primitive, and will be much much easier on the rest
+	of the system, especially to real-time workloads running on
+	the rest of the system.
+
+	In addition, it is illegal to call the expedited forms from
+	a CPU-hotplug notifier, or while holding a lock that is acquired
+	by a CPU-hotplug notifier.  Failing to observe this restriction
+	will result in deadlock.
+
 7.	If the updater uses call_rcu() or synchronize_rcu(), then the
 	corresponding readers must use rcu_read_lock() and
 	rcu_read_unlock().  If the updater uses call_rcu_bh() or
diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt
index 083d88c..523364e 100644
--- a/Documentation/RCU/stallwarn.txt
+++ b/Documentation/RCU/stallwarn.txt
@@ -12,14 +12,38 @@
 	This kernel configuration parameter defines the period of time
 	that RCU will wait from the beginning of a grace period until it
 	issues an RCU CPU stall warning.  This time period is normally
-	ten seconds.
+	sixty seconds.
 
-RCU_SECONDS_TILL_STALL_RECHECK
+	This configuration parameter may be changed at runtime via the
+	/sys/module/rcutree/parameters/rcu_cpu_stall_timeout, however
+	this parameter is checked only at the beginning of a cycle.
+	So if you are 30 seconds into a 70-second stall, setting this
+	sysfs parameter to (say) five will shorten the timeout for the
+	-next- stall, or the following warning for the current stall
+	(assuming the stall lasts long enough).  It will not affect the
+	timing of the next warning for the current stall.
 
-	This macro defines the period of time that RCU will wait after
-	issuing a stall warning until it issues another stall warning
-	for the same stall.  This time period is normally set to three
-	times the check interval plus thirty seconds.
+	Stall-warning messages may be enabled and disabled completely via
+	/sys/module/rcutree/parameters/rcu_cpu_stall_suppress.
+
+CONFIG_RCU_CPU_STALL_VERBOSE
+
+	This kernel configuration parameter causes the stall warning to
+	also dump the stacks of any tasks that are blocking the current
+	RCU-preempt grace period.
+
+RCU_CPU_STALL_INFO
+
+	This kernel configuration parameter causes the stall warning to
+	print out additional per-CPU diagnostic information, including
+	information on scheduling-clock ticks and RCU's idle-CPU tracking.
+
+RCU_STALL_DELAY_DELTA
+
+	Although the lockdep facility is extremely useful, it does add
+	some overhead.  Therefore, under CONFIG_PROVE_RCU, the
+	RCU_STALL_DELAY_DELTA macro allows five extra seconds before
+	giving an RCU CPU stall warning message.
 
 RCU_STALL_RAT_DELAY
 
@@ -64,6 +88,54 @@
 
 This is rare, but does happen from time to time in real life.
 
+If the CONFIG_RCU_CPU_STALL_INFO kernel configuration parameter is set,
+more information is printed with the stall-warning message, for example:
+
+	INFO: rcu_preempt detected stall on CPU
+	0: (63959 ticks this GP) idle=241/3fffffffffffffff/0
+	   (t=65000 jiffies)
+
+In kernels with CONFIG_RCU_FAST_NO_HZ, even more information is
+printed:
+
+	INFO: rcu_preempt detected stall on CPU
+	0: (64628 ticks this GP) idle=dd5/3fffffffffffffff/0 drain=0 . timer=-1
+	   (t=65000 jiffies)
+
+The "(64628 ticks this GP)" indicates that this CPU has taken more
+than 64,000 scheduling-clock interrupts during the current stalled
+grace period.  If the CPU was not yet aware of the current grace
+period (for example, if it was offline), then this part of the message
+indicates how many grace periods behind the CPU is.
+
+The "idle=" portion of the message prints the dyntick-idle state.
+The hex number before the first "/" is the low-order 12 bits of the
+dynticks counter, which will have an even-numbered value if the CPU is
+in dyntick-idle mode and an odd-numbered value otherwise.  The hex
+number between the two "/"s is the value of the nesting, which will
+be a small positive number if in the idle loop and a very large positive
+number (as shown above) otherwise.
+
+For CONFIG_RCU_FAST_NO_HZ kernels, the "drain=0" indicates that the
+CPU is not in the process of trying to force itself into dyntick-idle
+state, the "." indicates that the CPU has not given up forcing RCU
+into dyntick-idle mode (it would be "H" otherwise), and the "timer=-1"
+indicates that the CPU has not recented forced RCU into dyntick-idle
+mode (it would otherwise indicate the number of microseconds remaining
+in this forced state).
+
+
+Multiple Warnings From One Stall
+
+If a stall lasts long enough, multiple stall-warning messages will be
+printed for it.  The second and subsequent messages are printed at
+longer intervals, so that the time between (say) the first and second
+message will be about three times the interval between the beginning
+of the stall and the first message.
+
+
+What Causes RCU CPU Stall Warnings?
+
 So your kernel printed an RCU CPU stall warning.  The next question is
 "What caused it?"  The following problems can result in RCU CPU stall
 warnings:
@@ -128,4 +200,5 @@
 that portion of the stack which remains the same from trace to trace.
 If you can reliably trigger the stall, ftrace can be quite helpful.
 
-RCU bugs can often be debugged with the help of CONFIG_RCU_TRACE.
+RCU bugs can often be debugged with the help of CONFIG_RCU_TRACE
+and with RCU's event tracing.
diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt
index d67068d..375d3fb 100644
--- a/Documentation/RCU/torture.txt
+++ b/Documentation/RCU/torture.txt
@@ -69,6 +69,13 @@
 		CPU-hotplug operations regardless of what value is
 		specified for onoff_interval.
 
+onoff_holdoff	The number of seconds to wait until starting CPU-hotplug
+		operations.  This would normally only be used when
+		rcutorture was built into the kernel and started
+		automatically at boot time, in which case it is useful
+		in order to avoid confusing boot-time code with CPUs
+		coming and going.
+
 shuffle_interval
 		The number of seconds to keep the test threads affinitied
 		to a particular subset of the CPUs, defaults to 3 seconds.
@@ -79,6 +86,24 @@
 		zero, which disables test termination and system shutdown.
 		This capability is useful for automated testing.
 
+stall_cpu	The number of seconds that a CPU should be stalled while
+		within both an rcu_read_lock() and a preempt_disable().
+		This stall happens only once per rcutorture run.
+		If you need multiple stalls, use modprobe and rmmod to
+		repeatedly run rcutorture.  The default for stall_cpu
+		is zero, which prevents rcutorture from stalling a CPU.
+
+		Note that attempts to rmmod rcutorture while the stall
+		is ongoing will hang, so be careful what value you
+		choose for this module parameter!  In addition, too-large
+		values for stall_cpu might well induce failures and
+		warnings in other parts of the kernel.  You have been
+		warned!
+
+stall_cpu_holdoff
+		The number of seconds to wait after rcutorture starts
+		before stalling a CPU.  Defaults to 10 seconds.
+
 stat_interval	The number of seconds between output of torture
 		statistics (via printk()).  Regardless of the interval,
 		statistics are printed when the module is unloaded.
@@ -271,11 +296,13 @@
 	#!/bin/sh
 
 	modprobe rcutorture
-	sleep 100
+	sleep 3600
 	rmmod rcutorture
 	dmesg | grep torture:
 
 The output can be manually inspected for the error flag of "!!!".
 One could of course create a more elaborate script that automatically
-checked for such errors.  The "rmmod" command forces a "SUCCESS" or
-"FAILURE" indication to be printk()ed.
+checked for such errors.  The "rmmod" command forces a "SUCCESS",
+"FAILURE", or "RCU_HOTPLUG" indication to be printk()ed.  The first
+two are self-explanatory, while the last indicates that while there
+were no RCU failures, CPU-hotplug problems were detected.
diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt
index 49587ab..f6f15ce 100644
--- a/Documentation/RCU/trace.txt
+++ b/Documentation/RCU/trace.txt
@@ -33,23 +33,23 @@
 The output of "cat rcu/rcudata" looks as follows:
 
 rcu_sched:
-  0 c=20972 g=20973 pq=1 pgp=20973 qp=0 dt=545/1/0 df=50 of=0 ri=0 ql=163 qs=NRW. kt=0/W/0 ktl=ebc3 b=10 ci=153737 co=0 ca=0
-  1 c=20972 g=20973 pq=1 pgp=20973 qp=0 dt=967/1/0 df=58 of=0 ri=0 ql=634 qs=NRW. kt=0/W/1 ktl=58c b=10 ci=191037 co=0 ca=0
-  2 c=20972 g=20973 pq=1 pgp=20973 qp=0 dt=1081/1/0 df=175 of=0 ri=0 ql=74 qs=N.W. kt=0/W/2 ktl=da94 b=10 ci=75991 co=0 ca=0
-  3 c=20942 g=20943 pq=1 pgp=20942 qp=1 dt=1846/0/0 df=404 of=0 ri=0 ql=0 qs=.... kt=0/W/3 ktl=d1cd b=10 ci=72261 co=0 ca=0
-  4 c=20972 g=20973 pq=1 pgp=20973 qp=0 dt=369/1/0 df=83 of=0 ri=0 ql=48 qs=N.W. kt=0/W/4 ktl=e0e7 b=10 ci=128365 co=0 ca=0
-  5 c=20972 g=20973 pq=1 pgp=20973 qp=0 dt=381/1/0 df=64 of=0 ri=0 ql=169 qs=NRW. kt=0/W/5 ktl=fb2f b=10 ci=164360 co=0 ca=0
-  6 c=20972 g=20973 pq=1 pgp=20973 qp=0 dt=1037/1/0 df=183 of=0 ri=0 ql=62 qs=N.W. kt=0/W/6 ktl=d2ad b=10 ci=65663 co=0 ca=0
-  7 c=20897 g=20897 pq=1 pgp=20896 qp=0 dt=1572/0/0 df=382 of=0 ri=0 ql=0 qs=.... kt=0/W/7 ktl=cf15 b=10 ci=75006 co=0 ca=0
+  0 c=20972 g=20973 pq=1 pgp=20973 qp=0 dt=545/1/0 df=50 of=0 ql=163 qs=NRW. kt=0/W/0 ktl=ebc3 b=10 ci=153737 co=0 ca=0
+  1 c=20972 g=20973 pq=1 pgp=20973 qp=0 dt=967/1/0 df=58 of=0 ql=634 qs=NRW. kt=0/W/1 ktl=58c b=10 ci=191037 co=0 ca=0
+  2 c=20972 g=20973 pq=1 pgp=20973 qp=0 dt=1081/1/0 df=175 of=0 ql=74 qs=N.W. kt=0/W/2 ktl=da94 b=10 ci=75991 co=0 ca=0
+  3 c=20942 g=20943 pq=1 pgp=20942 qp=1 dt=1846/0/0 df=404 of=0 ql=0 qs=.... kt=0/W/3 ktl=d1cd b=10 ci=72261 co=0 ca=0
+  4 c=20972 g=20973 pq=1 pgp=20973 qp=0 dt=369/1/0 df=83 of=0 ql=48 qs=N.W. kt=0/W/4 ktl=e0e7 b=10 ci=128365 co=0 ca=0
+  5 c=20972 g=20973 pq=1 pgp=20973 qp=0 dt=381/1/0 df=64 of=0 ql=169 qs=NRW. kt=0/W/5 ktl=fb2f b=10 ci=164360 co=0 ca=0
+  6 c=20972 g=20973 pq=1 pgp=20973 qp=0 dt=1037/1/0 df=183 of=0 ql=62 qs=N.W. kt=0/W/6 ktl=d2ad b=10 ci=65663 co=0 ca=0
+  7 c=20897 g=20897 pq=1 pgp=20896 qp=0 dt=1572/0/0 df=382 of=0 ql=0 qs=.... kt=0/W/7 ktl=cf15 b=10 ci=75006 co=0 ca=0
 rcu_bh:
-  0 c=1480 g=1480 pq=1 pgp=1480 qp=0 dt=545/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/0 ktl=ebc3 b=10 ci=0 co=0 ca=0
-  1 c=1480 g=1480 pq=1 pgp=1480 qp=0 dt=967/1/0 df=3 of=0 ri=1 ql=0 qs=.... kt=0/W/1 ktl=58c b=10 ci=151 co=0 ca=0
-  2 c=1480 g=1480 pq=1 pgp=1480 qp=0 dt=1081/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/2 ktl=da94 b=10 ci=0 co=0 ca=0
-  3 c=1480 g=1480 pq=1 pgp=1480 qp=0 dt=1846/0/0 df=8 of=0 ri=1 ql=0 qs=.... kt=0/W/3 ktl=d1cd b=10 ci=0 co=0 ca=0
-  4 c=1480 g=1480 pq=1 pgp=1480 qp=0 dt=369/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/4 ktl=e0e7 b=10 ci=0 co=0 ca=0
-  5 c=1480 g=1480 pq=1 pgp=1480 qp=0 dt=381/1/0 df=4 of=0 ri=1 ql=0 qs=.... kt=0/W/5 ktl=fb2f b=10 ci=0 co=0 ca=0
-  6 c=1480 g=1480 pq=1 pgp=1480 qp=0 dt=1037/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/6 ktl=d2ad b=10 ci=0 co=0 ca=0
-  7 c=1474 g=1474 pq=1 pgp=1473 qp=0 dt=1572/0/0 df=8 of=0 ri=1 ql=0 qs=.... kt=0/W/7 ktl=cf15 b=10 ci=0 co=0 ca=0
+  0 c=1480 g=1480 pq=1 pgp=1480 qp=0 dt=545/1/0 df=6 of=0 ql=0 qs=.... kt=0/W/0 ktl=ebc3 b=10 ci=0 co=0 ca=0
+  1 c=1480 g=1480 pq=1 pgp=1480 qp=0 dt=967/1/0 df=3 of=0 ql=0 qs=.... kt=0/W/1 ktl=58c b=10 ci=151 co=0 ca=0
+  2 c=1480 g=1480 pq=1 pgp=1480 qp=0 dt=1081/1/0 df=6 of=0 ql=0 qs=.... kt=0/W/2 ktl=da94 b=10 ci=0 co=0 ca=0
+  3 c=1480 g=1480 pq=1 pgp=1480 qp=0 dt=1846/0/0 df=8 of=0 ql=0 qs=.... kt=0/W/3 ktl=d1cd b=10 ci=0 co=0 ca=0
+  4 c=1480 g=1480 pq=1 pgp=1480 qp=0 dt=369/1/0 df=6 of=0 ql=0 qs=.... kt=0/W/4 ktl=e0e7 b=10 ci=0 co=0 ca=0
+  5 c=1480 g=1480 pq=1 pgp=1480 qp=0 dt=381/1/0 df=4 of=0 ql=0 qs=.... kt=0/W/5 ktl=fb2f b=10 ci=0 co=0 ca=0
+  6 c=1480 g=1480 pq=1 pgp=1480 qp=0 dt=1037/1/0 df=6 of=0 ql=0 qs=.... kt=0/W/6 ktl=d2ad b=10 ci=0 co=0 ca=0
+  7 c=1474 g=1474 pq=1 pgp=1473 qp=0 dt=1572/0/0 df=8 of=0 ql=0 qs=.... kt=0/W/7 ktl=cf15 b=10 ci=0 co=0 ca=0
 
 The first section lists the rcu_data structures for rcu_sched, the second
 for rcu_bh.  Note that CONFIG_TREE_PREEMPT_RCU kernels will have an
@@ -119,10 +119,6 @@
 	CPU is offline when it is really alive and kicking) is a fatal
 	error, so it makes sense to err conservatively.
 
-o	"ri" is the number of times that RCU has seen fit to send a
-	reschedule IPI to this CPU in order to get it to report a
-	quiescent state.
-
 o	"ql" is the number of RCU callbacks currently residing on
 	this CPU.  This is the total number of callbacks, regardless
 	of what state they are in (new, waiting for grace period to
diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt
index a7c96ae..8e74980 100644
--- a/Documentation/cgroups/cgroups.txt
+++ b/Documentation/cgroups/cgroups.txt
@@ -558,8 +558,7 @@
 methods are create/destroy. Any others that are null are presumed to
 be successful no-ops.
 
-struct cgroup_subsys_state *create(struct cgroup_subsys *ss,
-				   struct cgroup *cgrp)
+struct cgroup_subsys_state *create(struct cgroup *cgrp)
 (cgroup_mutex held by caller)
 
 Called to create a subsystem state object for a cgroup. The
@@ -574,7 +573,7 @@
 it's the root of the hierarchy) and may be an appropriate place for
 initialization code.
 
-void destroy(struct cgroup_subsys *ss, struct cgroup *cgrp)
+void destroy(struct cgroup *cgrp)
 (cgroup_mutex held by caller)
 
 The cgroup system is about to destroy the passed cgroup; the subsystem
@@ -585,7 +584,7 @@
 newly-created cgroup if an error occurs after this subsystem's
 create() method has been called for the new cgroup).
 
-int pre_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp);
+int pre_destroy(struct cgroup *cgrp);
 
 Called before checking the reference count on each subsystem. This may
 be useful for subsystems which have some extra references even if
@@ -593,8 +592,7 @@
 rmdir() will fail with it. From this behavior, pre_destroy() can be
 called multiple times against a cgroup.
 
-int can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
-	       struct cgroup_taskset *tset)
+int can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
 (cgroup_mutex held by caller)
 
 Called prior to moving one or more tasks into a cgroup; if the
@@ -615,8 +613,7 @@
 while the caller holds cgroup_mutex and it is ensured that either
 attach() or cancel_attach() will be called in future.
 
-void cancel_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
-		   struct cgroup_taskset *tset)
+void cancel_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
 (cgroup_mutex held by caller)
 
 Called when a task attach operation has failed after can_attach() has succeeded.
@@ -625,23 +622,22 @@
 This will be called only about subsystems whose can_attach() operation have
 succeeded. The parameters are identical to can_attach().
 
-void attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
-	    struct cgroup_taskset *tset)
+void attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
 (cgroup_mutex held by caller)
 
 Called after the task has been attached to the cgroup, to allow any
 post-attachment activity that requires memory allocations or blocking.
 The parameters are identical to can_attach().
 
-void fork(struct cgroup_subsy *ss, struct task_struct *task)
+void fork(struct task_struct *task)
 
 Called when a task is forked into a cgroup.
 
-void exit(struct cgroup_subsys *ss, struct task_struct *task)
+void exit(struct task_struct *task)
 
 Called during task exit.
 
-int populate(struct cgroup_subsys *ss, struct cgroup *cgrp)
+int populate(struct cgroup *cgrp)
 (cgroup_mutex held by caller)
 
 Called after creation of a cgroup to allow a subsystem to populate
@@ -651,7 +647,7 @@
 method can return an error code, the error code is currently not
 always handled well.
 
-void post_clone(struct cgroup_subsys *ss, struct cgroup *cgrp)
+void post_clone(struct cgroup *cgrp)
 (cgroup_mutex held by caller)
 
 Called during cgroup_create() to do any parameter
@@ -659,7 +655,7 @@
 example in cpusets, no task may attach before 'cpus' and 'mems' are set
 up.
 
-void bind(struct cgroup_subsys *ss, struct cgroup *root)
+void bind(struct cgroup *root)
 (cgroup_mutex and ss->hierarchy_mutex held by caller)
 
 Called when a cgroup subsystem is rebound to a different hierarchy
diff --git a/Documentation/devicetree/bindings/tty/serial/efm32-uart.txt b/Documentation/devicetree/bindings/tty/serial/efm32-uart.txt
new file mode 100644
index 0000000..6588b69
--- /dev/null
+++ b/Documentation/devicetree/bindings/tty/serial/efm32-uart.txt
@@ -0,0 +1,14 @@
+* Energymicro efm32 UART
+
+Required properties:
+- compatible : Should be "efm32,uart"
+- reg : Address and length of the register set
+- interrupts : Should contain uart interrupt
+
+Example:
+
+uart@0x4000c400 {
+	compatible = "efm32,uart";
+	reg = <0x4000c400 0x400>;
+	interrupts = <15>;
+};
diff --git a/Documentation/dynamic-debug-howto.txt b/Documentation/dynamic-debug-howto.txt
index f959909..74e6c77 100644
--- a/Documentation/dynamic-debug-howto.txt
+++ b/Documentation/dynamic-debug-howto.txt
@@ -12,7 +12,7 @@
 Dynamic debug has even more useful features:
 
  * Simple query language allows turning on and off debugging statements by
-   matching any combination of:
+   matching any combination of 0 or 1 of:
 
    - source filename
    - function name
@@ -79,31 +79,24 @@
 ==========================
 
 At the lexical level, a command comprises a sequence of words separated
-by whitespace characters.  Note that newlines are treated as word
-separators and do *not* end a command or allow multiple commands to
-be done together.  So these are all equivalent:
+by spaces or tabs.  So these are all equivalent:
 
 nullarbor:~ # echo -c 'file svcsock.c line 1603 +p' >
 				<debugfs>/dynamic_debug/control
 nullarbor:~ # echo -c '  file   svcsock.c     line  1603 +p  ' >
 				<debugfs>/dynamic_debug/control
-nullarbor:~ # echo -c 'file svcsock.c\nline 1603 +p' >
-				<debugfs>/dynamic_debug/control
 nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >
 				<debugfs>/dynamic_debug/control
 
-Commands are bounded by a write() system call.  If you want to do
-multiple commands you need to do a separate "echo" for each, like:
+Command submissions are bounded by a write() system call.
+Multiple commands can be written together, separated by ';' or '\n'.
 
-nullarbor:~ # echo 'file svcsock.c line 1603 +p' > /proc/dprintk ;\
-> echo 'file svcsock.c line 1563 +p' > /proc/dprintk
+  ~# echo "func pnpacpi_get_resources +p; func pnp_assign_mem +p" \
+     > <debugfs>/dynamic_debug/control
 
-or even like:
+If your query set is big, you can batch them too:
 
-nullarbor:~ # (
-> echo 'file svcsock.c line 1603 +p' ;\
-> echo 'file svcsock.c line 1563 +p' ;\
-> ) > /proc/dprintk
+  ~# cat query-batch-file > <debugfs>/dynamic_debug/control
 
 At the syntactical level, a command comprises a sequence of match
 specifications, followed by a flags change specification.
@@ -144,11 +137,12 @@
     func svc_tcp_accept
 
 file
-    The given string is compared against either the full
-    pathname or the basename of the source file of each
-    callsite.  Examples:
+    The given string is compared against either the full pathname, the
+    src-root relative pathname, or the basename of the source file of
+    each callsite.  Examples:
 
     file svcsock.c
+    file kernel/freezer.c
     file /usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c
 
 module
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index a0ffac0..d5dc80f 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -524,3 +524,14 @@
 Why:	The code is not actively maintained and platforms are now hard to find.
 Who:	Nicolas Ferre <nicolas.ferre@atmel.com>
 	Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+
+----------------------------
+
+What:	Low Performance USB Block driver ("CONFIG_BLK_DEV_UB")
+When:	3.6
+Why:	This driver provides support for USB storage devices like "USB
+	sticks". As of now, it is deactivated in Debian, Fedora and
+        Ubuntu. All current users can switch over to usb-storage
+        (CONFIG_USB_STORAGE) which only drawback is the additional SCSI
+        stack.
+Who:	Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
diff --git a/Documentation/filesystems/debugfs.txt b/Documentation/filesystems/debugfs.txt
index 6872c91..4e25758 100644
--- a/Documentation/filesystems/debugfs.txt
+++ b/Documentation/filesystems/debugfs.txt
@@ -14,7 +14,10 @@
 
     mount -t debugfs none /sys/kernel/debug
 
-(Or an equivalent /etc/fstab line). 
+(Or an equivalent /etc/fstab line).
+The debugfs root directory is accessible by anyone by default. To
+restrict access to the tree the "uid", "gid" and "mode" mount
+options can be used.
 
 Note that the debugfs API is exported GPL-only to modules.
 
diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf
index 3f44dbd..ceaf6f6 100644
--- a/Documentation/hwmon/w83627ehf
+++ b/Documentation/hwmon/w83627ehf
@@ -50,7 +50,7 @@
 (NCT6775F), and NCT6776F super I/O chips. We will refer to them collectively
 as Winbond chips.
 
-The chips implement 2 to 4 temperature sensors (9 for NCT6775F and NCT6776F),
+The chips implement 3 to 4 temperature sensors (9 for NCT6775F and NCT6776F),
 2 to 5 fan rotation speed sensors, 8 to 10 analog voltage sensors, one VID
 (except for 627UHG), alarms with beep warnings (control unimplemented),
 and some automatic fan regulation strategies (plus manual fan control mode).
@@ -143,8 +143,13 @@
 pwm[1-4]_stop_time  - how many milliseconds [ms] must elapse to switch
                       corresponding fan off. (when the temperature was below
                       defined range).
+pwm[1-4]_start_output-minimum fan speed (range 1 - 255) when spinning up
+pwm[1-4]_step_output- rate of fan speed change (1 - 255)
+pwm[1-4]_stop_output- minimum fan speed (range 1 - 255) when spinning down
+pwm[1-4]_max_output - maximum fan speed (range 1 - 255), when the temperature
+                      is above defined range.
 
-Note: last two functions are influenced by other control bits, not yet exported
+Note: last six functions are influenced by other control bits, not yet exported
       by the driver, so a change might not have any effect.
 
 Implementation Details
diff --git a/Documentation/hwmon/zl6100 b/Documentation/hwmon/zl6100
index 51f76a1..a4e8d90 100644
--- a/Documentation/hwmon/zl6100
+++ b/Documentation/hwmon/zl6100
@@ -88,14 +88,12 @@
 delay
 -----
 
-Some Intersil/Zilker Labs DC-DC controllers require a minimum interval between
-I2C bus accesses. According to Intersil, the minimum interval is 2 ms, though
-1 ms appears to be sufficient and has not caused any problems in testing.
-The problem is known to affect ZL6100, ZL2105, and ZL2008. It is known not to
-affect ZL2004 and ZL6105. The driver automatically sets the interval to 1 ms
-except for ZL2004 and ZL6105. To enable manual override, the driver provides a
-writeable module parameter, 'delay', which can be used to set the interval to
-a value between 0 and 65,535 microseconds.
+Intersil/Zilker Labs DC-DC controllers require a minimum interval between I2C
+bus accesses. According to Intersil, the minimum interval is 2 ms, though 1 ms
+appears to be sufficient and has not caused any problems in testing. The problem
+is known to affect all currently supported chips. For manual override, the
+driver provides a writeable module parameter, 'delay', which can be used to set
+the interval to a value between 0 and 65,535 microseconds.
 
 
 Sysfs entries
diff --git a/Documentation/i2c/instantiating-devices b/Documentation/i2c/instantiating-devices
index 9edb75d..abf6361 100644
--- a/Documentation/i2c/instantiating-devices
+++ b/Documentation/i2c/instantiating-devices
@@ -87,11 +87,11 @@
 changing its design without notice). In this case, you can call
 i2c_new_probed_device() instead of i2c_new_device().
 
-Example (from the pnx4008 OHCI driver):
+Example (from the nxp OHCI driver):
 
 static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
 
-static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
+static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
 {
 	(...)
 	struct i2c_adapter *i2c_adap;
@@ -100,7 +100,7 @@
 	(...)
 	i2c_adap = i2c_get_adapter(2);
 	memset(&i2c_info, 0, sizeof(struct i2c_board_info));
-	strlcpy(i2c_info.type, "isp1301_pnx", I2C_NAME_SIZE);
+	strlcpy(i2c_info.type, "isp1301_nxp", I2C_NAME_SIZE);
 	isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
 						   normal_i2c, NULL);
 	i2c_put_adapter(i2c_adap);
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 4840334..5dbd906 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -189,7 +189,7 @@
 'Y'	all	linux/cyclades.h
 'Z'	14-15	drivers/message/fusion/mptctl.h
 '['	00-07	linux/usb/tmc.h		USB Test and Measurement Devices
-					<mailto:gregkh@suse.de>
+					<mailto:gregkh@linuxfoundation.org>
 'a'	all	linux/atm*.h, linux/sonet.h	ATM on linux
 					<http://lrcwww.epfl.ch/>
 'b'	00-FF				conflict! bit3 vme host bridge
diff --git a/Documentation/ko_KR/HOWTO b/Documentation/ko_KR/HOWTO
index ab5189a..2f48f20 100644
--- a/Documentation/ko_KR/HOWTO
+++ b/Documentation/ko_KR/HOWTO
@@ -354,7 +354,7 @@
     git.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
 
   quilt trees:
-    - USB, PCI, Driver Core, and I2C, Greg Kroah-Hartman < gregkh@suse.de>
+    - USB, PCI, Driver Core, and I2C, Greg Kroah-Hartman < gregkh@linuxfoundation.org>
     kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
     - x86-64, partly i386, Andi Kleen < ak@suse.de>
         ftp.firstfloor.org:/pub/ak/x86_64/quilt/
diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt
index 3ab2472..49578cf 100644
--- a/Documentation/kobject.txt
+++ b/Documentation/kobject.txt
@@ -1,6 +1,6 @@
 Everything you never wanted to know about kobjects, ksets, and ktypes
 
-Greg Kroah-Hartman <gregkh@suse.de>
+Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 
 Based on an original article by Jon Corbet for lwn.net written October 1,
 2003 and located at http://lwn.net/Articles/51437/
diff --git a/Documentation/lockup-watchdogs.txt b/Documentation/lockup-watchdogs.txt
new file mode 100644
index 0000000..d2a3660
--- /dev/null
+++ b/Documentation/lockup-watchdogs.txt
@@ -0,0 +1,63 @@
+===============================================================
+Softlockup detector and hardlockup detector (aka nmi_watchdog)
+===============================================================
+
+The Linux kernel can act as a watchdog to detect both soft and hard
+lockups.
+
+A 'softlockup' is defined as a bug that causes the kernel to loop in
+kernel mode for more than 20 seconds (see "Implementation" below for
+details), without giving other tasks a chance to run. The current
+stack trace is displayed upon detection and, by default, the system
+will stay locked up. Alternatively, the kernel can be configured to
+panic; a sysctl, "kernel.softlockup_panic", a kernel parameter,
+"softlockup_panic" (see "Documentation/kernel-parameters.txt" for
+details), and a compile option, "BOOTPARAM_HARDLOCKUP_PANIC", are
+provided for this.
+
+A 'hardlockup' is defined as a bug that causes the CPU to loop in
+kernel mode for more than 10 seconds (see "Implementation" below for
+details), without letting other interrupts have a chance to run.
+Similarly to the softlockup case, the current stack trace is displayed
+upon detection and the system will stay locked up unless the default
+behavior is changed, which can be done through a compile time knob,
+"BOOTPARAM_HARDLOCKUP_PANIC", and a kernel parameter, "nmi_watchdog"
+(see "Documentation/kernel-parameters.txt" for details).
+
+The panic option can be used in combination with panic_timeout (this
+timeout is set through the confusingly named "kernel.panic" sysctl),
+to cause the system to reboot automatically after a specified amount
+of time.
+
+=== Implementation ===
+
+The soft and hard lockup detectors are built on top of the hrtimer and
+perf subsystems, respectively. A direct consequence of this is that,
+in principle, they should work in any architecture where these
+subsystems are present.
+
+A periodic hrtimer runs to generate interrupts and kick the watchdog
+task. An NMI perf event is generated every "watchdog_thresh"
+(compile-time initialized to 10 and configurable through sysctl of the
+same name) seconds to check for hardlockups. If any CPU in the system
+does not receive any hrtimer interrupt during that time the
+'hardlockup detector' (the handler for the NMI perf event) will
+generate a kernel warning or call panic, depending on the
+configuration.
+
+The watchdog task is a high priority kernel thread that updates a
+timestamp every time it is scheduled. If that timestamp is not updated
+for 2*watchdog_thresh seconds (the softlockup threshold) the
+'softlockup detector' (coded inside the hrtimer callback function)
+will dump useful debug information to the system log, after which it
+will call panic if it was instructed to do so or resume execution of
+other kernel code.
+
+The period of the hrtimer is 2*watchdog_thresh/5, which means it has
+two or three chances to generate an interrupt before the hardlockup
+detector kicks in.
+
+As explained above, a kernel knob is provided that allows
+administrators to configure the period of the hrtimer and the perf
+event. The right value for a particular environment is a trade-off
+between fast response to lockups and detection overhead.
diff --git a/Documentation/nmi_watchdog.txt b/Documentation/nmi_watchdog.txt
deleted file mode 100644
index bf9f80a..0000000
--- a/Documentation/nmi_watchdog.txt
+++ /dev/null
@@ -1,83 +0,0 @@
-
-[NMI watchdog is available for x86 and x86-64 architectures]
-
-Is your system locking up unpredictably? No keyboard activity, just
-a frustrating complete hard lockup? Do you want to help us debugging
-such lockups? If all yes then this document is definitely for you.
-
-On many x86/x86-64 type hardware there is a feature that enables
-us to generate 'watchdog NMI interrupts'.  (NMI: Non Maskable Interrupt
-which get executed even if the system is otherwise locked up hard).
-This can be used to debug hard kernel lockups.  By executing periodic
-NMI interrupts, the kernel can monitor whether any CPU has locked up,
-and print out debugging messages if so.
-
-In order to use the NMI watchdog, you need to have APIC support in your
-kernel. For SMP kernels, APIC support gets compiled in automatically. For
-UP, enable either CONFIG_X86_UP_APIC (Processor type and features -> Local
-APIC support on uniprocessors) or CONFIG_X86_UP_IOAPIC (Processor type and
-features -> IO-APIC support on uniprocessors) in your kernel config.
-CONFIG_X86_UP_APIC is for uniprocessor machines without an IO-APIC.
-CONFIG_X86_UP_IOAPIC is for uniprocessor with an IO-APIC. [Note: certain
-kernel debugging options, such as Kernel Stack Meter or Kernel Tracer,
-may implicitly disable the NMI watchdog.]
-
-For x86-64, the needed APIC is always compiled in.
-
-Using local APIC (nmi_watchdog=2) needs the first performance register, so
-you can't use it for other purposes (such as high precision performance
-profiling.) However, at least oprofile and the perfctr driver disable the
-local APIC NMI watchdog automatically.
-
-To actually enable the NMI watchdog, use the 'nmi_watchdog=N' boot
-parameter.  Eg. the relevant lilo.conf entry:
-
-        append="nmi_watchdog=1"
-
-For SMP machines and UP machines with an IO-APIC use nmi_watchdog=1.
-For UP machines without an IO-APIC use nmi_watchdog=2, this only works
-for some processor types.  If in doubt, boot with nmi_watchdog=1 and
-check the NMI count in /proc/interrupts; if the count is zero then
-reboot with nmi_watchdog=2 and check the NMI count.  If it is still
-zero then log a problem, you probably have a processor that needs to be
-added to the nmi code.
-
-A 'lockup' is the following scenario: if any CPU in the system does not
-execute the period local timer interrupt for more than 5 seconds, then
-the NMI handler generates an oops and kills the process. This
-'controlled crash' (and the resulting kernel messages) can be used to
-debug the lockup. Thus whenever the lockup happens, wait 5 seconds and
-the oops will show up automatically. If the kernel produces no messages
-then the system has crashed so hard (eg. hardware-wise) that either it
-cannot even accept NMI interrupts, or the crash has made the kernel
-unable to print messages.
-
-Be aware that when using local APIC, the frequency of NMI interrupts
-it generates, depends on the system load. The local APIC NMI watchdog,
-lacking a better source, uses the "cycles unhalted" event. As you may
-guess it doesn't tick when the CPU is in the halted state (which happens
-when the system is idle), but if your system locks up on anything but the
-"hlt" processor instruction, the watchdog will trigger very soon as the
-"cycles unhalted" event will happen every clock tick. If it locks up on
-"hlt", then you are out of luck -- the event will not happen at all and the
-watchdog won't trigger. This is a shortcoming of the local APIC watchdog
--- unfortunately there is no "clock ticks" event that would work all the
-time. The I/O APIC watchdog is driven externally and has no such shortcoming.
-But its NMI frequency is much higher, resulting in a more significant hit
-to the overall system performance.
-
-On x86 nmi_watchdog is disabled by default so you have to enable it with
-a boot time parameter.
-
-It's possible to disable the NMI watchdog in run-time by writing "0" to
-/proc/sys/kernel/nmi_watchdog. Writing "1" to the same file will re-enable
-the NMI watchdog. Notice that you still need to use "nmi_watchdog=" parameter
-at boot time.
-
-NOTE: In kernels prior to 2.4.2-ac18 the NMI-oopser is enabled unconditionally
-on x86 SMP boxes.
-
-[ feel free to send bug reports, suggestions and patches to
-  Ingo Molnar <mingo@redhat.com> or the Linux SMP mailing
-  list at <linux-smp@vger.kernel.org> ]
-
diff --git a/Documentation/scheduler/sched-stats.txt b/Documentation/scheduler/sched-stats.txt
index 1cd5d51..8259b34 100644
--- a/Documentation/scheduler/sched-stats.txt
+++ b/Documentation/scheduler/sched-stats.txt
@@ -38,7 +38,8 @@
      1) # of times sched_yield() was called
 
 Next three are schedule() statistics:
-     2) # of times we switched to the expired queue and reused it
+     2) This field is a legacy array expiration count field used in the O(1)
+	scheduler. We kept it for ABI compatibility, but it is always set to zero.
      3) # of times schedule() was called
      4) # of times schedule() left the processor idle
 
diff --git a/Documentation/static-keys.txt b/Documentation/static-keys.txt
new file mode 100644
index 0000000..d93f3c0
--- /dev/null
+++ b/Documentation/static-keys.txt
@@ -0,0 +1,286 @@
+			Static Keys
+			-----------
+
+By: Jason Baron <jbaron@redhat.com>
+
+0) Abstract
+
+Static keys allows the inclusion of seldom used features in
+performance-sensitive fast-path kernel code, via a GCC feature and a code
+patching technique. A quick example:
+
+	struct static_key key = STATIC_KEY_INIT_FALSE;
+
+	...
+
+        if (static_key_false(&key))
+                do unlikely code
+        else
+                do likely code
+
+	...
+	static_key_slow_inc();
+	...
+	static_key_slow_inc();
+	...
+
+The static_key_false() branch will be generated into the code with as little
+impact to the likely code path as possible.
+
+
+1) Motivation
+
+
+Currently, tracepoints are implemented using a conditional branch. The
+conditional check requires checking a global variable for each tracepoint.
+Although the overhead of this check is small, it increases when the memory
+cache comes under pressure (memory cache lines for these global variables may
+be shared with other memory accesses). As we increase the number of tracepoints
+in the kernel this overhead may become more of an issue. In addition,
+tracepoints are often dormant (disabled) and provide no direct kernel
+functionality. Thus, it is highly desirable to reduce their impact as much as
+possible. Although tracepoints are the original motivation for this work, other
+kernel code paths should be able to make use of the static keys facility.
+
+
+2) Solution
+
+
+gcc (v4.5) adds a new 'asm goto' statement that allows branching to a label:
+
+http://gcc.gnu.org/ml/gcc-patches/2009-07/msg01556.html
+
+Using the 'asm goto', we can create branches that are either taken or not taken
+by default, without the need to check memory. Then, at run-time, we can patch
+the branch site to change the branch direction.
+
+For example, if we have a simple branch that is disabled by default:
+
+	if (static_key_false(&key))
+		printk("I am the true branch\n");
+
+Thus, by default the 'printk' will not be emitted. And the code generated will
+consist of a single atomic 'no-op' instruction (5 bytes on x86), in the
+straight-line code path. When the branch is 'flipped', we will patch the
+'no-op' in the straight-line codepath with a 'jump' instruction to the
+out-of-line true branch. Thus, changing branch direction is expensive but
+branch selection is basically 'free'. That is the basic tradeoff of this
+optimization.
+
+This lowlevel patching mechanism is called 'jump label patching', and it gives
+the basis for the static keys facility.
+
+3) Static key label API, usage and examples:
+
+
+In order to make use of this optimization you must first define a key:
+
+	struct static_key key;
+
+Which is initialized as:
+
+	struct static_key key = STATIC_KEY_INIT_TRUE;
+
+or:
+
+	struct static_key key = STATIC_KEY_INIT_FALSE;
+
+If the key is not initialized, it is default false. The 'struct static_key',
+must be a 'global'. That is, it can't be allocated on the stack or dynamically
+allocated at run-time.
+
+The key is then used in code as:
+
+        if (static_key_false(&key))
+                do unlikely code
+        else
+                do likely code
+
+Or:
+
+        if (static_key_true(&key))
+                do likely code
+        else
+                do unlikely code
+
+A key that is initialized via 'STATIC_KEY_INIT_FALSE', must be used in a
+'static_key_false()' construct. Likewise, a key initialized via
+'STATIC_KEY_INIT_TRUE' must be used in a 'static_key_true()' construct. A
+single key can be used in many branches, but all the branches must match the
+way that the key has been initialized.
+
+The branch(es) can then be switched via:
+
+	static_key_slow_inc(&key);
+	...
+	static_key_slow_dec(&key);
+
+Thus, 'static_key_slow_inc()' means 'make the branch true', and
+'static_key_slow_dec()' means 'make the the branch false' with appropriate
+reference counting. For example, if the key is initialized true, a
+static_key_slow_dec(), will switch the branch to false. And a subsequent
+static_key_slow_inc(), will change the branch back to true. Likewise, if the
+key is initialized false, a 'static_key_slow_inc()', will change the branch to
+true. And then a 'static_key_slow_dec()', will again make the branch false.
+
+An example usage in the kernel is the implementation of tracepoints:
+
+        static inline void trace_##name(proto)                          \
+        {                                                               \
+                if (static_key_false(&__tracepoint_##name.key))		\
+                        __DO_TRACE(&__tracepoint_##name,                \
+                                TP_PROTO(data_proto),                   \
+                                TP_ARGS(data_args),                     \
+                                TP_CONDITION(cond));                    \
+        }
+
+Tracepoints are disabled by default, and can be placed in performance critical
+pieces of the kernel. Thus, by using a static key, the tracepoints can have
+absolutely minimal impact when not in use.
+
+
+4) Architecture level code patching interface, 'jump labels'
+
+
+There are a few functions and macros that architectures must implement in order
+to take advantage of this optimization. If there is no architecture support, we
+simply fall back to a traditional, load, test, and jump sequence.
+
+* select HAVE_ARCH_JUMP_LABEL, see: arch/x86/Kconfig
+
+* #define JUMP_LABEL_NOP_SIZE, see: arch/x86/include/asm/jump_label.h
+
+* __always_inline bool arch_static_branch(struct static_key *key), see:
+					arch/x86/include/asm/jump_label.h
+
+* void arch_jump_label_transform(struct jump_entry *entry, enum jump_label_type type),
+					see: arch/x86/kernel/jump_label.c
+
+* __init_or_module void arch_jump_label_transform_static(struct jump_entry *entry, enum jump_label_type type),
+					see: arch/x86/kernel/jump_label.c
+
+
+* struct jump_entry, see: arch/x86/include/asm/jump_label.h
+
+
+5) Static keys / jump label analysis, results (x86_64):
+
+
+As an example, let's add the following branch to 'getppid()', such that the
+system call now looks like:
+
+SYSCALL_DEFINE0(getppid)
+{
+        int pid;
+
++       if (static_key_false(&key))
++               printk("I am the true branch\n");
+
+        rcu_read_lock();
+        pid = task_tgid_vnr(rcu_dereference(current->real_parent));
+        rcu_read_unlock();
+
+        return pid;
+}
+
+The resulting instructions with jump labels generated by GCC is:
+
+ffffffff81044290 <sys_getppid>:
+ffffffff81044290:       55                      push   %rbp
+ffffffff81044291:       48 89 e5                mov    %rsp,%rbp
+ffffffff81044294:       e9 00 00 00 00          jmpq   ffffffff81044299 <sys_getppid+0x9>
+ffffffff81044299:       65 48 8b 04 25 c0 b6    mov    %gs:0xb6c0,%rax
+ffffffff810442a0:       00 00
+ffffffff810442a2:       48 8b 80 80 02 00 00    mov    0x280(%rax),%rax
+ffffffff810442a9:       48 8b 80 b0 02 00 00    mov    0x2b0(%rax),%rax
+ffffffff810442b0:       48 8b b8 e8 02 00 00    mov    0x2e8(%rax),%rdi
+ffffffff810442b7:       e8 f4 d9 00 00          callq  ffffffff81051cb0 <pid_vnr>
+ffffffff810442bc:       5d                      pop    %rbp
+ffffffff810442bd:       48 98                   cltq
+ffffffff810442bf:       c3                      retq
+ffffffff810442c0:       48 c7 c7 e3 54 98 81    mov    $0xffffffff819854e3,%rdi
+ffffffff810442c7:       31 c0                   xor    %eax,%eax
+ffffffff810442c9:       e8 71 13 6d 00          callq  ffffffff8171563f <printk>
+ffffffff810442ce:       eb c9                   jmp    ffffffff81044299 <sys_getppid+0x9>
+
+Without the jump label optimization it looks like:
+
+ffffffff810441f0 <sys_getppid>:
+ffffffff810441f0:       8b 05 8a 52 d8 00       mov    0xd8528a(%rip),%eax        # ffffffff81dc9480 <key>
+ffffffff810441f6:       55                      push   %rbp
+ffffffff810441f7:       48 89 e5                mov    %rsp,%rbp
+ffffffff810441fa:       85 c0                   test   %eax,%eax
+ffffffff810441fc:       75 27                   jne    ffffffff81044225 <sys_getppid+0x35>
+ffffffff810441fe:       65 48 8b 04 25 c0 b6    mov    %gs:0xb6c0,%rax
+ffffffff81044205:       00 00
+ffffffff81044207:       48 8b 80 80 02 00 00    mov    0x280(%rax),%rax
+ffffffff8104420e:       48 8b 80 b0 02 00 00    mov    0x2b0(%rax),%rax
+ffffffff81044215:       48 8b b8 e8 02 00 00    mov    0x2e8(%rax),%rdi
+ffffffff8104421c:       e8 2f da 00 00          callq  ffffffff81051c50 <pid_vnr>
+ffffffff81044221:       5d                      pop    %rbp
+ffffffff81044222:       48 98                   cltq
+ffffffff81044224:       c3                      retq
+ffffffff81044225:       48 c7 c7 13 53 98 81    mov    $0xffffffff81985313,%rdi
+ffffffff8104422c:       31 c0                   xor    %eax,%eax
+ffffffff8104422e:       e8 60 0f 6d 00          callq  ffffffff81715193 <printk>
+ffffffff81044233:       eb c9                   jmp    ffffffff810441fe <sys_getppid+0xe>
+ffffffff81044235:       66 66 2e 0f 1f 84 00    data32 nopw %cs:0x0(%rax,%rax,1)
+ffffffff8104423c:       00 00 00 00
+
+Thus, the disable jump label case adds a 'mov', 'test' and 'jne' instruction
+vs. the jump label case just has a 'no-op' or 'jmp 0'. (The jmp 0, is patched
+to a 5 byte atomic no-op instruction at boot-time.) Thus, the disabled jump
+label case adds:
+
+6 (mov) + 2 (test) + 2 (jne) = 10 - 5 (5 byte jump 0) = 5 addition bytes.
+
+If we then include the padding bytes, the jump label code saves, 16 total bytes
+of instruction memory for this small fucntion. In this case the non-jump label
+function is 80 bytes long. Thus, we have have saved 20% of the instruction
+footprint. We can in fact improve this even further, since the 5-byte no-op
+really can be a 2-byte no-op since we can reach the branch with a 2-byte jmp.
+However, we have not yet implemented optimal no-op sizes (they are currently
+hard-coded).
+
+Since there are a number of static key API uses in the scheduler paths,
+'pipe-test' (also known as 'perf bench sched pipe') can be used to show the
+performance improvement. Testing done on 3.3.0-rc2:
+
+jump label disabled:
+
+ Performance counter stats for 'bash -c /tmp/pipe-test' (50 runs):
+
+        855.700314 task-clock                #    0.534 CPUs utilized            ( +-  0.11% )
+           200,003 context-switches          #    0.234 M/sec                    ( +-  0.00% )
+                 0 CPU-migrations            #    0.000 M/sec                    ( +- 39.58% )
+               487 page-faults               #    0.001 M/sec                    ( +-  0.02% )
+     1,474,374,262 cycles                    #    1.723 GHz                      ( +-  0.17% )
+   <not supported> stalled-cycles-frontend
+   <not supported> stalled-cycles-backend
+     1,178,049,567 instructions              #    0.80  insns per cycle          ( +-  0.06% )
+       208,368,926 branches                  #  243.507 M/sec                    ( +-  0.06% )
+         5,569,188 branch-misses             #    2.67% of all branches          ( +-  0.54% )
+
+       1.601607384 seconds time elapsed                                          ( +-  0.07% )
+
+jump label enabled:
+
+ Performance counter stats for 'bash -c /tmp/pipe-test' (50 runs):
+
+        841.043185 task-clock                #    0.533 CPUs utilized            ( +-  0.12% )
+           200,004 context-switches          #    0.238 M/sec                    ( +-  0.00% )
+                 0 CPU-migrations            #    0.000 M/sec                    ( +- 40.87% )
+               487 page-faults               #    0.001 M/sec                    ( +-  0.05% )
+     1,432,559,428 cycles                    #    1.703 GHz                      ( +-  0.18% )
+   <not supported> stalled-cycles-frontend
+   <not supported> stalled-cycles-backend
+     1,175,363,994 instructions              #    0.82  insns per cycle          ( +-  0.04% )
+       206,859,359 branches                  #  245.956 M/sec                    ( +-  0.04% )
+         4,884,119 branch-misses             #    2.36% of all branches          ( +-  0.85% )
+
+       1.579384366 seconds time elapsed
+
+The percentage of saved branches is .7%, and we've saved 12% on
+'branch-misses'. This is where we would expect to get the most savings, since
+this optimization is about reducing the number of branches. In addition, we've
+saved .2% on instructions, and 2.8% on cycles and 1.4% on elapsed time.
diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt
index 1ebc24c..6f51fed 100644
--- a/Documentation/trace/ftrace.txt
+++ b/Documentation/trace/ftrace.txt
@@ -226,6 +226,13 @@
 	Traces and records the max latency that it takes for
 	the highest priority task to get scheduled after
 	it has been woken up.
+        Traces all tasks as an average developer would expect.
+
+  "wakeup_rt"
+
+        Traces and records the max latency that it takes for just
+        RT tasks (as the current "wakeup" does). This is useful
+        for those interested in wake up timings of RT tasks.
 
   "hw-branch-tracer"
 
diff --git a/Documentation/zh_CN/HOWTO b/Documentation/zh_CN/HOWTO
index faf976c..7fba5aa 100644
--- a/Documentation/zh_CN/HOWTO
+++ b/Documentation/zh_CN/HOWTO
@@ -316,7 +316,7 @@
 	git.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
 
   使用quilt管理的补丁集:
-    - USB, PCI, 驱动程序核心和I2C, Greg Kroah-Hartman <gregkh@suse.de>
+    - USB, PCI, 驱动程序核心和I2C, Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 	kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
     - x86-64, 部分i386, Andi Kleen <ak@suse.de>
 	ftp.firstfloor.org:/pub/ak/x86_64/quilt/
diff --git a/MAINTAINERS b/MAINTAINERS
index 3321d75..5ac456e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1513,19 +1513,23 @@
 
 BLUETOOTH DRIVERS
 M:	Marcel Holtmann <marcel@holtmann.org>
-M:	"Gustavo F. Padovan" <padovan@profusion.mobi>
+M:	Gustavo Padovan <gustavo@padovan.org>
+M:	Johan Hedberg <johan.hedberg@gmail.com>
 L:	linux-bluetooth@vger.kernel.org
 W:	http://www.bluez.org/
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jh/bluetooth.git
 S:	Maintained
 F:	drivers/bluetooth/
 
 BLUETOOTH SUBSYSTEM
 M:	Marcel Holtmann <marcel@holtmann.org>
-M:	"Gustavo F. Padovan" <padovan@profusion.mobi>
+M:	Gustavo Padovan <gustavo@padovan.org>
+M:	Johan Hedberg <johan.hedberg@gmail.com>
 L:	linux-bluetooth@vger.kernel.org
 W:	http://www.bluez.org/
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jh/bluetooth.git
 S:	Maintained
 F:	net/bluetooth/
 F:	include/net/bluetooth/
@@ -1717,6 +1721,14 @@
 F:	include/linux/can/netlink.h
 F:	include/linux/can/platform/
 
+CAPABILITIES
+M:	Serge Hallyn <serge.hallyn@canonical.com>
+L:	linux-security-module@vger.kernel.org
+S:	Supported	
+F:	include/linux/capability.h
+F:	security/capability.c
+F:	security/commoncap.c 
+
 CELL BROADBAND ENGINE ARCHITECTURE
 M:	Arnd Bergmann <arnd@arndb.de>
 L:	linuxppc-dev@lists.ozlabs.org
@@ -2351,6 +2363,15 @@
 F:	drivers/gpu/drm/exynos
 F:	include/drm/exynos*
 
+EXYNOS MIPI DISPLAY DRIVERS
+M:	Inki Dae <inki.dae@samsung.com>
+M:	Donghwa Lee <dh09.lee@samsung.com>
+M:	Kyungmin Park <kyungmin.park@samsung.com>
+L:	linux-fbdev@vger.kernel.org
+S:	Maintained
+F:	drivers/video/exynos/exynos_mipi*
+F:	include/video/exynos_mipi*
+
 DSCC4 DRIVER
 M:	Francois Romieu <romieu@fr.zoreil.com>
 L:	netdev@vger.kernel.org
@@ -2845,6 +2866,12 @@
 F:	drivers/media/video/m5mols/
 F:	include/media/m5mols.h
 
+FUJITSU TABLET EXTRAS
+M:	Robert Gerlach <khnz@gmx.de>
+L:	platform-driver-x86@vger.kernel.org
+S:	Maintained
+F:	drivers/platform/x86/fujitsu-tablet.c
+
 FUSE: FILESYSTEM IN USERSPACE
 M:	Miklos Szeredi <miklos@szeredi.hu>
 L:	fuse-devel@lists.sourceforge.net
@@ -5853,6 +5880,7 @@
 
 SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) ST SPEAR DRIVER
 M:	Viresh Kumar <viresh.kumar@st.com>
+L:	spear-devel@list.st.com
 L:	linux-mmc@vger.kernel.org
 S:	Maintained
 F:	drivers/mmc/host/sdhci-spear.c
@@ -6184,8 +6212,8 @@
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6.git
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git
 S:	Maintained
+F:	include/linux/sunserialcore.h
 F:	drivers/tty/serial/suncore.c
-F:	drivers/tty/serial/suncore.h
 F:	drivers/tty/serial/sunhv.c
 F:	drivers/tty/serial/sunsab.c
 F:	drivers/tty/serial/sunsab.h
@@ -6195,24 +6223,32 @@
 
 SPEAR PLATFORM SUPPORT
 M:	Viresh Kumar <viresh.kumar@st.com>
+L:	spear-devel@list.st.com
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:	http://www.st.com/spear
 S:	Maintained
 F:	arch/arm/plat-spear/
 
 SPEAR3XX MACHINE SUPPORT
 M:	Viresh Kumar <viresh.kumar@st.com>
+L:	spear-devel@list.st.com
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:	http://www.st.com/spear
 S:	Maintained
 F:	arch/arm/mach-spear3xx/
 
 SPEAR6XX MACHINE SUPPORT
 M:	Rajeev Kumar <rajeev-dlh.kumar@st.com>
+L:	spear-devel@list.st.com
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:	http://www.st.com/spear
 S:	Maintained
 F:	arch/arm/mach-spear6xx/
 
 SPEAR CLOCK FRAMEWORK SUPPORT
 M:	Viresh Kumar <viresh.kumar@st.com>
+L:	spear-devel@list.st.com
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:	http://www.st.com/spear
 S:	Maintained
 F:	arch/arm/mach-spear*/clock.c
@@ -6221,6 +6257,8 @@
 
 SPEAR PAD MULTIPLEXING SUPPORT
 M:	Viresh Kumar <viresh.kumar@st.com>
+L:	spear-devel@list.st.com
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:	http://www.st.com/spear
 S:	Maintained
 F:	arch/arm/plat-spear/include/plat/padmux.h
@@ -6357,6 +6395,11 @@
 S:	Odd Fixes
 F:	drivers/staging/olpc_dcon/
 
+STAGING - OZMO DEVICES USB OVER WIFI DRIVER
+M:	Chris Kelly <ckelly@ozmodevices.com>
+S:	Maintained
+F:	drivers/staging/ozwpan/
+
 STAGING - PARALLEL LCD/KEYPAD PANEL DRIVER
 M:	Willy Tarreau <willy@meta-x.org>
 S:	Odd Fixes
diff --git a/Makefile b/Makefile
index 56d4817..1932984 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 3
 SUBLEVEL = 0
-EXTRAVERSION = -rc7
+EXTRAVERSION =
 NAME = Saber-toothed Squirrel
 
 # *DOCUMENTATION*
diff --git a/arch/Kconfig b/arch/Kconfig
index 4f55c73..5b448a7 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -47,18 +47,29 @@
 	  If in doubt, say "N".
 
 config JUMP_LABEL
-       bool "Optimize trace point call sites"
+       bool "Optimize very unlikely/likely branches"
        depends on HAVE_ARCH_JUMP_LABEL
        help
-         If it is detected that the compiler has support for "asm goto",
-	 the kernel will compile trace point locations with just a
-	 nop instruction. When trace points are enabled, the nop will
-	 be converted to a jump to the trace function. This technique
-	 lowers overhead and stress on the branch prediction of the
-	 processor.
+         This option enables a transparent branch optimization that
+	 makes certain almost-always-true or almost-always-false branch
+	 conditions even cheaper to execute within the kernel.
 
-	 On i386, options added to the compiler flags may increase
-	 the size of the kernel slightly.
+	 Certain performance-sensitive kernel code, such as trace points,
+	 scheduler functionality, networking code and KVM have such
+	 branches and include support for this optimization technique.
+
+         If it is detected that the compiler has support for "asm goto",
+	 the kernel will compile such branches with just a nop
+	 instruction. When the condition flag is toggled to true, the
+	 nop will be converted to a jump instruction to execute the
+	 conditional block of instructions.
+
+	 This technique lowers overhead and stress on the branch prediction
+	 of the processor and generally makes the kernel faster. The update
+	 of the condition is slower, but those are always very rare.
+
+	 ( On 32-bit x86, the necessary options added to the compiler
+	   flags may increase the size of the kernel slightly. )
 
 config OPTPROBES
 	def_bool y
diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c
index 8143cd7..0dae252 100644
--- a/arch/alpha/kernel/perf_event.c
+++ b/arch/alpha/kernel/perf_event.c
@@ -685,6 +685,10 @@
 {
 	int err;
 
+	/* does not support taken branch sampling */
+	if (has_branch_stack(event))
+		return -EOPNOTSUPP;
+
 	switch (event->attr.type) {
 	case PERF_TYPE_RAW:
 	case PERF_TYPE_HARDWARE:
diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c
index 783f4e5..3ea8094 100644
--- a/arch/alpha/kernel/srmcons.c
+++ b/arch/alpha/kernel/srmcons.c
@@ -30,10 +30,9 @@
 #define MAX_SRM_CONSOLE_DEVICES 1	/* only support 1 console device */
 
 struct srmcons_private {
-	struct tty_struct *tty;
+	struct tty_port port;
 	struct timer_list timer;
-	spinlock_t lock;
-};
+} srmcons_singleton;
 
 typedef union _srmcons_result {
 	struct {
@@ -68,22 +67,21 @@
 srmcons_receive_chars(unsigned long data)
 {
 	struct srmcons_private *srmconsp = (struct srmcons_private *)data;
+	struct tty_port *port = &srmconsp->port;
 	unsigned long flags;
 	int incr = 10;
 
 	local_irq_save(flags);
 	if (spin_trylock(&srmcons_callback_lock)) {
-		if (!srmcons_do_receive_chars(srmconsp->tty))
+		if (!srmcons_do_receive_chars(port->tty))
 			incr = 100;
 		spin_unlock(&srmcons_callback_lock);
 	} 
 
-	spin_lock(&srmconsp->lock);
-	if (srmconsp->tty) {
-		srmconsp->timer.expires = jiffies + incr;
-		add_timer(&srmconsp->timer);
-	}
-	spin_unlock(&srmconsp->lock);
+	spin_lock(&port->lock);
+	if (port->tty)
+		mod_timer(&srmconsp->timer, jiffies + incr);
+	spin_unlock(&port->lock);
 
 	local_irq_restore(flags);
 }
@@ -156,56 +154,22 @@
 }
 
 static int
-srmcons_get_private_struct(struct srmcons_private **ps)
-{
-	static struct srmcons_private *srmconsp = NULL;
-	static DEFINE_SPINLOCK(srmconsp_lock);
-	unsigned long flags;
-	int retval = 0;
-
-	if (srmconsp == NULL) {
-		srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL);
-		spin_lock_irqsave(&srmconsp_lock, flags);
-
-		if (srmconsp == NULL)
-			retval = -ENOMEM;
-		else {
-			srmconsp->tty = NULL;
-			spin_lock_init(&srmconsp->lock);
-			init_timer(&srmconsp->timer);
-		}
-
-		spin_unlock_irqrestore(&srmconsp_lock, flags);
-	}
-
-	*ps = srmconsp;
-	return retval;
-}
-
-static int
 srmcons_open(struct tty_struct *tty, struct file *filp)
 {
-	struct srmcons_private *srmconsp;
+	struct srmcons_private *srmconsp = &srmcons_singleton;
+	struct tty_port *port = &srmconsp->port;
 	unsigned long flags;
-	int retval;
 
-	retval = srmcons_get_private_struct(&srmconsp);
-	if (retval)
-		return retval;
+	spin_lock_irqsave(&port->lock, flags);
 
-	spin_lock_irqsave(&srmconsp->lock, flags);
-
-	if (!srmconsp->tty) {
+	if (!port->tty) {
 		tty->driver_data = srmconsp;
-
-		srmconsp->tty = tty;
-		srmconsp->timer.function = srmcons_receive_chars;
-		srmconsp->timer.data = (unsigned long)srmconsp;
-		srmconsp->timer.expires = jiffies + 10;
-		add_timer(&srmconsp->timer);
+		tty->port = port;
+		port->tty = tty; /* XXX proper refcounting */
+		mod_timer(&srmconsp->timer, jiffies + 10);
 	}
 
-	spin_unlock_irqrestore(&srmconsp->lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
 
 	return 0;
 }
@@ -214,16 +178,17 @@
 srmcons_close(struct tty_struct *tty, struct file *filp)
 {
 	struct srmcons_private *srmconsp = tty->driver_data;
+	struct tty_port *port = &srmconsp->port;
 	unsigned long flags;
 
-	spin_lock_irqsave(&srmconsp->lock, flags);
+	spin_lock_irqsave(&port->lock, flags);
 
 	if (tty->count == 1) {
-		srmconsp->tty = NULL;
+		port->tty = NULL;
 		del_timer(&srmconsp->timer);
 	}
 
-	spin_unlock_irqrestore(&srmconsp->lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
 }
 
 
@@ -240,6 +205,9 @@
 static int __init
 srmcons_init(void)
 {
+	tty_port_init(&srmcons_singleton.port);
+	setup_timer(&srmcons_singleton.timer, srmcons_receive_chars,
+			(unsigned long)&srmcons_singleton);
 	if (srm_is_registered_console) {
 		struct tty_driver *driver;
 		int err;
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
index 99cfe36..7523340 100644
--- a/arch/arm/include/asm/perf_event.h
+++ b/arch/arm/include/asm/perf_event.h
@@ -12,10 +12,6 @@
 #ifndef __ARM_PERF_EVENT_H__
 #define __ARM_PERF_EVENT_H__
 
-/* ARM performance counters start from 1 (in the cp15 accesses) so use the
- * same indexes here for consistency. */
-#define PERF_EVENT_INDEX_OFFSET 1
-
 /* ARM perf PMU IDs for use by internal perf clients. */
 enum arm_perf_pmu_ids {
 	ARM_PERF_PMU_ID_XSCALE1	= 0,
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index b2abfa1..8a89d3b 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -539,6 +539,10 @@
 	int err = 0;
 	atomic_t *active_events = &armpmu->active_events;
 
+	/* does not support taken branch sampling */
+	if (has_branch_stack(event))
+		return -EOPNOTSUPP;
+
 	if (armpmu->map_event(event) == -ENOENT)
 		return -ENOENT;
 
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 971d65c..c2ae3cd 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -239,9 +239,7 @@
 		leds_event(led_idle_end);
 		rcu_idle_exit();
 		tick_nohz_idle_exit();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index cdeb727..d616ed5 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -295,13 +295,6 @@
 	 */
 	percpu_timer_setup();
 
-	while (!cpu_active(cpu))
-		cpu_relax();
-
-	/*
-	 * cpu_active bit is set, so it's safe to enalbe interrupts
-	 * now.
-	 */
 	local_irq_enable();
 	local_fiq_enable();
 
diff --git a/arch/arm/mach-imx/mx31moboard-devboard.c b/arch/arm/mach-imx/mx31moboard-devboard.c
index 0aa2536..cc285e5 100644
--- a/arch/arm/mach-imx/mx31moboard-devboard.c
+++ b/arch/arm/mach-imx/mx31moboard-devboard.c
@@ -158,7 +158,7 @@
 #define USBH1_VBUSEN_B	IOMUX_TO_GPIO(MX31_PIN_NFRE_B)
 #define USBH1_MODE	IOMUX_TO_GPIO(MX31_PIN_NFALE)
 
-static int devboard_isp1105_init(struct otg_transceiver *otg)
+static int devboard_isp1105_init(struct usb_phy *otg)
 {
 	int ret = gpio_request(USBH1_MODE, "usbh1-mode");
 	if (ret)
@@ -177,7 +177,7 @@
 }
 
 
-static int devboard_isp1105_set_vbus(struct otg_transceiver *otg, bool on)
+static int devboard_isp1105_set_vbus(struct usb_otg *otg, bool on)
 {
 	if (on)
 		gpio_set_value(USBH1_VBUSEN_B, 0);
@@ -194,18 +194,24 @@
 
 static int __init devboard_usbh1_init(void)
 {
-	struct otg_transceiver *otg;
+	struct usb_phy *phy;
 	struct platform_device *pdev;
 
-	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
-	if (!otg)
+	phy = kzalloc(sizeof(*phy), GFP_KERNEL);
+	if (!phy)
 		return -ENOMEM;
 
-	otg->label	= "ISP1105";
-	otg->init	= devboard_isp1105_init;
-	otg->set_vbus	= devboard_isp1105_set_vbus;
+	phy->otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
+	if (!phy->otg) {
+		kfree(phy);
+		return -ENOMEM;
+	}
 
-	usbh1_pdata.otg = otg;
+	phy->label	= "ISP1105";
+	phy->init	= devboard_isp1105_init;
+	phy->otg->set_vbus	= devboard_isp1105_set_vbus;
+
+	usbh1_pdata.otg = phy;
 
 	pdev = imx31_add_mxc_ehci_hs(1, &usbh1_pdata);
 	if (IS_ERR(pdev))
diff --git a/arch/arm/mach-imx/mx31moboard-marxbot.c b/arch/arm/mach-imx/mx31moboard-marxbot.c
index bb639cb..135c90e 100644
--- a/arch/arm/mach-imx/mx31moboard-marxbot.c
+++ b/arch/arm/mach-imx/mx31moboard-marxbot.c
@@ -272,7 +272,7 @@
 #define USBH1_VBUSEN_B	IOMUX_TO_GPIO(MX31_PIN_NFRE_B)
 #define USBH1_MODE	IOMUX_TO_GPIO(MX31_PIN_NFALE)
 
-static int marxbot_isp1105_init(struct otg_transceiver *otg)
+static int marxbot_isp1105_init(struct usb_phy *otg)
 {
 	int ret = gpio_request(USBH1_MODE, "usbh1-mode");
 	if (ret)
@@ -291,7 +291,7 @@
 }
 
 
-static int marxbot_isp1105_set_vbus(struct otg_transceiver *otg, bool on)
+static int marxbot_isp1105_set_vbus(struct usb_otg *otg, bool on)
 {
 	if (on)
 		gpio_set_value(USBH1_VBUSEN_B, 0);
@@ -308,18 +308,24 @@
 
 static int __init marxbot_usbh1_init(void)
 {
-	struct otg_transceiver *otg;
+	struct usb_phy *phy;
 	struct platform_device *pdev;
 
-	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
-	if (!otg)
+	phy = kzalloc(sizeof(*phy), GFP_KERNEL);
+	if (!phy)
 		return -ENOMEM;
 
-	otg->label	= "ISP1105";
-	otg->init	= marxbot_isp1105_init;
-	otg->set_vbus	= marxbot_isp1105_set_vbus;
+	phy->otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
+	if (!phy->otg) {
+		kfree(phy);
+		return -ENOMEM;
+	}
 
-	usbh1_pdata.otg = otg;
+	phy->label	= "ISP1105";
+	phy->init	= marxbot_isp1105_init;
+	phy->otg->set_vbus	= marxbot_isp1105_set_vbus;
+
+	usbh1_pdata.otg = phy;
 
 	pdev = imx31_add_mxc_ehci_hs(1, &usbh1_pdata);
 	if (IS_ERR(pdev))
diff --git a/arch/arm/mach-pxa/pxa3xx-ulpi.c b/arch/arm/mach-pxa/pxa3xx-ulpi.c
index e28dfb8..5ead6d4 100644
--- a/arch/arm/mach-pxa/pxa3xx-ulpi.c
+++ b/arch/arm/mach-pxa/pxa3xx-ulpi.c
@@ -33,7 +33,7 @@
 	struct clk		*clk;
 	void __iomem		*mmio_base;
 
-	struct otg_transceiver	*otg;
+	struct usb_phy		*otg;
 	unsigned int		ulpi_mode;
 };
 
@@ -79,7 +79,7 @@
 	return -ETIMEDOUT;
 }
 
-static int pxa310_ulpi_read(struct otg_transceiver *otg, u32 reg)
+static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg)
 {
 	int err;
 
@@ -98,7 +98,7 @@
 	return u2d_readl(U2DOTGUCR) & U2DOTGUCR_RDATA;
 }
 
-static int pxa310_ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
+static int pxa310_ulpi_write(struct usb_phy *otg, u32 val, u32 reg)
 {
 	if (pxa310_ulpi_get_phymode() != SYNCH) {
 		pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
@@ -111,7 +111,7 @@
 	return pxa310_ulpi_poll();
 }
 
-struct otg_io_access_ops pxa310_ulpi_access_ops = {
+struct usb_phy_io_ops pxa310_ulpi_access_ops = {
 	.read	= pxa310_ulpi_read,
 	.write	= pxa310_ulpi_write,
 };
@@ -139,19 +139,19 @@
 
 	pxa310_otg_transceiver_rtsm();
 
-	err = otg_init(u2d->otg);
+	err = usb_phy_init(u2d->otg);
 	if (err) {
 		pr_err("OTG transceiver init failed");
 		return err;
 	}
 
-	err = otg_set_vbus(u2d->otg, 1);
+	err = otg_set_vbus(u2d->otg->otg, 1);
 	if (err) {
 		pr_err("OTG transceiver VBUS set failed");
 		return err;
 	}
 
-	err = otg_set_host(u2d->otg, host);
+	err = otg_set_host(u2d->otg->otg, host);
 	if (err)
 		pr_err("OTG transceiver Host mode set failed");
 
@@ -189,9 +189,9 @@
 {
 	pxa310_otg_transceiver_rtsm();
 
-	otg_set_host(u2d->otg, NULL);
-	otg_set_vbus(u2d->otg, 0);
-	otg_shutdown(u2d->otg);
+	otg_set_host(u2d->otg->otg, NULL);
+	otg_set_vbus(u2d->otg->otg, 0);
+	usb_phy_shutdown(u2d->otg);
 }
 
 static void pxa310_u2d_setup_otg_hc(void)
diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c
index 068b754..8aea3a2 100644
--- a/arch/arm/mach-shmobile/board-ag5evm.c
+++ b/arch/arm/mach-shmobile/board-ag5evm.c
@@ -38,6 +38,7 @@
 #include <linux/mmc/sh_mobile_sdhi.h>
 #include <linux/mfd/tmio.h>
 #include <linux/sh_clk.h>
+#include <linux/videodev2.h>
 #include <video/sh_mobile_lcdc.h>
 #include <video/sh_mipi_dsi.h>
 #include <sound/sh_fsi.h>
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index eeb4d96..b4718b0 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -794,7 +794,7 @@
 static struct platform_device fsi_ak4643_device = {
 	.name	= "fsi-ak4642-audio",
 	.dev	= {
-		.platform_data	= &fsi_info,
+		.platform_data	= &fsi2_ak4643_info,
 	},
 };
 
diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c
index 4d22016..4bd1162 100644
--- a/arch/arm/mach-shmobile/board-bonito.c
+++ b/arch/arm/mach-shmobile/board-bonito.c
@@ -27,6 +27,7 @@
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/smsc911x.h>
+#include <linux/videodev2.h>
 #include <mach/common.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -241,7 +242,7 @@
 	.clock_source	= LCDC_CLK_BUS,
 	.ch[0] = {
 		.chan			= LCDC_CHAN_MAINLCD,
-		.bpp			= 16,
+		.fourcc = V4L2_PIX_FMT_RGB565,
 		.interface_type		= RGB24,
 		.clock_divider		= 5,
 		.flags			= 0,
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index a281324..7b53cda 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -1352,6 +1352,10 @@
 static void __init mackerel_map_io(void)
 {
 	iotable_init(mackerel_io_desc, ARRAY_SIZE(mackerel_io_desc));
+	/* DMA memory at 0xff200000 - 0xffdfffff. The default 2MB size isn't
+	 * enough to allocate the frame buffer memory.
+	 */
+	init_consistent_dma_size(12 << 20);
 
 	/* setup early devices and console here as well */
 	sh7372_add_early_devices();
diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h
index d4b8f9e..de1a0f6 100644
--- a/arch/arm/mach-tegra/include/mach/usb_phy.h
+++ b/arch/arm/mach-tegra/include/mach/usb_phy.h
@@ -58,7 +58,7 @@
 	struct clk *pad_clk;
 	enum tegra_usb_phy_mode mode;
 	void *config;
-	struct otg_transceiver *ulpi;
+	struct usb_phy *ulpi;
 };
 
 struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs,
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
index 37576a7..ad321f9 100644
--- a/arch/arm/mach-tegra/usb_phy.c
+++ b/arch/arm/mach-tegra/usb_phy.c
@@ -608,13 +608,13 @@
 	writel(val, base + ULPI_TIMING_CTRL_1);
 
 	/* Fix VbusInvalid due to floating VBUS */
-	ret = otg_io_write(phy->ulpi, 0x40, 0x08);
+	ret = usb_phy_io_write(phy->ulpi, 0x40, 0x08);
 	if (ret) {
 		pr_err("%s: ulpi write failed\n", __func__);
 		return ret;
 	}
 
-	ret = otg_io_write(phy->ulpi, 0x80, 0x0B);
+	ret = usb_phy_io_write(phy->ulpi, 0x80, 0x0B);
 	if (ret) {
 		pr_err("%s: ulpi write failed\n", __func__);
 		return ret;
diff --git a/arch/arm/plat-mxc/include/mach/mxc_ehci.h b/arch/arm/plat-mxc/include/mach/mxc_ehci.h
index 2c159dc..9ffd1bb 100644
--- a/arch/arm/plat-mxc/include/mach/mxc_ehci.h
+++ b/arch/arm/plat-mxc/include/mach/mxc_ehci.h
@@ -44,7 +44,7 @@
 	int (*exit)(struct platform_device *pdev);
 
 	unsigned int		 portsc;
-	struct otg_transceiver	*otg;
+	struct usb_phy		*otg;
 };
 
 int mx51_initialize_usb_hw(int port, unsigned int flags);
diff --git a/arch/arm/plat-mxc/include/mach/ulpi.h b/arch/arm/plat-mxc/include/mach/ulpi.h
index f9161c9..42bdaca 100644
--- a/arch/arm/plat-mxc/include/mach/ulpi.h
+++ b/arch/arm/plat-mxc/include/mach/ulpi.h
@@ -2,15 +2,15 @@
 #define __MACH_ULPI_H
 
 #ifdef CONFIG_USB_ULPI
-struct otg_transceiver *imx_otg_ulpi_create(unsigned int flags);
+struct usb_phy *imx_otg_ulpi_create(unsigned int flags);
 #else
-static inline struct otg_transceiver *imx_otg_ulpi_create(unsigned int flags)
+static inline struct usb_phy *imx_otg_ulpi_create(unsigned int flags)
 {
 	return NULL;
 }
 #endif
 
-extern struct otg_io_access_ops mxc_ulpi_access_ops;
+extern struct usb_phy_io_ops mxc_ulpi_access_ops;
 
 #endif /* __MACH_ULPI_H */
 
diff --git a/arch/arm/plat-mxc/ulpi.c b/arch/arm/plat-mxc/ulpi.c
index 477e45b..d296342 100644
--- a/arch/arm/plat-mxc/ulpi.c
+++ b/arch/arm/plat-mxc/ulpi.c
@@ -58,7 +58,7 @@
 	return -ETIMEDOUT;
 }
 
-static int ulpi_read(struct otg_transceiver *otg, u32 reg)
+static int ulpi_read(struct usb_phy *otg, u32 reg)
 {
 	int ret;
 	void __iomem *view = otg->io_priv;
@@ -84,7 +84,7 @@
 	return (__raw_readl(view) >> ULPIVW_RDATA_SHIFT) & ULPIVW_RDATA_MASK;
 }
 
-static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
+static int ulpi_write(struct usb_phy *otg, u32 val, u32 reg)
 {
 	int ret;
 	void __iomem *view = otg->io_priv;
@@ -106,13 +106,13 @@
 	return ulpi_poll(view, ULPIVW_RUN);
 }
 
-struct otg_io_access_ops mxc_ulpi_access_ops = {
+struct usb_phy_io_ops mxc_ulpi_access_ops = {
 	.read	= ulpi_read,
 	.write	= ulpi_write,
 };
 EXPORT_SYMBOL_GPL(mxc_ulpi_access_ops);
 
-struct otg_transceiver *imx_otg_ulpi_create(unsigned int flags)
+struct usb_phy *imx_otg_ulpi_create(unsigned int flags)
 {
 	return otg_ulpi_create(&mxc_ulpi_access_ops, flags);
 }
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index ea33957..92c5af9 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -40,9 +40,7 @@
 			cpu_idle_sleep();
 		rcu_idle_exit();
 		tick_nohz_idle_exit();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index 8dd0416..a80a643 100644
--- a/arch/blackfin/kernel/process.c
+++ b/arch/blackfin/kernel/process.c
@@ -94,9 +94,7 @@
 			idle();
 		rcu_idle_exit();
 		tick_nohz_idle_exit();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/c6x/kernel/entry.S b/arch/c6x/kernel/entry.S
index 3e977cc..30b37e5 100644
--- a/arch/c6x/kernel/entry.S
+++ b/arch/c6x/kernel/entry.S
@@ -717,33 +717,6 @@
 #endif
 ENDPROC(sys_ftruncate64_c6x)
 
-#ifdef __ARCH_WANT_SYSCALL_OFF_T
-;; On Entry
-;;   A4 - fd
-;;   B4 - offset_lo (LE), offset_hi (BE)
-;;   A6 - offset_lo (BE), offset_hi (LE)
-;;   B6 - len
-;;   A8 - advice
-ENTRY(sys_fadvise64_c6x)
-#ifdef CONFIG_C6X_BIG_KERNEL
-	MVKL	.S1	sys_fadvise64,A0
-	MVKH	.S1	sys_fadvise64,A0
-	BNOP	.S2X	A0,2
-#else
-	B	.S2	sys_fadvise64
-	NOP	2
-#endif
-#ifdef CONFIG_CPU_BIG_ENDIAN
-	MV	.L2	B4,B5
- ||	MV	.D2X	A6,B4
-#else
-	MV	.D2X	A6,B5
-#endif
-	MV	.D1X	B6,A6
-	MV	.D2X	A8,B6
-#endif
-ENDPROC(sys_fadvise64_c6x)
-
 ;; On Entry
 ;;   A4 - fd
 ;;   B4 - offset_lo (LE), offset_hi (BE)
diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c
index aa585e4..d8f50ff 100644
--- a/arch/cris/kernel/process.c
+++ b/arch/cris/kernel/process.c
@@ -115,9 +115,7 @@
 				idle = default_idle;
 			idle();
 		}
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/frv/include/asm/perf_event.h b/arch/frv/include/asm/perf_event.h
index a69e015..c52ea55 100644
--- a/arch/frv/include/asm/perf_event.h
+++ b/arch/frv/include/asm/perf_event.h
@@ -12,6 +12,4 @@
 #ifndef _ASM_PERF_EVENT_H
 #define _ASM_PERF_EVENT_H
 
-#define PERF_EVENT_INDEX_OFFSET	0
-
 #endif /* _ASM_PERF_EVENT_H */
diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c
index 3901df1..29cc497 100644
--- a/arch/frv/kernel/process.c
+++ b/arch/frv/kernel/process.c
@@ -92,9 +92,7 @@
 				idle();
 		}
 
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c
index 933bd38..1a173b3 100644
--- a/arch/h8300/kernel/process.c
+++ b/arch/h8300/kernel/process.c
@@ -81,9 +81,7 @@
 	while (1) {
 		while (!need_resched())
 			idle();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/hexagon/include/asm/perf_event.h b/arch/hexagon/include/asm/perf_event.h
index 6c2910f..8b8526b 100644
--- a/arch/hexagon/include/asm/perf_event.h
+++ b/arch/hexagon/include/asm/perf_event.h
@@ -19,6 +19,4 @@
 #ifndef _ASM_PERF_EVENT_H
 #define _ASM_PERF_EVENT_H
 
-#define PERF_EVENT_INDEX_OFFSET	0
-
 #endif /* _ASM_PERF_EVENT_H */
diff --git a/arch/hexagon/kernel/smp.c b/arch/hexagon/kernel/smp.c
index c871a2c..0123c63 100644
--- a/arch/hexagon/kernel/smp.c
+++ b/arch/hexagon/kernel/smp.c
@@ -179,8 +179,6 @@
 	printk(KERN_INFO "%s cpu %d\n", __func__, current_thread_info()->cpu);
 
 	set_cpu_online(cpu, true);
-	while (!cpumask_test_cpu(cpu, cpu_active_mask))
-		cpu_relax();
 	local_irq_enable();
 
 	cpu_idle();
diff --git a/arch/ia64/hp/sim/boot/fw-emu.c b/arch/ia64/hp/sim/boot/fw-emu.c
index bf6d9d8..0216e28 100644
--- a/arch/ia64/hp/sim/boot/fw-emu.c
+++ b/arch/ia64/hp/sim/boot/fw-emu.c
@@ -160,28 +160,19 @@
 	 */
 	status = 0;
 	if (index == SAL_FREQ_BASE) {
-		switch (in1) {
-		      case SAL_FREQ_BASE_PLATFORM:
+		if (in1 == SAL_FREQ_BASE_PLATFORM)
 			r9 = 200000000;
-			break;
-
-		      case SAL_FREQ_BASE_INTERVAL_TIMER:
+		else if (in1 == SAL_FREQ_BASE_INTERVAL_TIMER) {
 			/*
 			 * Is this supposed to be the cr.itc frequency
 			 * or something platform specific?  The SAL
 			 * doc ain't exactly clear on this...
 			 */
 			r9 = 700000000;
-			break;
-
-		      case SAL_FREQ_BASE_REALTIME_CLOCK:
+		} else if (in1 == SAL_FREQ_BASE_REALTIME_CLOCK)
 			r9 = 1;
-			break;
-
-		      default:
+		else
 			status = -1;
-			break;
-		}
 	} else if (index == SAL_SET_VECTORS) {
 		;
 	} else if (index == SAL_GET_STATE_INFO) {
diff --git a/arch/ia64/hp/sim/hpsim_irq.c b/arch/ia64/hp/sim/hpsim_irq.c
index 4bd9a63..0aa70eb 100644
--- a/arch/ia64/hp/sim/hpsim_irq.c
+++ b/arch/ia64/hp/sim/hpsim_irq.c
@@ -10,6 +10,8 @@
 #include <linux/sched.h>
 #include <linux/irq.h>
 
+#include "hpsim_ssc.h"
+
 static unsigned int
 hpsim_irq_startup(struct irq_data *data)
 {
@@ -37,15 +39,37 @@
 	.irq_set_affinity =	hpsim_set_affinity_noop,
 };
 
+static void hpsim_irq_set_chip(int irq)
+{
+	struct irq_chip *chip = irq_get_chip(irq);
+
+	if (chip == &no_irq_chip)
+		irq_set_chip(irq, &irq_type_hp_sim);
+}
+
+static void hpsim_connect_irq(int intr, int irq)
+{
+	ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT);
+}
+
+int hpsim_get_irq(int intr)
+{
+	int irq = assign_irq_vector(AUTO_ASSIGN);
+
+	if (irq >= 0) {
+		hpsim_irq_set_chip(irq);
+		irq_set_handler(irq, handle_simple_irq);
+		hpsim_connect_irq(intr, irq);
+	}
+
+	return irq;
+}
+
 void __init
 hpsim_irq_init (void)
 {
 	int i;
 
-	for_each_active_irq(i) {
-		struct irq_chip *chip = irq_get_chip(i);
-
-		if (chip == &no_irq_chip)
-			irq_set_chip(i, &irq_type_hp_sim);
-	}
+	for_each_active_irq(i)
+		hpsim_irq_set_chip(i);
 }
diff --git a/arch/ia64/hp/sim/hpsim_setup.c b/arch/ia64/hp/sim/hpsim_setup.c
index f629e90..664a540 100644
--- a/arch/ia64/hp/sim/hpsim_setup.c
+++ b/arch/ia64/hp/sim/hpsim_setup.c
@@ -26,12 +26,6 @@
 #include "hpsim_ssc.h"
 
 void
-ia64_ssc_connect_irq (long intr, long irq)
-{
-	ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT);
-}
-
-void
 ia64_ctl_trace (long on)
 {
 	ia64_ssc(on, 0, 0, 0, SSC_CTL_TRACE);
diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c
index 47afcc6..e343357 100644
--- a/arch/ia64/hp/sim/simeth.c
+++ b/arch/ia64/hp/sim/simeth.c
@@ -129,17 +129,6 @@
 
 
 static inline int
-netdev_connect(int irq)
-{
-	/* XXX Fix me
-	 * this does not support multiple cards
-	 * also no return value
-	 */
-	ia64_ssc_connect_irq(NETWORK_INTR, irq);
-	return 0;
-}
-
-static inline int
 netdev_attach(int fd, int irq, unsigned int ipaddr)
 {
 	/* this puts the host interface in the right mode (start interrupting) */
@@ -226,15 +215,13 @@
 		return err;
 	}
 
-	if ((rc = assign_irq_vector(AUTO_ASSIGN)) < 0)
-		panic("%s: out of interrupt vectors!\n", __func__);
-	dev->irq = rc;
-
 	/*
 	 * attach the interrupt in the simulator, this does enable interrupts
 	 * until a netdev_attach() is called
 	 */
-	netdev_connect(dev->irq);
+	if ((rc = hpsim_get_irq(NETWORK_INTR)) < 0)
+		panic("%s: out of interrupt vectors!\n", __func__);
+	dev->irq = rc;
 
 	printk(KERN_INFO "%s: hosteth=%s simfd=%d, HwAddr",
 	       dev->name, simeth_device, local->simfd);
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
index bff0824..c34785d 100644
--- a/arch/ia64/hp/sim/simserial.c
+++ b/arch/ia64/hp/sim/simserial.c
@@ -4,16 +4,11 @@
  * This driver is mostly used for bringup purposes and will go away.
  * It has a strong dependency on the system console. All outputs
  * are rerouted to the same facility as the one used by printk which, in our
- * case means sys_sim.c console (goes via the simulator). The code hereafter
- * is completely leveraged from the serial.c driver.
+ * case means sys_sim.c console (goes via the simulator).
  *
  * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co
  *	Stephane Eranian <eranian@hpl.hp.com>
  *	David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * 02/04/00 D. Mosberger	Merged in serial.c bug fixes in rs_close().
- * 02/25/00 D. Mosberger	Synced up with 2.3.99pre-5 version of serial.c.
- * 07/30/02 D. Mosberger	Replace sti()/cli() with explicit spinlocks & local irq masking
  */
 
 #include <linux/init.h>
@@ -27,15 +22,17 @@
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/capability.h>
+#include <linux/circ_buf.h>
 #include <linux/console.h>
+#include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/serial.h>
-#include <linux/serialP.h>
 #include <linux/sysrq.h>
+#include <linux/uaccess.h>
 
-#include <asm/irq.h>
-#include <asm/hw_irq.h>
-#include <asm/uaccess.h>
+#include <asm/hpsim.h>
+
+#include "hpsim_ssc.h"
 
 #undef SIMSERIAL_DEBUG	/* define this to get some debug information */
 
@@ -43,118 +40,44 @@
 
 #define NR_PORTS	1	/* only one port for now */
 
-#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED)
-
-#define SSC_GETCHAR	21
-
-extern long ia64_ssc (long, long, long, long, int);
-extern void ia64_ssc_connect_irq (long intr, long irq);
-
-static char *serial_name = "SimSerial driver";
-static char *serial_version = "0.6";
-
-/*
- * This has been extracted from asm/serial.h. We need one eventually but
- * I don't know exactly what we're going to put in it so just fake one
- * for now.
- */
-#define BASE_BAUD ( 1843200 / 16 )
-
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
-/*
- * Most of the values here are meaningless to this particular driver.
- * However some values must be preserved for the code (leveraged from serial.c
- * to work correctly).
- * port must not be 0
- * type must not be UNKNOWN
- * So I picked arbitrary (guess from where?) values instead
- */
-static struct serial_state rs_table[NR_PORTS]={
-  /* UART CLK   PORT IRQ     FLAGS        */
-  { 0, BASE_BAUD, 0x3F8, 0, STD_COM_FLAGS,0,PORT_16550 }  /* ttyS0 */
+struct serial_state {
+	struct tty_port port;
+	struct circ_buf xmit;
+	int irq;
+	int x_char;
 };
 
-/*
- * Just for the fun of it !
- */
-static struct serial_uart_config uart_config[] = {
-	{ "unknown", 1, 0 },
-	{ "8250", 1, 0 },
-	{ "16450", 1, 0 },
-	{ "16550", 1, 0 },
-	{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
-	{ "cirrus", 1, 0 },
-	{ "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH },
-	{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
-		  UART_STARTECH },
-	{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
-	{ NULL, 0}
-};
+static struct serial_state rs_table[NR_PORTS];
 
 struct tty_driver *hp_simserial_driver;
 
-static struct async_struct *IRQ_ports[NR_IRQS];
-
 static struct console *console;
 
-static unsigned char *tmp_buf;
-
-extern struct console *console_drivers; /* from kernel/printk.c */
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void rs_stop(struct tty_struct *tty)
-{
-#ifdef SIMSERIAL_DEBUG
-	printk("rs_stop: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n",
-		tty->stopped, tty->hw_stopped, tty->flow_stopped);
-#endif
-
-}
-
-static void rs_start(struct tty_struct *tty)
-{
-#ifdef SIMSERIAL_DEBUG
-	printk("rs_start: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n",
-		tty->stopped, tty->hw_stopped, tty->flow_stopped);
-#endif
-}
-
-static  void receive_chars(struct tty_struct *tty)
+static void receive_chars(struct tty_struct *tty)
 {
 	unsigned char ch;
 	static unsigned char seen_esc = 0;
 
 	while ( (ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR)) ) {
-		if ( ch == 27 && seen_esc == 0 ) {
+		if (ch == 27 && seen_esc == 0) {
 			seen_esc = 1;
 			continue;
-		} else {
-			if ( seen_esc==1 && ch == 'O' ) {
-				seen_esc = 2;
-				continue;
-			} else if ( seen_esc == 2 ) {
-				if ( ch == 'P' ) /* F1 */
-					show_state();
+		} else if (seen_esc == 1 && ch == 'O') {
+			seen_esc = 2;
+			continue;
+		} else if (seen_esc == 2) {
+			if (ch == 'P') /* F1 */
+				show_state();
 #ifdef CONFIG_MAGIC_SYSRQ
-				if ( ch == 'S' ) { /* F4 */
-					do
-						ch = ia64_ssc(0, 0, 0, 0,
-							      SSC_GETCHAR);
-					while (!ch);
-					handle_sysrq(ch);
-				}
-#endif
-				seen_esc = 0;
-				continue;
+			if (ch == 'S') { /* F4 */
+				do {
+					ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR);
+				} while (!ch);
+				handle_sysrq(ch);
 			}
+#endif
+			seen_esc = 0;
+			continue;
 		}
 		seen_esc = 0;
 
@@ -169,22 +92,19 @@
  */
 static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
 {
-	struct async_struct * info;
+	struct serial_state *info = dev_id;
+	struct tty_struct *tty = tty_port_tty_get(&info->port);
 
-	/*
-	 * I don't know exactly why they don't use the dev_id opaque data
-	 * pointer instead of this extra lookup table
-	 */
-	info = IRQ_ports[irq];
-	if (!info || !info->tty) {
-		printk(KERN_INFO "simrs_interrupt_single: info|tty=0 info=%p problem\n", info);
+	if (!tty) {
+		printk(KERN_INFO "%s: tty=0 problem\n", __func__);
 		return IRQ_NONE;
 	}
 	/*
 	 * pretty simple in our case, because we only get interrupts
 	 * on inbound traffic
 	 */
-	receive_chars(info->tty);
+	receive_chars(tty);
+	tty_kref_put(tty);
 	return IRQ_HANDLED;
 }
 
@@ -194,17 +114,12 @@
  * -------------------------------------------------------------------
  */
 
-static void do_softint(struct work_struct *private_)
-{
-	printk(KERN_ERR "simserial: do_softint called\n");
-}
-
 static int rs_put_char(struct tty_struct *tty, unsigned char ch)
 {
-	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	unsigned long flags;
 
-	if (!tty || !info->xmit.buf)
+	if (!info->xmit.buf)
 		return 0;
 
 	local_irq_save(flags);
@@ -218,12 +133,12 @@
 	return 1;
 }
 
-static void transmit_chars(struct async_struct *info, int *intr_done)
+static void transmit_chars(struct tty_struct *tty, struct serial_state *info,
+		int *intr_done)
 {
 	int count;
 	unsigned long flags;
 
-
 	local_irq_save(flags);
 
 	if (info->x_char) {
@@ -231,16 +146,16 @@
 
 		console->write(console, &c, 1);
 
-		info->state->icount.tx++;
 		info->x_char = 0;
 
 		goto out;
 	}
 
-	if (info->xmit.head == info->xmit.tail || info->tty->stopped || info->tty->hw_stopped) {
+	if (info->xmit.head == info->xmit.tail || tty->stopped ||
+			tty->hw_stopped) {
 #ifdef SIMSERIAL_DEBUG
 		printk("transmit_chars: head=%d, tail=%d, stopped=%d\n",
-		       info->xmit.head, info->xmit.tail, info->tty->stopped);
+		       info->xmit.head, info->xmit.tail, tty->stopped);
 #endif
 		goto out;
 	}
@@ -272,24 +187,24 @@
 
 static void rs_flush_chars(struct tty_struct *tty)
 {
-	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 
-	if (info->xmit.head == info->xmit.tail || tty->stopped || tty->hw_stopped ||
-	    !info->xmit.buf)
+	if (info->xmit.head == info->xmit.tail || tty->stopped ||
+			tty->hw_stopped || !info->xmit.buf)
 		return;
 
-	transmit_chars(info, NULL);
+	transmit_chars(tty, info, NULL);
 }
 
-
 static int rs_write(struct tty_struct * tty,
 		    const unsigned char *buf, int count)
 {
+	struct serial_state *info = tty->driver_data;
 	int	c, ret = 0;
-	struct async_struct *info = (struct async_struct *)tty->driver_data;
 	unsigned long flags;
 
-	if (!tty || !info->xmit.buf || !tmp_buf) return 0;
+	if (!info->xmit.buf)
+		return 0;
 
 	local_irq_save(flags);
 	while (1) {
@@ -310,30 +225,30 @@
 	/*
 	 * Hey, we transmit directly from here in our case
 	 */
-	if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE)
-	    && !tty->stopped && !tty->hw_stopped) {
-		transmit_chars(info, NULL);
-	}
+	if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) &&
+			!tty->stopped && !tty->hw_stopped)
+		transmit_chars(tty, info, NULL);
+
 	return ret;
 }
 
 static int rs_write_room(struct tty_struct *tty)
 {
-	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 
 	return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
 }
 
 static int rs_chars_in_buffer(struct tty_struct *tty)
 {
-	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 
 	return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
 }
 
 static void rs_flush_buffer(struct tty_struct *tty)
 {
-	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	unsigned long flags;
 
 	local_irq_save(flags);
@@ -349,7 +264,7 @@
  */
 static void rs_send_xchar(struct tty_struct *tty, char ch)
 {
-	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 
 	info->x_char = ch;
 	if (ch) {
@@ -357,7 +272,7 @@
 		 * I guess we could call console->write() directly but
 		 * let's do that for now.
 		 */
-		transmit_chars(info, NULL);
+		transmit_chars(tty, info, NULL);
 	}
 }
 
@@ -371,14 +286,15 @@
  */
 static void rs_throttle(struct tty_struct * tty)
 {
-	if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty));
+	if (I_IXOFF(tty))
+		rs_send_xchar(tty, STOP_CHAR(tty));
 
 	printk(KERN_INFO "simrs_throttle called\n");
 }
 
 static void rs_unthrottle(struct tty_struct * tty)
 {
-	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 
 	if (I_IXOFF(tty)) {
 		if (info->x_char)
@@ -389,7 +305,6 @@
 	printk(KERN_INFO "simrs_unthrottle called\n");
 }
 
-
 static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
 {
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
@@ -400,48 +315,21 @@
 	}
 
 	switch (cmd) {
-		case TIOCGSERIAL:
-			printk(KERN_INFO "simrs_ioctl TIOCGSERIAL called\n");
-			return 0;
-		case TIOCSSERIAL:
-			printk(KERN_INFO "simrs_ioctl TIOCSSERIAL called\n");
-			return 0;
-		case TIOCSERCONFIG:
-			printk(KERN_INFO "rs_ioctl: TIOCSERCONFIG called\n");
-			return -EINVAL;
-
-		case TIOCSERGETLSR: /* Get line status register */
-			printk(KERN_INFO "rs_ioctl: TIOCSERGETLSR called\n");
-			return  -EINVAL;
-
-		case TIOCSERGSTRUCT:
-			printk(KERN_INFO "rs_ioctl: TIOCSERGSTRUCT called\n");
-#if 0
-			if (copy_to_user((struct async_struct *) arg,
-					 info, sizeof(struct async_struct)))
-				return -EFAULT;
-#endif
-			return 0;
-
-		/*
-		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
-		 * - mask passed in arg for lines of interest
-		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
-		 * Caller should use TIOCGICOUNT to see which one it was
-		 */
-		case TIOCMIWAIT:
-			printk(KERN_INFO "rs_ioctl: TIOCMIWAIT: called\n");
-			return 0;
-		case TIOCSERGWILD:
-		case TIOCSERSWILD:
-			/* "setserial -W" is called in Debian boot */
-			printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n");
-			return 0;
-
-		default:
-			return -ENOIOCTLCMD;
-		}
-	return 0;
+	case TIOCGSERIAL:
+	case TIOCSSERIAL:
+	case TIOCSERGSTRUCT:
+	case TIOCMIWAIT:
+		return 0;
+	case TIOCSERCONFIG:
+	case TIOCSERGETLSR: /* Get line status register */
+		return -EINVAL;
+	case TIOCSERGWILD:
+	case TIOCSERSWILD:
+		/* "setserial -W" is called in Debian boot */
+		printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n");
+		return 0;
+	}
+	return -ENOIOCTLCMD;
 }
 
 #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
@@ -452,220 +340,50 @@
 	if ((old_termios->c_cflag & CRTSCTS) &&
 	    !(tty->termios->c_cflag & CRTSCTS)) {
 		tty->hw_stopped = 0;
-		rs_start(tty);
 	}
 }
 /*
  * This routine will shutdown a serial port; interrupts are disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
  */
-static void shutdown(struct async_struct * info)
+static void shutdown(struct tty_port *port)
 {
-	unsigned long	flags;
-	struct serial_state *state;
-	int		retval;
-
-	if (!(info->flags & ASYNC_INITIALIZED)) return;
-
-	state = info->state;
-
-#ifdef SIMSERIAL_DEBUG
-	printk("Shutting down serial port %d (irq %d)....", info->line,
-	       state->irq);
-#endif
+	struct serial_state *info = container_of(port, struct serial_state,
+			port);
+	unsigned long flags;
 
 	local_irq_save(flags);
-	{
-		/*
-		 * First unlink the serial port from the IRQ chain...
-		 */
-		if (info->next_port)
-			info->next_port->prev_port = info->prev_port;
-		if (info->prev_port)
-			info->prev_port->next_port = info->next_port;
-		else
-			IRQ_ports[state->irq] = info->next_port;
+	if (info->irq)
+		free_irq(info->irq, info);
 
-		/*
-		 * Free the IRQ, if necessary
-		 */
-		if (state->irq && (!IRQ_ports[state->irq] ||
-				   !IRQ_ports[state->irq]->next_port)) {
-			if (IRQ_ports[state->irq]) {
-				free_irq(state->irq, NULL);
-				retval = request_irq(state->irq, rs_interrupt_single,
-						     IRQ_T(info), "serial", NULL);
-
-				if (retval)
-					printk(KERN_ERR "serial shutdown: request_irq: error %d"
-					       "  Couldn't reacquire IRQ.\n", retval);
-			} else
-				free_irq(state->irq, NULL);
-		}
-
-		if (info->xmit.buf) {
-			free_page((unsigned long) info->xmit.buf);
-			info->xmit.buf = NULL;
-		}
-
-		if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);
-
-		info->flags &= ~ASYNC_INITIALIZED;
+	if (info->xmit.buf) {
+		free_page((unsigned long) info->xmit.buf);
+		info->xmit.buf = NULL;
 	}
 	local_irq_restore(flags);
 }
 
-/*
- * ------------------------------------------------------------
- * rs_close()
- *
- * This routine is called when the serial port gets closed.  First, we
- * wait for the last remaining data to be sent.  Then, we unlink its
- * async structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
 static void rs_close(struct tty_struct *tty, struct file * filp)
 {
-	struct async_struct * info = (struct async_struct *)tty->driver_data;
-	struct serial_state *state;
-	unsigned long flags;
+	struct serial_state *info = tty->driver_data;
 
-	if (!info ) return;
-
-	state = info->state;
-
-	local_irq_save(flags);
-	if (tty_hung_up_p(filp)) {
-#ifdef SIMSERIAL_DEBUG
-		printk("rs_close: hung_up\n");
-#endif
-		local_irq_restore(flags);
-		return;
-	}
-#ifdef SIMSERIAL_DEBUG
-	printk("rs_close ttys%d, count = %d\n", info->line, state->count);
-#endif
-	if ((tty->count == 1) && (state->count != 1)) {
-		/*
-		 * Uh, oh.  tty->count is 1, which means that the tty
-		 * structure will be freed.  state->count should always
-		 * be one in these conditions.  If it's greater than
-		 * one, we've got real problems, since it means the
-		 * serial port won't be shutdown.
-		 */
-		printk(KERN_ERR "rs_close: bad serial port count; tty->count is 1, "
-		       "state->count is %d\n", state->count);
-		state->count = 1;
-	}
-	if (--state->count < 0) {
-		printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n",
-		       info->line, state->count);
-		state->count = 0;
-	}
-	if (state->count) {
-		local_irq_restore(flags);
-		return;
-	}
-	info->flags |= ASYNC_CLOSING;
-	local_irq_restore(flags);
-
-	/*
-	 * Now we wait for the transmit buffer to clear; and we notify
-	 * the line discipline to only process XON/XOFF characters.
-	 */
-	shutdown(info);
-	rs_flush_buffer(tty);
-	tty_ldisc_flush(tty);
-	info->event = 0;
-	info->tty = NULL;
-	if (info->blocked_open) {
-		if (info->close_delay)
-			schedule_timeout_interruptible(info->close_delay);
-		wake_up_interruptible(&info->open_wait);
-	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-	wake_up_interruptible(&info->close_wait);
+	tty_port_close(&info->port, tty, filp);
 }
 
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-}
-
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
 static void rs_hangup(struct tty_struct *tty)
 {
-	struct async_struct * info = (struct async_struct *)tty->driver_data;
-	struct serial_state *state = info->state;
-
-#ifdef SIMSERIAL_DEBUG
-	printk("rs_hangup: called\n");
-#endif
-
-	state = info->state;
+	struct serial_state *info = tty->driver_data;
 
 	rs_flush_buffer(tty);
-	if (info->flags & ASYNC_CLOSING)
-		return;
-	shutdown(info);
-
-	info->event = 0;
-	state->count = 0;
-	info->flags &= ~ASYNC_NORMAL_ACTIVE;
-	info->tty = NULL;
-	wake_up_interruptible(&info->open_wait);
+	tty_port_hangup(&info->port);
 }
 
-
-static int get_async_struct(int line, struct async_struct **ret_info)
+static int activate(struct tty_port *port, struct tty_struct *tty)
 {
-	struct async_struct *info;
-	struct serial_state *sstate;
-
-	sstate = rs_table + line;
-	sstate->count++;
-	if (sstate->info) {
-		*ret_info = sstate->info;
-		return 0;
-	}
-	info = kzalloc(sizeof(struct async_struct), GFP_KERNEL);
-	if (!info) {
-		sstate->count--;
-		return -ENOMEM;
-	}
-	init_waitqueue_head(&info->open_wait);
-	init_waitqueue_head(&info->close_wait);
-	init_waitqueue_head(&info->delta_msr_wait);
-	info->magic = SERIAL_MAGIC;
-	info->port = sstate->port;
-	info->flags = sstate->flags;
-	info->xmit_fifo_size = sstate->xmit_fifo_size;
-	info->line = line;
-	INIT_WORK(&info->work, do_softint);
-	info->state = sstate;
-	if (sstate->info) {
-		kfree(info);
-		*ret_info = sstate->info;
-		return 0;
-	}
-	*ret_info = sstate->info = info;
-	return 0;
-}
-
-static int
-startup(struct async_struct *info)
-{
-	unsigned long flags;
-	int	retval=0;
-	irq_handler_t handler;
-	struct serial_state *state= info->state;
-	unsigned long page;
+	struct serial_state *state = container_of(port, struct serial_state,
+			port);
+	unsigned long flags, page;
+	int retval = 0;
 
 	page = get_zeroed_page(GFP_KERNEL);
 	if (!page)
@@ -673,86 +391,31 @@
 
 	local_irq_save(flags);
 
-	if (info->flags & ASYNC_INITIALIZED) {
-		free_page(page);
-		goto errout;
-	}
-
-	if (!state->port || !state->type) {
-		if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);
-		free_page(page);
-		goto errout;
-	}
-	if (info->xmit.buf)
+	if (state->xmit.buf)
 		free_page(page);
 	else
-		info->xmit.buf = (unsigned char *) page;
+		state->xmit.buf = (unsigned char *) page;
 
-#ifdef SIMSERIAL_DEBUG
-	printk("startup: ttys%d (irq %d)...", info->line, state->irq);
-#endif
-
-	/*
-	 * Allocate the IRQ if necessary
-	 */
-	if (state->irq && (!IRQ_ports[state->irq] ||
-			  !IRQ_ports[state->irq]->next_port)) {
-		if (IRQ_ports[state->irq]) {
-			retval = -EBUSY;
+	if (state->irq) {
+		retval = request_irq(state->irq, rs_interrupt_single, 0,
+				"simserial", state);
+		if (retval)
 			goto errout;
-		} else
-			handler = rs_interrupt_single;
-
-		retval = request_irq(state->irq, handler, IRQ_T(info), "simserial", NULL);
-		if (retval) {
-			if (capable(CAP_SYS_ADMIN)) {
-				if (info->tty)
-					set_bit(TTY_IO_ERROR,
-						&info->tty->flags);
-				retval = 0;
-			}
-			goto errout;
-		}
 	}
 
-	/*
-	 * Insert serial port into IRQ chain.
-	 */
-	info->prev_port = NULL;
-	info->next_port = IRQ_ports[state->irq];
-	if (info->next_port)
-		info->next_port->prev_port = info;
-	IRQ_ports[state->irq] = info;
-
-	if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags);
-
-	info->xmit.head = info->xmit.tail = 0;
-
-#if 0
-	/*
-	 * Set up serial timers...
-	 */
-	timer_table[RS_TIMER].expires = jiffies + 2*HZ/100;
-	timer_active |= 1 << RS_TIMER;
-#endif
+	state->xmit.head = state->xmit.tail = 0;
 
 	/*
 	 * Set up the tty->alt_speed kludge
 	 */
-	if (info->tty) {
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-			info->tty->alt_speed = 57600;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-			info->tty->alt_speed = 115200;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-			info->tty->alt_speed = 230400;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-			info->tty->alt_speed = 460800;
-	}
-
-	info->flags |= ASYNC_INITIALIZED;
-	local_irq_restore(flags);
-	return 0;
+	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+		tty->alt_speed = 57600;
+	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+		tty->alt_speed = 115200;
+	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+		tty->alt_speed = 230400;
+	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+		tty->alt_speed = 460800;
 
 errout:
 	local_irq_restore(flags);
@@ -768,56 +431,11 @@
  */
 static int rs_open(struct tty_struct *tty, struct file * filp)
 {
-	struct async_struct	*info;
-	int			retval, line;
-	unsigned long		page;
+	struct serial_state *info = rs_table + tty->index;
+	struct tty_port *port = &info->port;
 
-	line = tty->index;
-	if ((line < 0) || (line >= NR_PORTS))
-		return -ENODEV;
-	retval = get_async_struct(line, &info);
-	if (retval)
-		return retval;
 	tty->driver_data = info;
-	info->tty = tty;
-
-#ifdef SIMSERIAL_DEBUG
-	printk("rs_open %s, count = %d\n", tty->name, info->state->count);
-#endif
-	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-
-	if (!tmp_buf) {
-		page = get_zeroed_page(GFP_KERNEL);
-		if (!page)
-			return -ENOMEM;
-		if (tmp_buf)
-			free_page(page);
-		else
-			tmp_buf = (unsigned char *) page;
-	}
-
-	/*
-	 * If the port is the middle of closing, bail out now
-	 */
-	if (tty_hung_up_p(filp) ||
-	    (info->flags & ASYNC_CLOSING)) {
-		if (info->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-		return ((info->flags & ASYNC_HUP_NOTIFY) ?
-			-EAGAIN : -ERESTARTSYS);
-#else
-		return -EAGAIN;
-#endif
-	}
-
-	/*
-	 * Start up serial port
-	 */
-	retval = startup(info);
-	if (retval) {
-		return retval;
-	}
+	tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 	/*
 	 * figure out which console to use (should be one already)
@@ -828,30 +446,21 @@
 		console = console->next;
 	}
 
-#ifdef SIMSERIAL_DEBUG
-	printk("rs_open ttys%d successful\n", info->line);
-#endif
-	return 0;
+	return tty_port_open(port, tty, filp);
 }
 
 /*
  * /proc fs routines....
  */
 
-static inline void line_info(struct seq_file *m, struct serial_state *state)
-{
-	seq_printf(m, "%d: uart:%s port:%lX irq:%d\n",
-		       state->line, uart_config[state->type].name,
-		       state->port, state->irq);
-}
-
 static int rs_proc_show(struct seq_file *m, void *v)
 {
 	int i;
 
-	seq_printf(m, "simserinfo:1.0 driver:%s\n", serial_version);
+	seq_printf(m, "simserinfo:1.0\n");
 	for (i = 0; i < NR_PORTS; i++)
-		line_info(m, &rs_table[i]);
+		seq_printf(m, "%d: uart:16550 port:3F8 irq:%d\n",
+		       i, rs_table[i].irq);
 	return 0;
 }
 
@@ -868,25 +477,6 @@
 	.release	= single_release,
 };
 
-/*
- * ---------------------------------------------------------------------
- * rs_init() and friends
- *
- * rs_init() is called at boot-time to initialize the serial driver.
- * ---------------------------------------------------------------------
- */
-
-/*
- * This routine prints out the appropriate serial driver version
- * number, and identifies which options were configured into this
- * driver.
- */
-static inline void show_serial_version(void)
-{
-	printk(KERN_INFO "%s version %s with", serial_name, serial_version);
-	printk(KERN_INFO " no serial options enabled\n");
-}
-
 static const struct tty_operations hp_ops = {
 	.open = rs_open,
 	.close = rs_close,
@@ -901,34 +491,31 @@
 	.unthrottle = rs_unthrottle,
 	.send_xchar = rs_send_xchar,
 	.set_termios = rs_set_termios,
-	.stop = rs_stop,
-	.start = rs_start,
 	.hangup = rs_hangup,
-	.wait_until_sent = rs_wait_until_sent,
 	.proc_fops = &rs_proc_fops,
 };
 
-/*
- * The serial driver boot-time initialization code!
- */
-static int __init
-simrs_init (void)
+static const struct tty_port_operations hp_port_ops = {
+	.activate = activate,
+	.shutdown = shutdown,
+};
+
+static int __init simrs_init(void)
 {
-	int			i, rc;
-	struct serial_state	*state;
+	struct serial_state *state;
+	int retval;
 
 	if (!ia64_platform_is("hpsim"))
 		return -ENODEV;
 
-	hp_simserial_driver = alloc_tty_driver(1);
+	hp_simserial_driver = alloc_tty_driver(NR_PORTS);
 	if (!hp_simserial_driver)
 		return -ENOMEM;
 
-	show_serial_version();
+	printk(KERN_INFO "SimSerial driver with no serial options enabled\n");
 
 	/* Initialize the tty_driver structure */
 
-	hp_simserial_driver->owner = THIS_MODULE;
 	hp_simserial_driver->driver_name = "simserial";
 	hp_simserial_driver->name = "ttyS";
 	hp_simserial_driver->major = TTY_MAJOR;
@@ -941,31 +528,33 @@
 	hp_simserial_driver->flags = TTY_DRIVER_REAL_RAW;
 	tty_set_operations(hp_simserial_driver, &hp_ops);
 
-	/*
-	 * Let's have a little bit of fun !
-	 */
-	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+	state = rs_table;
+	tty_port_init(&state->port);
+	state->port.ops = &hp_port_ops;
+	state->port.close_delay = 0; /* XXX really 0? */
 
-		if (state->type == PORT_UNKNOWN) continue;
-
-		if (!state->irq) {
-			if ((rc = assign_irq_vector(AUTO_ASSIGN)) < 0)
-				panic("%s: out of interrupt vectors!\n",
-				      __func__);
-			state->irq = rc;
-			ia64_ssc_connect_irq(KEYBOARD_INTR, state->irq);
-		}
-
-		printk(KERN_INFO "ttyS%d at 0x%04lx (irq = %d) is a %s\n",
-		       state->line,
-		       state->port, state->irq,
-		       uart_config[state->type].name);
+	retval = hpsim_get_irq(KEYBOARD_INTR);
+	if (retval < 0) {
+		printk(KERN_ERR "%s: out of interrupt vectors!\n",
+				__func__);
+		goto err_free_tty;
 	}
 
-	if (tty_register_driver(hp_simserial_driver))
-		panic("Couldn't register simserial driver\n");
+	state->irq = retval;
+
+	/* the port is imaginary */
+	printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq);
+
+	retval = tty_register_driver(hp_simserial_driver);
+	if (retval) {
+		printk(KERN_ERR "Couldn't register simserial driver\n");
+		goto err_free_tty;
+	}
 
 	return 0;
+err_free_tty:
+	put_tty_driver(hp_simserial_driver);
+	return retval;
 }
 
 #ifndef MODULE
diff --git a/arch/ia64/include/asm/hpsim.h b/arch/ia64/include/asm/hpsim.h
index 892ab19..0fe5022 100644
--- a/arch/ia64/include/asm/hpsim.h
+++ b/arch/ia64/include/asm/hpsim.h
@@ -10,7 +10,7 @@
 struct tty_driver;
 extern struct tty_driver *hp_simserial_driver;
 
-void ia64_ssc_connect_irq(long intr, long irq);
+extern int hpsim_get_irq(int intr);
 void ia64_ctl_trace(long on);
 
 #endif
diff --git a/arch/ia64/include/asm/paravirt.h b/arch/ia64/include/asm/paravirt.h
index 32551d3..b149b88 100644
--- a/arch/ia64/include/asm/paravirt.h
+++ b/arch/ia64/include/asm/paravirt.h
@@ -281,9 +281,9 @@
 		pv_time_ops.init_missing_ticks_accounting(cpu);
 }
 
-struct jump_label_key;
-extern struct jump_label_key paravirt_steal_enabled;
-extern struct jump_label_key paravirt_steal_rq_enabled;
+struct static_key;
+extern struct static_key paravirt_steal_enabled;
+extern struct static_key paravirt_steal_rq_enabled;
 
 static inline int
 paravirt_do_steal_accounting(unsigned long *new_itm)
diff --git a/arch/ia64/kernel/paravirt.c b/arch/ia64/kernel/paravirt.c
index 1008682..1b22f6d 100644
--- a/arch/ia64/kernel/paravirt.c
+++ b/arch/ia64/kernel/paravirt.c
@@ -634,8 +634,8 @@
  * pv_time_ops
  * time operations
  */
-struct jump_label_key paravirt_steal_enabled;
-struct jump_label_key paravirt_steal_rq_enabled;
+struct static_key paravirt_steal_enabled;
+struct static_key paravirt_steal_rq_enabled;
 
 static int
 ia64_native_do_steal_accounting(unsigned long *new_itm)
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 6d33c5c..9dc52b6 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -330,9 +330,7 @@
 			normal_xtp();
 #endif
 		}
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 		check_pgt_cache();
 		if (cpu_is_offline(cpu))
 			play_dead();
diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c
index 422bea9..3a4a32b 100644
--- a/arch/m32r/kernel/process.c
+++ b/arch/m32r/kernel/process.c
@@ -90,9 +90,7 @@
 
 			idle();
 		}
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/m68k/emu/nfcon.c b/arch/m68k/emu/nfcon.c
index ab20dc0..8db25e8 100644
--- a/arch/m68k/emu/nfcon.c
+++ b/arch/m68k/emu/nfcon.c
@@ -127,7 +127,6 @@
 	if (!nfcon_tty_driver)
 		return -ENOMEM;
 
-	nfcon_tty_driver->owner = THIS_MODULE;
 	nfcon_tty_driver->driver_name = "nfcon";
 	nfcon_tty_driver->name = "nfcon";
 	nfcon_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
diff --git a/arch/m68k/kernel/process_mm.c b/arch/m68k/kernel/process_mm.c
index 099283e..fe4186b 100644
--- a/arch/m68k/kernel/process_mm.c
+++ b/arch/m68k/kernel/process_mm.c
@@ -78,9 +78,7 @@
 	while (1) {
 		while (!need_resched())
 			idle();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/m68k/kernel/process_no.c b/arch/m68k/kernel/process_no.c
index 5e1078c..f7fe6c3 100644
--- a/arch/m68k/kernel/process_no.c
+++ b/arch/m68k/kernel/process_no.c
@@ -73,9 +73,7 @@
 	/* endless idle loop with no priority at all */
 	while (1) {
 		idle();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
index 7dcb5bf..9155f7d 100644
--- a/arch/microblaze/kernel/process.c
+++ b/arch/microblaze/kernel/process.c
@@ -110,9 +110,7 @@
 		rcu_idle_exit();
 		tick_nohz_idle_exit();
 
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 		check_pgt_cache();
 	}
 }
diff --git a/arch/mips/ath79/dev-usb.c b/arch/mips/ath79/dev-usb.c
index 002d6d2..36e9570 100644
--- a/arch/mips/ath79/dev-usb.c
+++ b/arch/mips/ath79/dev-usb.c
@@ -17,6 +17,8 @@
 #include <linux/irq.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
+#include <linux/usb/ehci_pdriver.h>
+#include <linux/usb/ohci_pdriver.h>
 
 #include <asm/mach-ath79/ath79.h>
 #include <asm/mach-ath79/ar71xx_regs.h>
@@ -36,14 +38,19 @@
 };
 
 static u64 ath79_ohci_dmamask = DMA_BIT_MASK(32);
+
+static struct usb_ohci_pdata ath79_ohci_pdata = {
+};
+
 static struct platform_device ath79_ohci_device = {
-	.name		= "ath79-ohci",
+	.name		= "ohci-platform",
 	.id		= -1,
 	.resource	= ath79_ohci_resources,
 	.num_resources	= ARRAY_SIZE(ath79_ohci_resources),
 	.dev = {
 		.dma_mask		= &ath79_ohci_dmamask,
 		.coherent_dma_mask	= DMA_BIT_MASK(32),
+		.platform_data		= &ath79_ohci_pdata,
 	},
 };
 
@@ -60,8 +67,20 @@
 };
 
 static u64 ath79_ehci_dmamask = DMA_BIT_MASK(32);
+
+static struct usb_ehci_pdata ath79_ehci_pdata_v1 = {
+	.has_synopsys_hc_bug	= 1,
+	.port_power_off		= 1,
+};
+
+static struct usb_ehci_pdata ath79_ehci_pdata_v2 = {
+	.caps_offset		= 0x100,
+	.has_tt			= 1,
+	.port_power_off		= 1,
+};
+
 static struct platform_device ath79_ehci_device = {
-	.name		= "ath79-ehci",
+	.name		= "ehci-platform",
 	.id		= -1,
 	.resource	= ath79_ehci_resources,
 	.num_resources	= ARRAY_SIZE(ath79_ehci_resources),
@@ -101,7 +120,7 @@
 
 	ath79_ehci_resources[0].start = AR71XX_EHCI_BASE;
 	ath79_ehci_resources[0].end = AR71XX_EHCI_BASE + AR71XX_EHCI_SIZE - 1;
-	ath79_ehci_device.name = "ar71xx-ehci";
+	ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v1;
 	platform_device_register(&ath79_ehci_device);
 }
 
@@ -142,7 +161,7 @@
 
 	ath79_ehci_resources[0].start = AR724X_EHCI_BASE;
 	ath79_ehci_resources[0].end = AR724X_EHCI_BASE + AR724X_EHCI_SIZE - 1;
-	ath79_ehci_device.name = "ar724x-ehci";
+	ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2;
 	platform_device_register(&ath79_ehci_device);
 }
 
@@ -159,7 +178,7 @@
 
 	ath79_ehci_resources[0].start = AR913X_EHCI_BASE;
 	ath79_ehci_resources[0].end = AR913X_EHCI_BASE + AR913X_EHCI_SIZE - 1;
-	ath79_ehci_device.name = "ar913x-ehci";
+	ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2;
 	platform_device_register(&ath79_ehci_device);
 }
 
@@ -176,7 +195,7 @@
 
 	ath79_ehci_resources[0].start = AR933X_EHCI_BASE;
 	ath79_ehci_resources[0].end = AR933X_EHCI_BASE + AR933X_EHCI_SIZE - 1;
-	ath79_ehci_device.name = "ar933x-ehci";
+	ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2;
 	platform_device_register(&ath79_ehci_device);
 }
 
diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h
index 1881b31..4d6d77e 100644
--- a/arch/mips/include/asm/jump_label.h
+++ b/arch/mips/include/asm/jump_label.h
@@ -20,7 +20,7 @@
 #define WORD_INSN ".word"
 #endif
 
-static __always_inline bool arch_static_branch(struct jump_label_key *key)
+static __always_inline bool arch_static_branch(struct static_key *key)
 {
 	asm goto("1:\tnop\n\t"
 		"nop\n\t"
diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c
index e3b897a..811084f 100644
--- a/arch/mips/kernel/perf_event_mipsxx.c
+++ b/arch/mips/kernel/perf_event_mipsxx.c
@@ -606,6 +606,10 @@
 {
 	int err = 0;
 
+	/* does not support taken branch sampling */
+	if (has_branch_stack(event))
+		return -EOPNOTSUPP;
+
 	switch (event->attr.type) {
 	case PERF_TYPE_RAW:
 	case PERF_TYPE_HARDWARE:
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 7955409..61f1cb4 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -80,9 +80,7 @@
 #endif
 		rcu_idle_exit();
 		tick_nohz_idle_exit();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c
index 28eec31..cac401d 100644
--- a/arch/mn10300/kernel/process.c
+++ b/arch/mn10300/kernel/process.c
@@ -123,9 +123,7 @@
 			idle();
 		}
 
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c
index fc770be..4f00459 100644
--- a/arch/parisc/kernel/pdc_cons.c
+++ b/arch/parisc/kernel/pdc_cons.c
@@ -90,11 +90,13 @@
 
 #define PDC_CONS_POLL_DELAY (30 * HZ / 1000)
 
-static struct timer_list pdc_console_timer;
+static void pdc_console_poll(unsigned long unused);
+static DEFINE_TIMER(pdc_console_timer, pdc_console_poll, 0, 0);
+static struct tty_port tty_port;
 
 static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp)
 {
-
+	tty_port_tty_set(&tty_port, tty);
 	mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
 
 	return 0;
@@ -102,8 +104,10 @@
 
 static void pdc_console_tty_close(struct tty_struct *tty, struct file *filp)
 {
-	if (!tty->count)
-		del_timer(&pdc_console_timer);
+	if (!tty->count) {
+		del_timer_sync(&pdc_console_timer);
+		tty_port_tty_set(&tty_port, NULL);
+	}
 }
 
 static int pdc_console_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -122,8 +126,6 @@
 	return 0; /* no buffer */
 }
 
-static struct tty_driver *pdc_console_tty_driver;
-
 static const struct tty_operations pdc_console_tty_ops = {
 	.open = pdc_console_tty_open,
 	.close = pdc_console_tty_close,
@@ -134,10 +136,8 @@
 
 static void pdc_console_poll(unsigned long unused)
 {
-
 	int data, count = 0;
-
-	struct tty_struct *tty = pdc_console_tty_driver->ttys[0];
+	struct tty_struct *tty = tty_port_tty_get(&tty_port);
 
 	if (!tty)
 		return;
@@ -153,15 +153,17 @@
 	if (count)
 		tty_flip_buffer_push(tty);
 
-	if (tty->count && (pdc_cons.flags & CON_ENABLED))
+	tty_kref_put(tty);
+
+	if (pdc_cons.flags & CON_ENABLED)
 		mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
 }
 
+static struct tty_driver *pdc_console_tty_driver;
+
 static int __init pdc_console_tty_driver_init(void)
 {
-
 	int err;
-	struct tty_driver *drv;
 
 	/* Check if the console driver is still registered.
 	 * It is unregistered if the pdc console was not selected as the
@@ -183,32 +185,29 @@
 	printk(KERN_INFO "The PDC console driver is still registered, removing CON_BOOT flag\n");
 	pdc_cons.flags &= ~CON_BOOT;
 
-	drv = alloc_tty_driver(1);
+	tty_port_init(&tty_port);
 
-	if (!drv)
+	pdc_console_tty_driver = alloc_tty_driver(1);
+
+	if (!pdc_console_tty_driver)
 		return -ENOMEM;
 
-	drv->driver_name = "pdc_cons";
-	drv->name = "ttyB";
-	drv->major = MUX_MAJOR;
-	drv->minor_start = 0;
-	drv->type = TTY_DRIVER_TYPE_SYSTEM;
-	drv->init_termios = tty_std_termios;
-	drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
-	tty_set_operations(drv, &pdc_console_tty_ops);
+	pdc_console_tty_driver->driver_name = "pdc_cons";
+	pdc_console_tty_driver->name = "ttyB";
+	pdc_console_tty_driver->major = MUX_MAJOR;
+	pdc_console_tty_driver->minor_start = 0;
+	pdc_console_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
+	pdc_console_tty_driver->init_termios = tty_std_termios;
+	pdc_console_tty_driver->flags = TTY_DRIVER_REAL_RAW |
+		TTY_DRIVER_RESET_TERMIOS;
+	tty_set_operations(pdc_console_tty_driver, &pdc_console_tty_ops);
 
-	err = tty_register_driver(drv);
+	err = tty_register_driver(pdc_console_tty_driver);
 	if (err) {
 		printk(KERN_ERR "Unable to register the PDC console TTY driver\n");
 		return err;
 	}
 
-	pdc_console_tty_driver = drv;
-
-	/* No need to initialize the pdc_console_timer if tty isn't allocated */
-	init_timer(&pdc_console_timer);
-	pdc_console_timer.function = pdc_console_poll;
-
 	return 0;
 }
 
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index 62c60b8..d4b94b3 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -71,9 +71,7 @@
 	while (1) {
 		while (!need_resched())
 			barrier();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 		check_pgt_cache();
 	}
 }
diff --git a/arch/powerpc/include/asm/jump_label.h b/arch/powerpc/include/asm/jump_label.h
index 938986e..ae098c4 100644
--- a/arch/powerpc/include/asm/jump_label.h
+++ b/arch/powerpc/include/asm/jump_label.h
@@ -17,7 +17,7 @@
 #define JUMP_ENTRY_TYPE		stringify_in_c(FTR_ENTRY_LONG)
 #define JUMP_LABEL_NOP_SIZE	4
 
-static __always_inline bool arch_static_branch(struct jump_label_key *key)
+static __always_inline bool arch_static_branch(struct static_key *key)
 {
 	asm goto("1:\n\t"
 		 "nop\n\t"
diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h
index 8f1df12..1a8093f 100644
--- a/arch/powerpc/include/asm/perf_event_server.h
+++ b/arch/powerpc/include/asm/perf_event_server.h
@@ -61,8 +61,6 @@
 extern unsigned long perf_misc_flags(struct pt_regs *regs);
 extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
 
-#define PERF_EVENT_INDEX_OFFSET	1
-
 /*
  * Only override the default definitions in include/linux/perf_event.h
  * if we have hardware PMU support.
diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c
index 0a48bf5..c97fc60 100644
--- a/arch/powerpc/kernel/idle.c
+++ b/arch/powerpc/kernel/idle.c
@@ -101,11 +101,11 @@
 		ppc64_runlatch_on();
 		rcu_idle_exit();
 		tick_nohz_idle_exit();
-		preempt_enable_no_resched();
-		if (cpu_should_die())
+		if (cpu_should_die()) {
+			sched_preempt_enable_no_resched();
 			cpu_die();
-		schedule();
-		preempt_disable();
+		}
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c
index 64483fd..c2e27ed 100644
--- a/arch/powerpc/kernel/perf_event.c
+++ b/arch/powerpc/kernel/perf_event.c
@@ -1084,6 +1084,10 @@
 	if (!ppmu)
 		return -ENOENT;
 
+	/* does not support taken branch sampling */
+	if (has_branch_stack(event))
+		return -EOPNOTSUPP;
+
 	switch (event->attr.type) {
 	case PERF_TYPE_HARDWARE:
 		ev = event->attr.config;
@@ -1193,6 +1197,11 @@
 	return err;
 }
 
+static int power_pmu_event_idx(struct perf_event *event)
+{
+	return event->hw.idx;
+}
+
 struct pmu power_pmu = {
 	.pmu_enable	= power_pmu_enable,
 	.pmu_disable	= power_pmu_disable,
@@ -1205,6 +1214,7 @@
 	.start_txn	= power_pmu_start_txn,
 	.cancel_txn	= power_pmu_cancel_txn,
 	.commit_txn	= power_pmu_commit_txn,
+	.event_idx	= power_pmu_event_idx,
 };
 
 /*
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 8fc6258..a5fbf4c 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -584,9 +584,7 @@
 		if (hvlpevent_is_pending())
 			process_iSeries_events();
 
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
@@ -615,9 +613,7 @@
 		ppc64_runlatch_on();
 		rcu_idle_exit();
 		tick_nohz_idle_exit();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/s390/include/asm/jump_label.h b/arch/s390/include/asm/jump_label.h
index 95a6cf2..6c32190 100644
--- a/arch/s390/include/asm/jump_label.h
+++ b/arch/s390/include/asm/jump_label.h
@@ -13,7 +13,7 @@
 #define ASM_ALIGN ".balign 4"
 #endif
 
-static __always_inline bool arch_static_branch(struct jump_label_key *key)
+static __always_inline bool arch_static_branch(struct static_key *key)
 {
 	asm goto("0:	brcl 0,0\n"
 		".pushsection __jump_table, \"aw\"\n"
diff --git a/arch/s390/include/asm/perf_event.h b/arch/s390/include/asm/perf_event.h
index a75f168..4eb444e 100644
--- a/arch/s390/include/asm/perf_event.h
+++ b/arch/s390/include/asm/perf_event.h
@@ -6,4 +6,3 @@
 
 /* Empty, just to avoid compiling error */
 
-#define PERF_EVENT_INDEX_OFFSET 0
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index b9a7fdd..e30b2df 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -165,13 +165,6 @@
 	return (code + (code >> 9)) & 0xff;
 }
 
-static void ext_int_hash_update(struct rcu_head *head)
-{
-	struct ext_int_info *p = container_of(head, struct ext_int_info, rcu);
-
-	kfree(p);
-}
-
 int register_external_interrupt(u16 code, ext_int_handler_t handler)
 {
 	struct ext_int_info *p;
@@ -202,7 +195,7 @@
 	list_for_each_entry_rcu(p, &ext_int_hash[index], entry)
 		if (p->code == code && p->handler == handler) {
 			list_del_rcu(&p->entry);
-			call_rcu(&p->rcu, ext_int_hash_update);
+			kfree_rcu(p, rcu);
 		}
 	spin_unlock_irqrestore(&ext_int_hash_lock, flags);
 	return 0;
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index e795933..7618085 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -97,9 +97,7 @@
 		tick_nohz_idle_exit();
 		if (test_thread_flag(TIF_MCCK_PENDING))
 			s390_handle_mcck();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 2398ce6..b0e28c4 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -550,12 +550,6 @@
 	S390_lowcore.restart_psw.addr =
 		PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler;
 	__ctl_set_bit(0, 28); /* Enable lowcore protection */
-	/*
-	 * Wait until the cpu which brought this one up marked it
-	 * active before enabling interrupts.
-	 */
-	while (!cpumask_test_cpu(smp_processor_id(), cpu_active_mask))
-		cpu_relax();
 	local_irq_enable();
 	/* cpu_idle will call schedule for us */
 	cpu_idle();
diff --git a/arch/score/kernel/process.c b/arch/score/kernel/process.c
index 25d0803..2707023 100644
--- a/arch/score/kernel/process.c
+++ b/arch/score/kernel/process.c
@@ -53,9 +53,7 @@
 		while (!need_resched())
 			barrier();
 
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/sh/kernel/cpu/sh2a/ex.S b/arch/sh/kernel/cpu/sh2a/ex.S
index 3ead9e6..4568066 100644
--- a/arch/sh/kernel/cpu/sh2a/ex.S
+++ b/arch/sh/kernel/cpu/sh2a/ex.S
@@ -66,6 +66,7 @@
 	.long	exception_entry0 + vector * 6
 vector	=	vector + 1
 	.endr
+vector	=	0
 	.rept	256
 	.long	exception_entry1 + vector * 6
 vector	=	vector + 1
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
index 0fbff14..0bd21c8 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
@@ -79,7 +79,7 @@
 #define MSTPCR1		0xffc80034
 #define MSTPCR2		0xffc10028
 
-enum { MSTP004, MSTP000, MSTP114, MSTP113, MSTP112,
+enum { MSTP004, MSTP000, MSTP127, MSTP114, MSTP113, MSTP112,
        MSTP111, MSTP110, MSTP103, MSTP102, MSTP220,
        MSTP_NR };
 
@@ -89,6 +89,7 @@
 	[MSTP000] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 0, 0),
 
 	/* MSTPCR1 */
+	[MSTP127] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 27, 0),
 	[MSTP114] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 14, 0),
 	[MSTP113] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 13, 0),
 	[MSTP112] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 12, 0),
@@ -131,6 +132,7 @@
 	CLKDEV_CON_ID("usb_fck", &mstp_clks[MSTP103]),
 	CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP102]),
 	CLKDEV_CON_ID("mmc0", &mstp_clks[MSTP220]),
+	CLKDEV_CON_ID("rspi2", &mstp_clks[MSTP127]),
 };
 
 int __init arch_clk_init(void)
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
index e5b420c..2b31443 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
@@ -156,7 +156,7 @@
 	CLKDEV_CON_ID("siof_fck", &mstp_clks[MSTP003]),
 	CLKDEV_CON_ID("hspi_fck", &mstp_clks[MSTP002]),
 	CLKDEV_CON_ID("hudi_fck", &mstp_clks[MSTP119]),
-	CLKDEV_CON_ID("ubc_fck", &mstp_clks[MSTP117]),
+	CLKDEV_CON_ID("ubc0", &mstp_clks[MSTP117]),
 	CLKDEV_CON_ID("dmac_11_6_fck", &mstp_clks[MSTP105]),
 	CLKDEV_CON_ID("dmac_5_0_fck", &mstp_clks[MSTP104]),
 	CLKDEV_CON_ID("gdta_fck", &mstp_clks[MSTP100]),
diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c
index 406508d..7e48928 100644
--- a/arch/sh/kernel/idle.c
+++ b/arch/sh/kernel/idle.c
@@ -114,9 +114,7 @@
 
 		rcu_idle_exit();
 		tick_nohz_idle_exit();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/sh/kernel/perf_event.c b/arch/sh/kernel/perf_event.c
index 10b14e3..068b8a2 100644
--- a/arch/sh/kernel/perf_event.c
+++ b/arch/sh/kernel/perf_event.c
@@ -310,6 +310,10 @@
 {
 	int err;
 
+	/* does not support taken branch sampling */
+	if (has_branch_stack(event))
+		return -EOPNOTSUPP;
+
 	switch (event->attr.type) {
 	case PERF_TYPE_RAW:
 	case PERF_TYPE_HW_CACHE:
diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile
index ad1fb5d..eddcfb3 100644
--- a/arch/sparc/Makefile
+++ b/arch/sparc/Makefile
@@ -31,7 +31,7 @@
 
 #KBUILD_CFLAGS += -g -pipe -fcall-used-g5 -fcall-used-g7
 KBUILD_CFLAGS += -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
-KBUILD_AFLAGS += -m32
+KBUILD_AFLAGS += -m32 -Wa,-Av8
 
 #LDFLAGS_vmlinux = -N -Ttext 0xf0004000
 #  Since 2.5.40, the first stage is left not btfix-ed.
diff --git a/arch/sparc/include/asm/jump_label.h b/arch/sparc/include/asm/jump_label.h
index fc73a82..5080d16 100644
--- a/arch/sparc/include/asm/jump_label.h
+++ b/arch/sparc/include/asm/jump_label.h
@@ -7,7 +7,7 @@
 
 #define JUMP_LABEL_NOP_SIZE 4
 
-static __always_inline bool arch_static_branch(struct jump_label_key *key)
+static __always_inline bool arch_static_branch(struct static_key *key)
 {
 		asm goto("1:\n\t"
 			 "nop\n\t"
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c
index 614da62..8e16a4a 100644
--- a/arch/sparc/kernel/perf_event.c
+++ b/arch/sparc/kernel/perf_event.c
@@ -1105,6 +1105,10 @@
 	if (atomic_read(&nmi_active) < 0)
 		return -ENODEV;
 
+	/* does not support taken branch sampling */
+	if (has_branch_stack(event))
+		return -EOPNOTSUPP;
+
 	switch (attr->type) {
 	case PERF_TYPE_HARDWARE:
 		if (attr->config >= sparc_pmu->max_events)
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
index f793742..935fdbc 100644
--- a/arch/sparc/kernel/process_32.c
+++ b/arch/sparc/kernel/process_32.c
@@ -113,9 +113,7 @@
 			while (!need_resched())
 				cpu_relax();
 		}
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 		check_pgt_cache();
 	}
 }
@@ -138,9 +136,7 @@
 			while (!need_resched())
 				cpu_relax();
 		}
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 		check_pgt_cache();
 	}
 }
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index 39d8b05..06b5b5f 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -104,15 +104,13 @@
 		rcu_idle_exit();
 		tick_nohz_idle_exit();
 
-		preempt_enable_no_resched();
-
 #ifdef CONFIG_HOTPLUG_CPU
-		if (cpu_is_offline(cpu))
+		if (cpu_is_offline(cpu)) {
+			sched_preempt_enable_no_resched();
 			cpu_play_dead();
+		}
 #endif
-
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/tile/configs/tilegx_defconfig b/arch/tile/configs/tilegx_defconfig
index dafdbba..b8d99ac 100644
--- a/arch/tile/configs/tilegx_defconfig
+++ b/arch/tile/configs/tilegx_defconfig
@@ -1,337 +1,93 @@
-#
-# Automatically generated make config: don't edit
-# Linux/tilegx 2.6.39-rc5 Kernel Configuration
-# Wed May  4 11:08:04 2011
-#
-CONFIG_TILE=y
-CONFIG_MMU=y
-CONFIG_GENERIC_CSUM=y
-CONFIG_SEMAPHORE_SLEEPERS=y
-CONFIG_HAVE_ARCH_ALLOC_REMAP=y
-CONFIG_HAVE_SETUP_PER_CPU_AREA=y
-CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
-CONFIG_SYS_SUPPORTS_HUGETLBFS=y
-CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_DEFAULT_MIGRATION_COST=10000000
-CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
-CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
-CONFIG_ARCH_DMA_ADDR_T_64BIT=y
-CONFIG_LOCKDEP_SUPPORT=y
-CONFIG_STACKTRACE_SUPPORT=y
-CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-CONFIG_STRICT_DEVMEM=y
-CONFIG_SMP=y
-# CONFIG_DEBUG_COPY_FROM_USER is not set
-CONFIG_HVC_TILE=y
 CONFIG_TILEGX=y
-CONFIG_64BIT=y
-CONFIG_ARCH_DEFCONFIG="arch/tile/configs/tilegx_defconfig"
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-CONFIG_CONSTRUCTORS=y
-
-#
-# General setup
-#
 CONFIG_EXPERIMENTAL=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-CONFIG_CROSS_COMPILE=""
-CONFIG_LOCALVERSION=""
 # CONFIG_LOCALVERSION_AUTO is not set
-CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
-CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BSD_PROCESS_ACCT_V3=y
-# CONFIG_FHANDLE is not set
+CONFIG_FHANDLE=y
 CONFIG_TASKSTATS=y
 CONFIG_TASK_DELAY_ACCT=y
 CONFIG_TASK_XACCT=y
 CONFIG_TASK_IO_ACCOUNTING=y
 CONFIG_AUDIT=y
-CONFIG_HAVE_GENERIC_HARDIRQS=y
-
-#
-# IRQ subsystem
-#
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_GENERIC_IRQ_SHOW=y
-CONFIG_GENERIC_PENDING_IRQ=y
-
-#
-# RCU Subsystem
-#
-CONFIG_TREE_RCU=y
-# CONFIG_PREEMPT_RCU is not set
-# CONFIG_RCU_TRACE is not set
-CONFIG_RCU_FANOUT=64
-# CONFIG_RCU_FANOUT_EXACT is not set
-# CONFIG_RCU_FAST_NO_HZ is not set
-# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=19
 CONFIG_CGROUPS=y
 CONFIG_CGROUP_DEBUG=y
-CONFIG_CGROUP_NS=y
-# CONFIG_CGROUP_FREEZER is not set
 CONFIG_CGROUP_DEVICE=y
 CONFIG_CPUSETS=y
-CONFIG_PROC_PID_CPUSET=y
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_RESOURCE_COUNTERS=y
 CONFIG_CGROUP_MEM_RES_CTLR=y
 CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
-CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED=y
 CONFIG_CGROUP_SCHED=y
-CONFIG_FAIR_GROUP_SCHED=y
 CONFIG_RT_GROUP_SCHED=y
 CONFIG_BLK_CGROUP=y
-# CONFIG_DEBUG_BLK_CGROUP is not set
 CONFIG_NAMESPACES=y
-CONFIG_UTS_NS=y
-CONFIG_IPC_NS=y
-CONFIG_USER_NS=y
-CONFIG_PID_NS=y
-CONFIG_NET_NS=y
-# CONFIG_SCHED_AUTOGROUP is not set
-CONFIG_MM_OWNER=y
-# CONFIG_SYSFS_DEPRECATED is not set
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="usr/contents.txt"
-CONFIG_INITRAMFS_ROOT_UID=0
-CONFIG_INITRAMFS_ROOT_GID=0
-CONFIG_RD_GZIP=y
-# CONFIG_RD_BZIP2 is not set
-# CONFIG_RD_LZMA is not set
-# CONFIG_RD_XZ is not set
-# CONFIG_RD_LZO is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
-# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SYSCTL=y
-CONFIG_ANON_INODES=y
-CONFIG_EXPERT=y
 CONFIG_SYSCTL_SYSCALL=y
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_ALL is not set
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_HOTPLUG=y
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
-CONFIG_SHMEM=y
-CONFIG_AIO=y
 CONFIG_EMBEDDED=y
-
-#
-# Kernel Performance Events And Counters
-#
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_PCI_QUIRKS=y
-CONFIG_SLUB_DEBUG=y
 # CONFIG_COMPAT_BRK is not set
-# CONFIG_SLAB is not set
-CONFIG_SLUB=y
-# CONFIG_SLOB is not set
 CONFIG_PROFILING=y
-CONFIG_USE_GENERIC_SMP_HELPERS=y
-
-#
-# GCOV-based kernel profiling
-#
-# CONFIG_GCOV_KERNEL is not set
-# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
-CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
-CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
 CONFIG_MODULE_FORCE_LOAD=y
 CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_STOP_MACHINE=y
-CONFIG_BLOCK=y
-CONFIG_BLK_DEV_BSG=y
 CONFIG_BLK_DEV_INTEGRITY=y
-# CONFIG_BLK_DEV_THROTTLING is not set
-CONFIG_BLOCK_COMPAT=y
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_SGI_PARTITION=y
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_EFI_PARTITION=y
 CONFIG_CFQ_GROUP_IOSCHED=y
-# CONFIG_DEFAULT_DEADLINE is not set
-CONFIG_DEFAULT_CFQ=y
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="cfq"
-CONFIG_PADATA=y
-# CONFIG_INLINE_SPIN_TRYLOCK is not set
-# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
-# CONFIG_INLINE_SPIN_LOCK is not set
-# CONFIG_INLINE_SPIN_LOCK_BH is not set
-# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
-# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
-CONFIG_INLINE_SPIN_UNLOCK=y
-# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
-CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
-# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
-# CONFIG_INLINE_READ_TRYLOCK is not set
-# CONFIG_INLINE_READ_LOCK is not set
-# CONFIG_INLINE_READ_LOCK_BH is not set
-# CONFIG_INLINE_READ_LOCK_IRQ is not set
-# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
-CONFIG_INLINE_READ_UNLOCK=y
-# CONFIG_INLINE_READ_UNLOCK_BH is not set
-CONFIG_INLINE_READ_UNLOCK_IRQ=y
-# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
-# CONFIG_INLINE_WRITE_TRYLOCK is not set
-# CONFIG_INLINE_WRITE_LOCK is not set
-# CONFIG_INLINE_WRITE_LOCK_BH is not set
-# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
-# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
-CONFIG_INLINE_WRITE_UNLOCK=y
-# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
-CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
-# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
-CONFIG_MUTEX_SPIN_ON_OWNER=y
-
-#
-# Tilera-specific configuration
-#
 CONFIG_NR_CPUS=100
-CONFIG_TICK_ONESHOT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
-CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 CONFIG_HZ_100=y
-# CONFIG_HZ_250 is not set
-# CONFIG_HZ_300 is not set
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=100
-CONFIG_SCHED_HRTICK=y
-# CONFIG_KEXEC is not set
-CONFIG_COMPAT=y
-CONFIG_SYSVIPC_COMPAT=y
-# CONFIG_HIGHMEM is not set
-CONFIG_NUMA=y
-CONFIG_NODES_SHIFT=2
-CONFIG_PAGE_OFFSET=0xC0000000
-CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_DISCONTIGMEM_MANUAL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-CONFIG_NEED_MULTIPLE_NODES=y
-CONFIG_PAGEFLAGS_EXTENDED=y
-CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_COMPACTION is not set
-CONFIG_MIGRATION=y
-CONFIG_PHYS_ADDR_T_64BIT=y
-CONFIG_ZONE_DMA_FLAG=0
-CONFIG_VIRT_TO_BUS=y
-# CONFIG_KSM is not set
-CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
-# CONFIG_CMDLINE_BOOL is not set
-CONFIG_VMALLOC_RESERVE=0x1000000
-CONFIG_HARDWALL=y
-CONFIG_KERNEL_PL=1
-
-#
-# Bus options
-#
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-# CONFIG_NO_IOMEM is not set
-# CONFIG_NO_IOPORT is not set
-# CONFIG_ARCH_SUPPORTS_MSI is not set
 CONFIG_PCI_DEBUG=y
-# CONFIG_PCI_STUB is not set
-# CONFIG_PCI_IOV is not set
-# CONFIG_HOTPLUG_PCI is not set
-
-#
-# Executable file formats
-#
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_COMPAT_BINFMT_ELF=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-# CONFIG_HAVE_AOUT is not set
 CONFIG_BINFMT_MISC=y
 CONFIG_NET=y
-
-#
-# Networking options
-#
 CONFIG_PACKET=y
 CONFIG_UNIX=y
-CONFIG_XFRM=y
 CONFIG_XFRM_USER=y
 CONFIG_XFRM_SUB_POLICY=y
-CONFIG_XFRM_MIGRATE=y
 CONFIG_XFRM_STATISTICS=y
-CONFIG_XFRM_IPCOMP=m
 CONFIG_NET_KEY=m
 CONFIG_NET_KEY_MIGRATE=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 CONFIG_IP_ADVANCED_ROUTER=y
-# CONFIG_IP_FIB_TRIE_STATS is not set
 CONFIG_IP_MULTIPLE_TABLES=y
 CONFIG_IP_ROUTE_MULTIPATH=y
 CONFIG_IP_ROUTE_VERBOSE=y
-CONFIG_IP_ROUTE_CLASSID=y
-# CONFIG_IP_PNP is not set
 CONFIG_NET_IPIP=m
-# CONFIG_NET_IPGRE_DEMUX is not set
 CONFIG_IP_MROUTE=y
-# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set
 CONFIG_IP_PIMSM_V1=y
 CONFIG_IP_PIMSM_V2=y
-# CONFIG_ARPD is not set
 CONFIG_SYN_COOKIES=y
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
-CONFIG_INET_XFRM_TUNNEL=m
-CONFIG_INET_TUNNEL=m
 CONFIG_INET_XFRM_MODE_TRANSPORT=m
 CONFIG_INET_XFRM_MODE_TUNNEL=m
 CONFIG_INET_XFRM_MODE_BEET=m
-CONFIG_INET_LRO=y
 CONFIG_INET_DIAG=m
-CONFIG_INET_TCP_DIAG=m
 CONFIG_TCP_CONG_ADVANCED=y
-CONFIG_TCP_CONG_BIC=m
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_TCP_CONG_WESTWOOD=m
-CONFIG_TCP_CONG_HTCP=m
 CONFIG_TCP_CONG_HSTCP=m
 CONFIG_TCP_CONG_HYBLA=m
-CONFIG_TCP_CONG_VEGAS=m
 CONFIG_TCP_CONG_SCALABLE=m
 CONFIG_TCP_CONG_LP=m
 CONFIG_TCP_CONG_VENO=m
 CONFIG_TCP_CONG_YEAH=m
 CONFIG_TCP_CONG_ILLINOIS=m
-CONFIG_DEFAULT_CUBIC=y
-# CONFIG_DEFAULT_RENO is not set
-CONFIG_DEFAULT_TCP_CONG="cubic"
 CONFIG_TCP_MD5SIG=y
 CONFIG_IPV6=y
 CONFIG_IPV6_PRIVACY=y
@@ -342,108 +98,60 @@
 CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
 CONFIG_IPV6_MIP6=m
-CONFIG_INET6_XFRM_TUNNEL=m
-CONFIG_INET6_TUNNEL=m
 CONFIG_INET6_XFRM_MODE_TRANSPORT=m
 CONFIG_INET6_XFRM_MODE_TUNNEL=m
 CONFIG_INET6_XFRM_MODE_BEET=m
 CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
 CONFIG_IPV6_SIT=m
-# CONFIG_IPV6_SIT_6RD is not set
-CONFIG_IPV6_NDISC_NODETYPE=y
 CONFIG_IPV6_TUNNEL=m
 CONFIG_IPV6_MULTIPLE_TABLES=y
-# CONFIG_IPV6_SUBTREES is not set
 CONFIG_IPV6_MROUTE=y
-# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set
 CONFIG_IPV6_PIMSM_V2=y
 CONFIG_NETLABEL=y
-CONFIG_NETWORK_SECMARK=y
-# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
 CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-CONFIG_NETFILTER_ADVANCED=y
-CONFIG_BRIDGE_NETFILTER=y
-
-#
-# Core Netfilter Configuration
-#
-CONFIG_NETFILTER_NETLINK=m
-CONFIG_NETFILTER_NETLINK_QUEUE=m
-CONFIG_NETFILTER_NETLINK_LOG=m
-CONFIG_NF_CONNTRACK=y
-CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_ZONES=y
 CONFIG_NF_CONNTRACK_EVENTS=y
-# CONFIG_NF_CONNTRACK_TIMESTAMP is not set
 CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_GRE=m
-CONFIG_NF_CT_PROTO_SCTP=m
 CONFIG_NF_CT_PROTO_UDPLITE=m
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
 CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_BROADCAST=m
 CONFIG_NF_CONNTRACK_NETBIOS_NS=m
-# CONFIG_NF_CONNTRACK_SNMP is not set
 CONFIG_NF_CONNTRACK_PPTP=m
 CONFIG_NF_CONNTRACK_SANE=m
 CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
-# CONFIG_NF_CT_NETLINK is not set
 CONFIG_NETFILTER_TPROXY=m
-CONFIG_NETFILTER_XTABLES=y
-
-#
-# Xtables combined modules
-#
-CONFIG_NETFILTER_XT_MARK=m
-CONFIG_NETFILTER_XT_CONNMARK=m
-
-#
-# Xtables targets
-#
-# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set
-# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
 CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
 CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
 CONFIG_NETFILTER_XT_TARGET_CT=m
 CONFIG_NETFILTER_XT_TARGET_DSCP=m
-CONFIG_NETFILTER_XT_TARGET_HL=m
 CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
 CONFIG_NETFILTER_XT_TARGET_MARK=m
 CONFIG_NETFILTER_XT_TARGET_NFLOG=m
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
 CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
-CONFIG_NETFILTER_XT_TARGET_RATEEST=m
 CONFIG_NETFILTER_XT_TARGET_TEE=m
 CONFIG_NETFILTER_XT_TARGET_TPROXY=m
 CONFIG_NETFILTER_XT_TARGET_TRACE=m
 CONFIG_NETFILTER_XT_TARGET_SECMARK=m
 CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
 CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
-
-#
-# Xtables matches
-#
-# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
 CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
 CONFIG_NETFILTER_XT_MATCH_COMMENT=m
 CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
-# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
 CONFIG_NETFILTER_XT_MATCH_DCCP=m
-# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
 CONFIG_NETFILTER_XT_MATCH_DSCP=m
 CONFIG_NETFILTER_XT_MATCH_ESP=m
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
 CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_HL=m
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
 CONFIG_NETFILTER_XT_MATCH_IPVS=m
 CONFIG_NETFILTER_XT_MATCH_LENGTH=m
@@ -460,55 +168,29 @@
 CONFIG_NETFILTER_XT_MATCH_RATEEST=m
 CONFIG_NETFILTER_XT_MATCH_REALM=m
 CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SCTP=m
 CONFIG_NETFILTER_XT_MATCH_SOCKET=m
-CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATE=m
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
 CONFIG_NETFILTER_XT_MATCH_STRING=m
 CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 CONFIG_NETFILTER_XT_MATCH_TIME=m
 CONFIG_NETFILTER_XT_MATCH_U32=m
-# CONFIG_IP_SET is not set
 CONFIG_IP_VS=m
 CONFIG_IP_VS_IPV6=y
-# CONFIG_IP_VS_DEBUG is not set
-CONFIG_IP_VS_TAB_BITS=12
-
-#
-# IPVS transport protocol load balancing support
-#
 CONFIG_IP_VS_PROTO_TCP=y
 CONFIG_IP_VS_PROTO_UDP=y
-CONFIG_IP_VS_PROTO_AH_ESP=y
 CONFIG_IP_VS_PROTO_ESP=y
 CONFIG_IP_VS_PROTO_AH=y
 CONFIG_IP_VS_PROTO_SCTP=y
-
-#
-# IPVS scheduler
-#
 CONFIG_IP_VS_RR=m
 CONFIG_IP_VS_WRR=m
 CONFIG_IP_VS_LC=m
 CONFIG_IP_VS_WLC=m
 CONFIG_IP_VS_LBLC=m
 CONFIG_IP_VS_LBLCR=m
-# CONFIG_IP_VS_DH is not set
-# CONFIG_IP_VS_SH is not set
 CONFIG_IP_VS_SED=m
 CONFIG_IP_VS_NQ=m
-
-#
-# IPVS application helper
-#
-# CONFIG_IP_VS_NFCT is not set
-# CONFIG_IP_VS_PE_SIP is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_NF_DEFRAG_IPV4=y
-CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=m
 # CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=y
@@ -519,9 +201,7 @@
 CONFIG_IP_NF_TARGET_REJECT=y
 CONFIG_IP_NF_TARGET_LOG=m
 CONFIG_IP_NF_TARGET_ULOG=m
-# CONFIG_NF_NAT is not set
 CONFIG_IP_NF_MANGLE=m
-# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_TTL=m
 CONFIG_IP_NF_RAW=m
@@ -529,11 +209,6 @@
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-
-#
-# IPv6: Netfilter Configuration
-#
-CONFIG_NF_DEFRAG_IPV6=m
 CONFIG_NF_CONNTRACK_IPV6=m
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -574,57 +249,20 @@
 CONFIG_BRIDGE_EBT_LOG=m
 CONFIG_BRIDGE_EBT_ULOG=m
 CONFIG_BRIDGE_EBT_NFLOG=m
-# CONFIG_IP_DCCP is not set
-CONFIG_IP_SCTP=m
-# CONFIG_SCTP_DBG_MSG is not set
-# CONFIG_SCTP_DBG_OBJCNT is not set
-# CONFIG_SCTP_HMAC_NONE is not set
-# CONFIG_SCTP_HMAC_SHA1 is not set
-CONFIG_SCTP_HMAC_MD5=y
 CONFIG_RDS=m
 CONFIG_RDS_TCP=m
-# CONFIG_RDS_DEBUG is not set
-# CONFIG_TIPC is not set
-# CONFIG_ATM is not set
-# CONFIG_L2TP is not set
-CONFIG_STP=m
-CONFIG_GARP=m
 CONFIG_BRIDGE=m
-CONFIG_BRIDGE_IGMP_SNOOPING=y
 CONFIG_NET_DSA=y
-CONFIG_NET_DSA_TAG_DSA=y
-CONFIG_NET_DSA_TAG_EDSA=y
-CONFIG_NET_DSA_TAG_TRAILER=y
-CONFIG_NET_DSA_MV88E6XXX=y
-CONFIG_NET_DSA_MV88E6060=y
-CONFIG_NET_DSA_MV88E6XXX_NEED_PPU=y
-CONFIG_NET_DSA_MV88E6131=y
-CONFIG_NET_DSA_MV88E6123_61_65=y
 CONFIG_VLAN_8021Q=m
 CONFIG_VLAN_8021Q_GVRP=y
-# CONFIG_DECNET is not set
-CONFIG_LLC=m
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
 CONFIG_PHONET=m
-# CONFIG_IEEE802154 is not set
 CONFIG_NET_SCHED=y
-
-#
-# Queueing/Scheduling
-#
 CONFIG_NET_SCH_CBQ=m
 CONFIG_NET_SCH_HTB=m
 CONFIG_NET_SCH_HFSC=m
 CONFIG_NET_SCH_PRIO=m
 CONFIG_NET_SCH_MULTIQ=m
 CONFIG_NET_SCH_RED=m
-# CONFIG_NET_SCH_SFB is not set
 CONFIG_NET_SCH_SFQ=m
 CONFIG_NET_SCH_TEQL=m
 CONFIG_NET_SCH_TBF=m
@@ -632,14 +270,7 @@
 CONFIG_NET_SCH_DSMARK=m
 CONFIG_NET_SCH_NETEM=m
 CONFIG_NET_SCH_DRR=m
-# CONFIG_NET_SCH_MQPRIO is not set
-# CONFIG_NET_SCH_CHOKE is not set
 CONFIG_NET_SCH_INGRESS=m
-
-#
-# Classification
-#
-CONFIG_NET_CLS=y
 CONFIG_NET_CLS_BASIC=m
 CONFIG_NET_CLS_TCINDEX=m
 CONFIG_NET_CLS_ROUTE4=m
@@ -652,7 +283,6 @@
 CONFIG_NET_CLS_FLOW=m
 CONFIG_NET_CLS_CGROUP=y
 CONFIG_NET_EMATCH=y
-CONFIG_NET_EMATCH_STACK=32
 CONFIG_NET_EMATCH_CMP=m
 CONFIG_NET_EMATCH_NBYTE=m
 CONFIG_NET_EMATCH_U32=m
@@ -668,307 +298,46 @@
 CONFIG_NET_ACT_PEDIT=m
 CONFIG_NET_ACT_SIMP=m
 CONFIG_NET_ACT_SKBEDIT=m
-# CONFIG_NET_ACT_CSUM is not set
 CONFIG_NET_CLS_IND=y
-CONFIG_NET_SCH_FIFO=y
 CONFIG_DCB=y
-CONFIG_DNS_RESOLVER=y
-# CONFIG_BATMAN_ADV is not set
-CONFIG_RPS=y
-CONFIG_RFS_ACCEL=y
-CONFIG_XPS=y
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_CAN is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_AF_RXRPC is not set
-CONFIG_FIB_RULES=y
 # CONFIG_WIRELESS is not set
-# CONFIG_WIMAX is not set
-# CONFIG_RFKILL is not set
-# CONFIG_NET_9P is not set
-# CONFIG_CAIF is not set
-# CONFIG_CEPH_LIB is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=y
 # CONFIG_FIRMWARE_IN_KERNEL is not set
-CONFIG_EXTRA_FIRMWARE=""
-# CONFIG_DEBUG_DRIVER is not set
-# CONFIG_DEBUG_DEVRES is not set
-# CONFIG_SYS_HYPERVISOR is not set
 CONFIG_CONNECTOR=y
-CONFIG_PROC_EVENTS=y
-# CONFIG_MTD is not set
-# CONFIG_PARPORT is not set
-CONFIG_BLK_DEV=y
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
-# CONFIG_BLK_DEV_DRBD is not set
-# CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_SX8=m
 CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=16384
-# CONFIG_BLK_DEV_XIP is not set
-# CONFIG_CDROM_PKTCDVD is not set
-CONFIG_ATA_OVER_ETH=y
-# CONFIG_BLK_DEV_RBD is not set
-# CONFIG_SENSORS_LIS3LV02D is not set
-CONFIG_MISC_DEVICES=y
-# CONFIG_AD525X_DPOT is not set
-# CONFIG_PHANTOM is not set
-# CONFIG_SGI_IOC4 is not set
-# CONFIG_TIFM_CORE is not set
-# CONFIG_ICS932S401 is not set
-# CONFIG_ENCLOSURE_SERVICES is not set
-# CONFIG_HP_ILO is not set
-# CONFIG_APDS9802ALS is not set
-# CONFIG_ISL29003 is not set
-# CONFIG_ISL29020 is not set
-# CONFIG_SENSORS_TSL2550 is not set
-# CONFIG_SENSORS_BH1780 is not set
-# CONFIG_SENSORS_BH1770 is not set
-# CONFIG_SENSORS_APDS990X is not set
-# CONFIG_HMC6352 is not set
-# CONFIG_DS1682 is not set
-# CONFIG_BMP085 is not set
-# CONFIG_PCH_PHUB is not set
-# CONFIG_C2PORT is not set
-
-#
-# EEPROM support
-#
-# CONFIG_EEPROM_AT24 is not set
-# CONFIG_EEPROM_LEGACY is not set
-# CONFIG_EEPROM_MAX6875 is not set
-# CONFIG_EEPROM_93CX6 is not set
-# CONFIG_CB710_CORE is not set
-
-#
-# Texas Instruments shared transport line discipline
-#
-# CONFIG_SENSORS_LIS3_I2C is not set
-
-#
-# SCSI device support
-#
-CONFIG_SCSI_MOD=m
+CONFIG_ATA_OVER_ETH=m
 CONFIG_RAID_ATTRS=m
-CONFIG_SCSI=m
-CONFIG_SCSI_DMA=y
 CONFIG_SCSI_TGT=m
-# CONFIG_SCSI_NETLINK is not set
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=m
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_CHR_DEV_SCH is not set
-# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_BLK_DEV_SD=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
-# CONFIG_SCSI_SCAN_ASYNC is not set
-CONFIG_SCSI_WAIT_SCAN=m
-
-#
-# SCSI Transports
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-CONFIG_SCSI_SAS_ATTRS=m
-# CONFIG_SCSI_SAS_LIBSAS is not set
-# CONFIG_SCSI_SRP_ATTRS is not set
-CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_ISCSI_BOOT_SYSFS is not set
-# CONFIG_SCSI_CXGB3_ISCSI is not set
-# CONFIG_SCSI_CXGB4_ISCSI is not set
-# CONFIG_SCSI_BNX2_ISCSI is not set
-# CONFIG_SCSI_BNX2X_FCOE is not set
-# CONFIG_BE2ISCSI is not set
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_HPSA is not set
-# CONFIG_SCSI_3W_9XXX is not set
-# CONFIG_SCSI_3W_SAS is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_AIC94XX is not set
-# CONFIG_SCSI_MVSAS is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_ARCMSR is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_MPT2SAS is not set
-# CONFIG_SCSI_HPTIOP is not set
-# CONFIG_LIBFC is not set
-# CONFIG_LIBFCOE is not set
-# CONFIG_FCOE is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_STEX is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLA_FC is not set
-# CONFIG_SCSI_QLA_ISCSI is not set
-# CONFIG_SCSI_LPFC is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_PMCRAID is not set
-# CONFIG_SCSI_PM8001 is not set
-# CONFIG_SCSI_SRP is not set
-# CONFIG_SCSI_BFA_FC is not set
-# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
-# CONFIG_SCSI_DH is not set
-# CONFIG_SCSI_OSD_INITIATOR is not set
-CONFIG_ATA=m
-# CONFIG_ATA_NONSTANDARD is not set
-CONFIG_ATA_VERBOSE_ERROR=y
-CONFIG_SATA_PMP=y
-
-#
-# Controllers with non-SFF native interface
-#
-# CONFIG_SATA_AHCI is not set
-# CONFIG_SATA_AHCI_PLATFORM is not set
-# CONFIG_SATA_INIC162X is not set
-# CONFIG_SATA_ACARD_AHCI is not set
-CONFIG_SATA_SIL24=m
-CONFIG_ATA_SFF=y
-
-#
-# SFF controllers with custom DMA interface
-#
-# CONFIG_PDC_ADMA is not set
-# CONFIG_SATA_QSTOR is not set
-# CONFIG_SATA_SX4 is not set
-CONFIG_ATA_BMDMA=y
-
-#
-# SATA SFF controllers with BMDMA
-#
-# CONFIG_ATA_PIIX is not set
-# CONFIG_SATA_MV is not set
-# CONFIG_SATA_NV is not set
-# CONFIG_SATA_PROMISE is not set
-# CONFIG_SATA_SIL is not set
-# CONFIG_SATA_SIS is not set
-# CONFIG_SATA_SVW is not set
-# CONFIG_SATA_ULI is not set
-# CONFIG_SATA_VIA is not set
-# CONFIG_SATA_VITESSE is not set
-
-#
-# PATA SFF controllers with BMDMA
-#
-# CONFIG_PATA_ALI is not set
-# CONFIG_PATA_AMD is not set
-# CONFIG_PATA_ARASAN_CF is not set
-# CONFIG_PATA_ARTOP is not set
-# CONFIG_PATA_ATIIXP is not set
-# CONFIG_PATA_ATP867X is not set
-# CONFIG_PATA_CMD64X is not set
-# CONFIG_PATA_CS5520 is not set
-# CONFIG_PATA_CS5530 is not set
-# CONFIG_PATA_CS5536 is not set
-# CONFIG_PATA_CYPRESS is not set
-# CONFIG_PATA_EFAR is not set
-# CONFIG_PATA_HPT366 is not set
-# CONFIG_PATA_HPT37X is not set
-# CONFIG_PATA_HPT3X2N is not set
-# CONFIG_PATA_HPT3X3 is not set
-# CONFIG_PATA_IT8213 is not set
-# CONFIG_PATA_IT821X is not set
-# CONFIG_PATA_JMICRON is not set
-# CONFIG_PATA_MARVELL is not set
-# CONFIG_PATA_NETCELL is not set
-# CONFIG_PATA_NINJA32 is not set
-# CONFIG_PATA_NS87415 is not set
-# CONFIG_PATA_OLDPIIX is not set
-# CONFIG_PATA_OPTIDMA is not set
-# CONFIG_PATA_PDC2027X is not set
-# CONFIG_PATA_PDC_OLD is not set
-# CONFIG_PATA_RADISYS is not set
-# CONFIG_PATA_RDC is not set
-# CONFIG_PATA_SC1200 is not set
-# CONFIG_PATA_SCH is not set
-# CONFIG_PATA_SERVERWORKS is not set
-# CONFIG_PATA_SIL680 is not set
-# CONFIG_PATA_SIS is not set
-# CONFIG_PATA_TOSHIBA is not set
-# CONFIG_PATA_TRIFLEX is not set
-# CONFIG_PATA_VIA is not set
-# CONFIG_PATA_WINBOND is not set
-
-#
-# PIO-only SFF controllers
-#
-# CONFIG_PATA_CMD640_PCI is not set
-# CONFIG_PATA_MPIIX is not set
-# CONFIG_PATA_NS87410 is not set
-# CONFIG_PATA_OPTI is not set
-# CONFIG_PATA_PLATFORM is not set
-# CONFIG_PATA_RZ1000 is not set
-
-#
-# Generic fallback / legacy drivers
-#
-# CONFIG_ATA_GENERIC is not set
-# CONFIG_PATA_LEGACY is not set
+CONFIG_SCSI_SAS_ATA=y
+CONFIG_SCSI_MVSAS=y
+# CONFIG_SCSI_MVSAS_DEBUG is not set
+CONFIG_SCSI_MVSAS_TASKLET=y
+CONFIG_ATA=y
+CONFIG_SATA_SIL24=y
+# CONFIG_ATA_SFF is not set
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=y
-CONFIG_MD_AUTODETECT=y
 CONFIG_MD_LINEAR=m
 CONFIG_MD_RAID0=m
 CONFIG_MD_RAID1=m
 CONFIG_MD_RAID10=m
 CONFIG_MD_RAID456=m
 CONFIG_MULTICORE_RAID456=y
-# CONFIG_MD_MULTIPATH is not set
 CONFIG_MD_FAULTY=m
 CONFIG_BLK_DEV_DM=m
 CONFIG_DM_DEBUG=y
 CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
-# CONFIG_DM_RAID is not set
 CONFIG_DM_LOG_USERSPACE=m
 CONFIG_DM_ZERO=m
 CONFIG_DM_MULTIPATH=m
@@ -976,558 +345,143 @@
 CONFIG_DM_MULTIPATH_ST=m
 CONFIG_DM_DELAY=m
 CONFIG_DM_UEVENT=y
-# CONFIG_DM_FLAKEY is not set
-# CONFIG_TARGET_CORE is not set
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_FIREWIRE is not set
-# CONFIG_FIREWIRE_NOSY is not set
-# CONFIG_I2O is not set
+CONFIG_FUSION=y
+CONFIG_FUSION_SAS=y
 CONFIG_NETDEVICES=y
-CONFIG_IFB=m
-CONFIG_DUMMY=m
 CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_IFB=m
 CONFIG_MACVLAN=m
 CONFIG_MACVTAP=m
-# CONFIG_EQUALIZER is not set
+CONFIG_NETCONSOLE=m
+CONFIG_NETCONSOLE_DYNAMIC=y
+CONFIG_NETPOLL_TRAP=y
 CONFIG_TUN=y
 CONFIG_VETH=m
-# CONFIG_ARCNET is not set
-# CONFIG_MII is not set
-CONFIG_PHYLIB=y
-
-#
-# MII PHY device drivers
-#
-# CONFIG_MARVELL_PHY is not set
-# CONFIG_DAVICOM_PHY is not set
-# CONFIG_QSEMI_PHY is not set
-# CONFIG_LXT_PHY is not set
-# CONFIG_CICADA_PHY is not set
-# CONFIG_VITESSE_PHY is not set
-# CONFIG_SMSC_PHY is not set
-# CONFIG_BROADCOM_PHY is not set
-# CONFIG_BCM63XX_PHY is not set
-# CONFIG_ICPLUS_PHY is not set
-# CONFIG_REALTEK_PHY is not set
-# CONFIG_NATIONAL_PHY is not set
-# CONFIG_STE10XP is not set
-# CONFIG_LSI_ET1011C_PHY is not set
-# CONFIG_MICREL_PHY is not set
-# CONFIG_FIXED_PHY is not set
-# CONFIG_MDIO_BITBANG is not set
-# CONFIG_NET_ETHERNET is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-CONFIG_E1000E=m
-# CONFIG_IP1000 is not set
-# CONFIG_IGB is not set
-# CONFIG_IGBVF is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
-# CONFIG_SKGE is not set
-# CONFIG_SKY2 is not set
-# CONFIG_VIA_VELOCITY is not set
-# CONFIG_TIGON3 is not set
-# CONFIG_BNX2 is not set
-# CONFIG_CNIC is not set
-# CONFIG_QLA3XXX is not set
-# CONFIG_ATL1 is not set
-# CONFIG_ATL1E is not set
-# CONFIG_ATL1C is not set
-# CONFIG_JME is not set
-# CONFIG_STMMAC_ETH is not set
-# CONFIG_PCH_GBE is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_TR is not set
-# CONFIG_WLAN is not set
-
-#
-# Enable WiMAX (Networking options) to see the WiMAX drivers
-#
-# CONFIG_WAN is not set
-
-#
-# CAIF transport drivers
-#
+CONFIG_NET_DSA_MV88E6060=y
+CONFIG_NET_DSA_MV88E6131=y
+CONFIG_NET_DSA_MV88E6123_61_65=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_NET_VENDOR_DEC is not set
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+# CONFIG_NET_VENDOR_HP is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_REALTEK is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
 # CONFIG_TILE_NET is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_NET_FC is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_VMXNET3 is not set
-# CONFIG_ISDN is not set
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_POLLDEV is not set
-# CONFIG_INPUT_SPARSEKMAP is not set
-
-#
-# Userland interfaces
-#
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
 # CONFIG_SERIO is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
 # CONFIG_VT is not set
-CONFIG_UNIX98_PTYS=y
-# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_NOZOMI is not set
-# CONFIG_N_GSM is not set
-CONFIG_DEVKMEM=y
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-# CONFIG_SERIAL_MFD_HSU is not set
-# CONFIG_SERIAL_JSM is not set
-# CONFIG_SERIAL_TIMBERDALE is not set
-# CONFIG_SERIAL_ALTERA_JTAGUART is not set
-# CONFIG_SERIAL_ALTERA_UART is not set
-# CONFIG_SERIAL_PCH_UART is not set
-# CONFIG_TTY_PRINTK is not set
-CONFIG_HVC_DRIVER=y
-# CONFIG_IPMI_HANDLER is not set
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_TIMERIOMEM=m
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# PCMCIA character devices
-#
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_TCG_TPM is not set
-CONFIG_DEVPORT=y
-# CONFIG_RAMOOPS is not set
 CONFIG_I2C=y
-CONFIG_I2C_BOARDINFO=y
-CONFIG_I2C_COMPAT=y
 CONFIG_I2C_CHARDEV=y
-# CONFIG_I2C_MUX is not set
-CONFIG_I2C_HELPER_AUTO=y
-
-#
-# I2C Hardware Bus support
-#
-
-#
-# PC SMBus host controller drivers
-#
-# CONFIG_I2C_ALI1535 is not set
-# CONFIG_I2C_ALI1563 is not set
-# CONFIG_I2C_ALI15X3 is not set
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-# CONFIG_I2C_I801 is not set
-# CONFIG_I2C_ISCH is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_SIS5595 is not set
-# CONFIG_I2C_SIS630 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_VIA is not set
-# CONFIG_I2C_VIAPRO is not set
-
-#
-# I2C system bus drivers (mostly embedded / system-on-chip)
-#
-# CONFIG_I2C_INTEL_MID is not set
-# CONFIG_I2C_OCORES is not set
-# CONFIG_I2C_PCA_PLATFORM is not set
-# CONFIG_I2C_PXA_PCI is not set
-# CONFIG_I2C_SIMTEC is not set
-# CONFIG_I2C_XILINX is not set
-# CONFIG_I2C_EG20T is not set
-
-#
-# External I2C/SMBus adapter drivers
-#
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_TAOS_EVM is not set
-
-#
-# Other I2C/SMBus bus drivers
-#
-# CONFIG_I2C_STUB is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_SPI is not set
-
-#
-# PPS support
-#
-# CONFIG_PPS is not set
-
-#
-# PPS generators support
-#
-# CONFIG_W1 is not set
-# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
-# CONFIG_THERMAL is not set
-# CONFIG_WATCHDOG is not set
-CONFIG_SSB_POSSIBLE=y
-
-#
-# Sonics Silicon Backplane
-#
-# CONFIG_SSB is not set
-CONFIG_MFD_SUPPORT=y
-# CONFIG_MFD_CORE is not set
-# CONFIG_MFD_88PM860X is not set
-# CONFIG_MFD_SM501 is not set
-# CONFIG_HTC_PASIC3 is not set
-# CONFIG_TPS6105X is not set
-# CONFIG_TPS6507X is not set
-# CONFIG_TWL4030_CORE is not set
-# CONFIG_MFD_STMPE is not set
-# CONFIG_MFD_TC3589X is not set
-# CONFIG_MFD_TMIO is not set
-# CONFIG_PMIC_DA903X is not set
-# CONFIG_PMIC_ADP5520 is not set
-# CONFIG_MFD_MAX8925 is not set
-# CONFIG_MFD_MAX8997 is not set
-# CONFIG_MFD_MAX8998 is not set
-# CONFIG_MFD_WM8400 is not set
-# CONFIG_MFD_WM831X_I2C is not set
-# CONFIG_MFD_WM8350_I2C is not set
-# CONFIG_MFD_WM8994 is not set
-# CONFIG_MFD_PCF50633 is not set
-# CONFIG_ABX500_CORE is not set
-# CONFIG_LPC_SCH is not set
-# CONFIG_MFD_RDC321X is not set
-# CONFIG_MFD_JANZ_CMODIO is not set
-# CONFIG_MFD_VX855 is not set
-# CONFIG_MFD_WL1273_CORE is not set
-# CONFIG_REGULATOR is not set
-# CONFIG_MEDIA_SUPPORT is not set
-
-#
-# Graphics support
-#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
 # CONFIG_VGA_ARB is not set
-# CONFIG_DRM is not set
-# CONFIG_STUB_POULSBO is not set
-# CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Display device support
-#
-# CONFIG_DISPLAY_SUPPORT is not set
-# CONFIG_SOUND is not set
 # CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-# CONFIG_UWB is not set
-# CONFIG_MMC is not set
-# CONFIG_MEMSTICK is not set
-# CONFIG_NEW_LEDS is not set
-# CONFIG_NFC_DEVICES is not set
-# CONFIG_ACCESSIBILITY is not set
-# CONFIG_INFINIBAND is not set
-# CONFIG_EDAC is not set
-CONFIG_RTC_LIB=y
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_EDAC=y
+CONFIG_EDAC_MM_EDAC=y
 CONFIG_RTC_CLASS=y
-CONFIG_RTC_HCTOSYS=y
-CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-# CONFIG_RTC_DEBUG is not set
-
-#
-# RTC interfaces
-#
-CONFIG_RTC_INTF_SYSFS=y
-CONFIG_RTC_INTF_PROC=y
-CONFIG_RTC_INTF_DEV=y
-# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
-# CONFIG_RTC_DRV_TEST is not set
-
-#
-# I2C RTC drivers
-#
-# CONFIG_RTC_DRV_DS1307 is not set
-# CONFIG_RTC_DRV_DS1374 is not set
-# CONFIG_RTC_DRV_DS1672 is not set
-# CONFIG_RTC_DRV_DS3232 is not set
-# CONFIG_RTC_DRV_MAX6900 is not set
-# CONFIG_RTC_DRV_RS5C372 is not set
-# CONFIG_RTC_DRV_ISL1208 is not set
-# CONFIG_RTC_DRV_ISL12022 is not set
-# CONFIG_RTC_DRV_X1205 is not set
-# CONFIG_RTC_DRV_PCF8563 is not set
-# CONFIG_RTC_DRV_PCF8583 is not set
-# CONFIG_RTC_DRV_M41T80 is not set
-# CONFIG_RTC_DRV_BQ32K is not set
-# CONFIG_RTC_DRV_S35390A is not set
-# CONFIG_RTC_DRV_FM3130 is not set
-# CONFIG_RTC_DRV_RX8581 is not set
-# CONFIG_RTC_DRV_RX8025 is not set
-
-#
-# SPI RTC drivers
-#
-
-#
-# Platform RTC drivers
-#
-# CONFIG_RTC_DRV_DS1286 is not set
-# CONFIG_RTC_DRV_DS1511 is not set
-# CONFIG_RTC_DRV_DS1553 is not set
-# CONFIG_RTC_DRV_DS1742 is not set
-# CONFIG_RTC_DRV_STK17TA8 is not set
-# CONFIG_RTC_DRV_M48T86 is not set
-# CONFIG_RTC_DRV_M48T35 is not set
-# CONFIG_RTC_DRV_M48T59 is not set
-# CONFIG_RTC_DRV_MSM6242 is not set
-# CONFIG_RTC_DRV_BQ4802 is not set
-# CONFIG_RTC_DRV_RP5C01 is not set
-# CONFIG_RTC_DRV_V3020 is not set
-
-#
-# on-CPU RTC drivers
-#
 CONFIG_RTC_DRV_TILE=y
-# CONFIG_DMADEVICES is not set
-# CONFIG_AUXDISPLAY is not set
-# CONFIG_UIO is not set
-# CONFIG_STAGING is not set
-
-#
-# File systems
-#
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
 CONFIG_EXT2_FS_SECURITY=y
 CONFIG_EXT2_FS_XIP=y
 CONFIG_EXT3_FS=y
-CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
-CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
 CONFIG_EXT3_FS_SECURITY=y
 CONFIG_EXT4_FS=y
-CONFIG_EXT4_FS_XATTR=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
-# CONFIG_EXT4_DEBUG is not set
-CONFIG_FS_XIP=y
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_JBD2=y
-CONFIG_JBD2_DEBUG=y
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-CONFIG_XFS_FS=m
+CONFIG_XFS_FS=y
 CONFIG_XFS_QUOTA=y
 CONFIG_XFS_POSIX_ACL=y
-# CONFIG_XFS_RT is not set
-# CONFIG_XFS_DEBUG is not set
 CONFIG_GFS2_FS=m
 CONFIG_GFS2_FS_LOCKING_DLM=y
-# CONFIG_OCFS2_FS is not set
 CONFIG_BTRFS_FS=m
 CONFIG_BTRFS_FS_POSIX_ACL=y
-# CONFIG_NILFS2_FS is not set
-CONFIG_FS_POSIX_ACL=y
-CONFIG_EXPORTFS=y
-CONFIG_FILE_LOCKING=y
-CONFIG_FSNOTIFY=y
-CONFIG_DNOTIFY=y
-CONFIG_INOTIFY_USER=y
-# CONFIG_FANOTIFY is not set
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 # CONFIG_PRINT_QUOTA_WARNING is not set
-# CONFIG_QUOTA_DEBUG is not set
-CONFIG_QUOTA_TREE=y
-# CONFIG_QFMT_V1 is not set
 CONFIG_QFMT_V2=y
-CONFIG_QUOTACTL=y
-# CONFIG_AUTOFS4_FS is not set
+CONFIG_AUTOFS4_FS=m
 CONFIG_FUSE_FS=y
 CONFIG_CUSE=m
-CONFIG_GENERIC_ACL=y
-
-#
-# Caches
-#
 CONFIG_FSCACHE=m
 CONFIG_FSCACHE_STATS=y
-# CONFIG_FSCACHE_HISTOGRAM is not set
-# CONFIG_FSCACHE_DEBUG is not set
-# CONFIG_FSCACHE_OBJECT_LIST is not set
 CONFIG_CACHEFILES=m
-# CONFIG_CACHEFILES_DEBUG is not set
-# CONFIG_CACHEFILES_HISTOGRAM is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
 CONFIG_ISO9660_FS=m
 CONFIG_JOLIET=y
 CONFIG_ZISOFS=y
 CONFIG_UDF_FS=m
-CONFIG_UDF_NLS=y
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=m
 CONFIG_MSDOS_FS=m
 CONFIG_VFAT_FS=m
-CONFIG_FAT_DEFAULT_CODEPAGE=437
 CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_PROC_PAGE_MONITOR=y
-CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_HUGETLBFS=y
-CONFIG_HUGETLB_PAGE=y
-CONFIG_CONFIGFS_FS=m
-CONFIG_MISC_FILESYSTEMS=y
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
 CONFIG_ECRYPT_FS=m
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_LOGFS is not set
 CONFIG_CRAMFS=m
 CONFIG_SQUASHFS=m
-# CONFIG_SQUASHFS_XATTR is not set
-# CONFIG_SQUASHFS_LZO is not set
-# CONFIG_SQUASHFS_XZ is not set
-# CONFIG_SQUASHFS_EMBEDDED is not set
-CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
-# CONFIG_VXFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_OMFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_PSTORE is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
 CONFIG_NFS_V3_ACL=y
 CONFIG_NFS_V4=y
 CONFIG_NFS_V4_1=y
-CONFIG_PNFS_FILE_LAYOUT=m
 CONFIG_NFS_FSCACHE=y
-# CONFIG_NFS_USE_LEGACY_DNS is not set
-CONFIG_NFS_USE_KERNEL_DNS=y
-# CONFIG_NFS_USE_NEW_IDMAPPER is not set
 CONFIG_NFSD=m
-CONFIG_NFSD_V2_ACL=y
-CONFIG_NFSD_V3=y
 CONFIG_NFSD_V3_ACL=y
 CONFIG_NFSD_V4=y
-CONFIG_LOCKD=m
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_ACL_SUPPORT=m
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=m
-CONFIG_SUNRPC_GSS=m
-CONFIG_RPCSEC_GSS_KRB5=m
-# CONFIG_CEPH_FS is not set
 CONFIG_CIFS=m
 CONFIG_CIFS_STATS=y
-# CONFIG_CIFS_STATS2 is not set
 CONFIG_CIFS_WEAK_PW_HASH=y
 CONFIG_CIFS_UPCALL=y
 CONFIG_CIFS_XATTR=y
 CONFIG_CIFS_POSIX=y
-# CONFIG_CIFS_DEBUG2 is not set
 CONFIG_CIFS_DFS_UPCALL=y
 CONFIG_CIFS_FSCACHE=y
-# CONFIG_CIFS_ACL is not set
-CONFIG_CIFS_EXPERIMENTAL=y
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-CONFIG_OSF_PARTITION=y
-CONFIG_AMIGA_PARTITION=y
-# CONFIG_ATARI_PARTITION is not set
-CONFIG_MAC_PARTITION=y
-CONFIG_MSDOS_PARTITION=y
-CONFIG_BSD_DISKLABEL=y
-CONFIG_MINIX_SUBPARTITION=y
-CONFIG_SOLARIS_X86_PARTITION=y
-CONFIG_UNIXWARE_DISKLABEL=y
-# CONFIG_LDM_PARTITION is not set
-CONFIG_SGI_PARTITION=y
-# CONFIG_ULTRIX_PARTITION is not set
-CONFIG_SUN_PARTITION=y
-CONFIG_KARMA_PARTITION=y
-CONFIG_EFI_PARTITION=y
-# CONFIG_SYSV68_PARTITION is not set
-CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="utf8"
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_737=m
@@ -1567,185 +521,47 @@
 CONFIG_NLS_KOI8_R=m
 CONFIG_NLS_KOI8_U=m
 CONFIG_NLS_UTF8=m
-CONFIG_DLM=m
 CONFIG_DLM_DEBUG=y
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
 # CONFIG_ENABLE_WARN_DEPRECATED is not set
-CONFIG_ENABLE_MUST_CHECK=y
-CONFIG_FRAME_WARN=2048
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_STRIP_ASM_SYMS=y
-# CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 CONFIG_HEADERS_CHECK=y
-# CONFIG_DEBUG_SECTION_MISMATCH is not set
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_SHIRQ=y
 CONFIG_LOCKUP_DETECTOR=y
-# CONFIG_HARDLOCKUP_DETECTOR is not set
-# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set
-CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0
-# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
-CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
-CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
-CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
-CONFIG_SCHED_DEBUG=y
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
-# CONFIG_DEBUG_OBJECTS is not set
-# CONFIG_SLUB_DEBUG_ON is not set
-# CONFIG_SLUB_STATS is not set
-# CONFIG_DEBUG_KMEMLEAK is not set
-# CONFIG_DEBUG_RT_MUTEXES is not set
-# CONFIG_RT_MUTEX_TESTER is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_MUTEXES is not set
-# CONFIG_DEBUG_LOCK_ALLOC is not set
-# CONFIG_PROVE_LOCKING is not set
-# CONFIG_SPARSE_RCU_POINTER is not set
-# CONFIG_LOCK_STAT is not set
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-CONFIG_STACKTRACE=y
-# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_INFO_REDUCED=y
 CONFIG_DEBUG_VM=y
-# CONFIG_DEBUG_WRITECOUNT is not set
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_DEBUG_LIST=y
-# CONFIG_TEST_LIST_SORT is not set
-# CONFIG_DEBUG_SG is not set
-# CONFIG_DEBUG_NOTIFIERS is not set
 CONFIG_DEBUG_CREDENTIALS=y
-# CONFIG_RCU_TORTURE_TEST is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_BACKTRACE_SELF_TEST is not set
-# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
-# CONFIG_LKDTM is not set
-# CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
-# CONFIG_DEBUG_PAGEALLOC is not set
-CONFIG_TRACING_SUPPORT=y
-CONFIG_FTRACE=y
-# CONFIG_IRQSOFF_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_ENABLE_DEFAULT_TRACERS is not set
-CONFIG_BRANCH_PROFILE_NONE=y
-# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
-# CONFIG_PROFILE_ALL_BRANCHES is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_BUILD_DOCSRC is not set
 CONFIG_DYNAMIC_DEBUG=y
-# CONFIG_ATOMIC64_SELFTEST is not set
 CONFIG_ASYNC_RAID6_TEST=m
-# CONFIG_SAMPLES is not set
-# CONFIG_TEST_KSTRTOX is not set
-CONFIG_EARLY_PRINTK=y
 CONFIG_DEBUG_STACKOVERFLOW=y
-# CONFIG_DEBUG_STACK_USAGE is not set
-CONFIG_DEBUG_EXTRA_FLAGS=""
-
-#
-# Security options
-#
-CONFIG_KEYS=y
 CONFIG_KEYS_DEBUG_PROC_KEYS=y
-# CONFIG_SECURITY_DMESG_RESTRICT is not set
 CONFIG_SECURITY=y
 CONFIG_SECURITYFS=y
 CONFIG_SECURITY_NETWORK=y
 CONFIG_SECURITY_NETWORK_XFRM=y
-# CONFIG_SECURITY_PATH is not set
-CONFIG_LSM_MMAP_MIN_ADDR=65536
 CONFIG_SECURITY_SELINUX=y
 CONFIG_SECURITY_SELINUX_BOOTPARAM=y
-CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1
 CONFIG_SECURITY_SELINUX_DISABLE=y
-CONFIG_SECURITY_SELINUX_DEVELOP=y
-CONFIG_SECURITY_SELINUX_AVC_STATS=y
-CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
-# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
-# CONFIG_SECURITY_SMACK is not set
-# CONFIG_SECURITY_TOMOYO is not set
-# CONFIG_SECURITY_APPARMOR is not set
-# CONFIG_IMA is not set
-CONFIG_DEFAULT_SECURITY_SELINUX=y
-# CONFIG_DEFAULT_SECURITY_DAC is not set
-CONFIG_DEFAULT_SECURITY="selinux"
-CONFIG_XOR_BLOCKS=m
-CONFIG_ASYNC_CORE=m
-CONFIG_ASYNC_MEMCPY=m
-CONFIG_ASYNC_XOR=m
-CONFIG_ASYNC_PQ=m
-CONFIG_ASYNC_RAID6_RECOV=m
-CONFIG_CRYPTO=y
-
-#
-# Crypto core or helper
-#
-CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_ALGAPI2=y
-CONFIG_CRYPTO_AEAD=m
-CONFIG_CRYPTO_AEAD2=y
-CONFIG_CRYPTO_BLKCIPHER=m
-CONFIG_CRYPTO_BLKCIPHER2=y
-CONFIG_CRYPTO_HASH=y
-CONFIG_CRYPTO_HASH2=y
-CONFIG_CRYPTO_RNG=m
-CONFIG_CRYPTO_RNG2=y
-CONFIG_CRYPTO_PCOMP=m
-CONFIG_CRYPTO_PCOMP2=y
-CONFIG_CRYPTO_MANAGER=y
-CONFIG_CRYPTO_MANAGER2=y
-CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
-CONFIG_CRYPTO_GF128MUL=m
 CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_PCRYPT=m
-CONFIG_CRYPTO_WORKQUEUE=y
 CONFIG_CRYPTO_CRYPTD=m
-CONFIG_CRYPTO_AUTHENC=m
 CONFIG_CRYPTO_TEST=m
-
-#
-# Authenticated Encryption with Associated Data
-#
 CONFIG_CRYPTO_CCM=m
 CONFIG_CRYPTO_GCM=m
-CONFIG_CRYPTO_SEQIV=m
-
-#
-# Block modes
-#
-CONFIG_CRYPTO_CBC=m
-CONFIG_CRYPTO_CTR=m
 CONFIG_CRYPTO_CTS=m
-CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
-
-#
-# Hash modes
-#
 CONFIG_CRYPTO_HMAC=y
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
-
-#
-# Digest
-#
 CONFIG_CRYPTO_CRC32C=y
-CONFIG_CRYPTO_GHASH=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD128=m
 CONFIG_CRYPTO_RMD160=m
@@ -1756,76 +572,16 @@
 CONFIG_CRYPTO_SHA512=m
 CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
-
-#
-# Ciphers
-#
-CONFIG_CRYPTO_AES=m
 CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_CAST5=m
 CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_DES=m
 CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
-# CONFIG_CRYPTO_SALSA20 is not set
 CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_TWOFISH_COMMON=m
-
-#
-# Compression
-#
-CONFIG_CRYPTO_DEFLATE=m
 CONFIG_CRYPTO_ZLIB=m
 CONFIG_CRYPTO_LZO=m
-
-#
-# Random Number Generation
-#
-CONFIG_CRYPTO_ANSI_CPRNG=m
-# CONFIG_CRYPTO_USER_API_HASH is not set
-# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
-CONFIG_CRYPTO_HW=y
-CONFIG_CRYPTO_DEV_HIFN_795X=m
-CONFIG_CRYPTO_DEV_HIFN_795X_RNG=y
-# CONFIG_BINARY_PRINTF is not set
-
-#
-# Library routines
-#
-CONFIG_RAID6_PQ=m
-CONFIG_BITREVERSE=y
-CONFIG_GENERIC_FIND_FIRST_BIT=y
-CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_FIND_LAST_BIT=y
-# CONFIG_CRC_CCITT is not set
-CONFIG_CRC16=y
-CONFIG_CRC_T10DIF=y
-CONFIG_CRC_ITU_T=m
-CONFIG_CRC32=y
-# CONFIG_CRC7 is not set
-CONFIG_LIBCRC32C=m
-CONFIG_AUDIT_GENERIC=y
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=m
-CONFIG_LZO_COMPRESS=m
-CONFIG_LZO_DECOMPRESS=m
-# CONFIG_XZ_DEC is not set
-# CONFIG_XZ_DEC_BCJ is not set
-CONFIG_DECOMPRESS_GZIP=y
-CONFIG_TEXTSEARCH=y
-CONFIG_TEXTSEARCH_KMP=m
-CONFIG_TEXTSEARCH_BM=m
-CONFIG_TEXTSEARCH_FSM=m
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
-CONFIG_HAS_DMA=y
-CONFIG_CPU_RMAP=y
-CONFIG_NLATTR=y
-# CONFIG_AVERAGE is not set
-# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/tile/configs/tilepro_defconfig b/arch/tile/configs/tilepro_defconfig
index 6f05f96..2b1fd31 100644
--- a/arch/tile/configs/tilepro_defconfig
+++ b/arch/tile/configs/tilepro_defconfig
@@ -1,1162 +1,579 @@
-#
-# Automatically generated make config: don't edit
-# Linux/tile 2.6.39-rc5 Kernel Configuration
-# Tue May  3 09:15:02 2011
-#
-CONFIG_TILE=y
-CONFIG_MMU=y
-CONFIG_GENERIC_CSUM=y
-CONFIG_SEMAPHORE_SLEEPERS=y
-CONFIG_HAVE_ARCH_ALLOC_REMAP=y
-CONFIG_HAVE_SETUP_PER_CPU_AREA=y
-CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
-CONFIG_SYS_SUPPORTS_HUGETLBFS=y
-CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_DEFAULT_MIGRATION_COST=10000000
-CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
-CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
-CONFIG_ARCH_DMA_ADDR_T_64BIT=y
-CONFIG_LOCKDEP_SUPPORT=y
-CONFIG_STACKTRACE_SUPPORT=y
-CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-CONFIG_STRICT_DEVMEM=y
-CONFIG_SMP=y
-# CONFIG_DEBUG_COPY_FROM_USER is not set
-CONFIG_HVC_TILE=y
-# CONFIG_TILEGX is not set
-CONFIG_ARCH_DEFCONFIG="arch/tile/configs/tile_defconfig"
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-CONFIG_CONSTRUCTORS=y
-
-#
-# General setup
-#
 CONFIG_EXPERIMENTAL=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-CONFIG_CROSS_COMPILE=""
-CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
-# CONFIG_SWAP is not set
+# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_POSIX_MQUEUE is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_FHANDLE=y
-# CONFIG_TASKSTATS is not set
-# CONFIG_AUDIT is not set
-CONFIG_HAVE_GENERIC_HARDIRQS=y
-
-#
-# IRQ subsystem
-#
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_GENERIC_IRQ_SHOW=y
-CONFIG_GENERIC_PENDING_IRQ=y
-
-#
-# RCU Subsystem
-#
-CONFIG_TREE_RCU=y
-# CONFIG_PREEMPT_RCU is not set
-# CONFIG_RCU_TRACE is not set
-CONFIG_RCU_FANOUT=32
-# CONFIG_RCU_FANOUT_EXACT is not set
-# CONFIG_RCU_FAST_NO_HZ is not set
-# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_IKCONFIG is not set
-CONFIG_LOG_BUF_SHIFT=17
-# CONFIG_CGROUPS is not set
-# CONFIG_NAMESPACES is not set
-# CONFIG_SCHED_AUTOGROUP is not set
-# CONFIG_SYSFS_DEPRECATED is not set
-# CONFIG_RELAY is not set
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_AUDIT=y
+CONFIG_LOG_BUF_SHIFT=19
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_MEM_RES_CTLR=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
+CONFIG_NAMESPACES=y
+CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="usr/contents.txt"
-CONFIG_INITRAMFS_ROOT_UID=0
-CONFIG_INITRAMFS_ROOT_GID=0
-CONFIG_RD_GZIP=y
-# CONFIG_RD_BZIP2 is not set
-# CONFIG_RD_LZMA is not set
-# CONFIG_RD_XZ is not set
-# CONFIG_RD_LZO is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
-# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SYSCTL=y
-CONFIG_ANON_INODES=y
-CONFIG_EXPERT=y
 CONFIG_SYSCTL_SYSCALL=y
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_ALL is not set
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_HOTPLUG=y
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
-CONFIG_SHMEM=y
-CONFIG_AIO=y
 CONFIG_EMBEDDED=y
-
-#
-# Kernel Performance Events And Counters
-#
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_PCI_QUIRKS=y
-CONFIG_SLUB_DEBUG=y
 # CONFIG_COMPAT_BRK is not set
-# CONFIG_SLAB is not set
-CONFIG_SLUB=y
-# CONFIG_SLOB is not set
 CONFIG_PROFILING=y
-CONFIG_USE_GENERIC_SMP_HELPERS=y
-
-#
-# GCOV-based kernel profiling
-#
-# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
-CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
-CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
-# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_FORCE_LOAD=y
 CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_STOP_MACHINE=y
-CONFIG_BLOCK=y
-CONFIG_LBDAF=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_BLK_DEV_INTEGRITY is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_DEFAULT_NOOP=y
-CONFIG_DEFAULT_IOSCHED="noop"
-# CONFIG_INLINE_SPIN_TRYLOCK is not set
-# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
-# CONFIG_INLINE_SPIN_LOCK is not set
-# CONFIG_INLINE_SPIN_LOCK_BH is not set
-# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
-# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
-CONFIG_INLINE_SPIN_UNLOCK=y
-# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
-CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
-# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
-# CONFIG_INLINE_READ_TRYLOCK is not set
-# CONFIG_INLINE_READ_LOCK is not set
-# CONFIG_INLINE_READ_LOCK_BH is not set
-# CONFIG_INLINE_READ_LOCK_IRQ is not set
-# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
-CONFIG_INLINE_READ_UNLOCK=y
-# CONFIG_INLINE_READ_UNLOCK_BH is not set
-CONFIG_INLINE_READ_UNLOCK_IRQ=y
-# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
-# CONFIG_INLINE_WRITE_TRYLOCK is not set
-# CONFIG_INLINE_WRITE_LOCK is not set
-# CONFIG_INLINE_WRITE_LOCK_BH is not set
-# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
-# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
-CONFIG_INLINE_WRITE_UNLOCK=y
-# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
-CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
-# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
-CONFIG_MUTEX_SPIN_ON_OWNER=y
-
-#
-# Tilera-specific configuration
-#
-CONFIG_NR_CPUS=64
-CONFIG_TICK_ONESHOT=y
+CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_SGI_PARTITION=y
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_EFI_PARTITION=y
+CONFIG_CFQ_GROUP_IOSCHED=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
-CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 CONFIG_HZ_100=y
-# CONFIG_HZ_250 is not set
-# CONFIG_HZ_300 is not set
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=100
-CONFIG_SCHED_HRTICK=y
-# CONFIG_KEXEC is not set
-CONFIG_HIGHMEM=y
-CONFIG_NUMA=y
-CONFIG_NODES_SHIFT=2
-# CONFIG_VMSPLIT_3_75G is not set
-# CONFIG_VMSPLIT_3_5G is not set
-CONFIG_VMSPLIT_3G=y
-# CONFIG_VMSPLIT_2_75G is not set
-# CONFIG_VMSPLIT_2_5G is not set
-# CONFIG_VMSPLIT_2_25G is not set
-# CONFIG_VMSPLIT_2G is not set
-# CONFIG_VMSPLIT_1G is not set
-CONFIG_PAGE_OFFSET=0xC0000000
-CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_DISCONTIGMEM_MANUAL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-CONFIG_NEED_MULTIPLE_NODES=y
-CONFIG_PAGEFLAGS_EXTENDED=y
-CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_COMPACTION is not set
-CONFIG_MIGRATION=y
-CONFIG_PHYS_ADDR_T_64BIT=y
-CONFIG_ZONE_DMA_FLAG=0
-CONFIG_BOUNCE=y
-CONFIG_VIRT_TO_BUS=y
-# CONFIG_KSM is not set
-CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
-# CONFIG_CMDLINE_BOOL is not set
-CONFIG_VMALLOC_RESERVE=0x1000000
-CONFIG_HARDWALL=y
-CONFIG_KERNEL_PL=1
-
-#
-# Bus options
-#
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-# CONFIG_NO_IOMEM is not set
-# CONFIG_NO_IOPORT is not set
-# CONFIG_ARCH_SUPPORTS_MSI is not set
-# CONFIG_PCI_DEBUG is not set
-# CONFIG_PCI_STUB is not set
-# CONFIG_PCI_IOV is not set
-# CONFIG_HOTPLUG_PCI is not set
-
-#
-# Executable file formats
-#
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
+CONFIG_PCI_DEBUG=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-# CONFIG_HAVE_AOUT is not set
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=y
 CONFIG_NET=y
-
-#
-# Networking options
-#
 CONFIG_PACKET=y
 CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS is not set
-# CONFIG_NET_KEY is not set
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=m
+CONFIG_NET_KEY_MIGRATE=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE_DEMUX is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_XFRM_TUNNEL is not set
-CONFIG_INET_TUNNEL=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_BEET=y
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_DEFAULT_TCP_CONG="cubic"
-# CONFIG_TCP_MD5SIG is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_NET_IPIP=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+CONFIG_TCP_MD5SIG=y
 CONFIG_IPV6=y
-# CONFIG_IPV6_PRIVACY is not set
-# CONFIG_IPV6_ROUTER_PREF is not set
-# CONFIG_IPV6_OPTIMISTIC_DAD is not set
-# CONFIG_INET6_AH is not set
-# CONFIG_INET6_ESP is not set
-# CONFIG_INET6_IPCOMP is not set
-# CONFIG_IPV6_MIP6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
-CONFIG_INET6_XFRM_MODE_TRANSPORT=y
-CONFIG_INET6_XFRM_MODE_TUNNEL=y
-CONFIG_INET6_XFRM_MODE_BEET=y
-# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
-CONFIG_IPV6_SIT=y
-# CONFIG_IPV6_SIT_6RD is not set
-CONFIG_IPV6_NDISC_NODETYPE=y
-# CONFIG_IPV6_TUNNEL is not set
-# CONFIG_IPV6_MULTIPLE_TABLES is not set
-# CONFIG_IPV6_MROUTE is not set
-# CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_IP_DCCP is not set
-# CONFIG_IP_SCTP is not set
-# CONFIG_RDS is not set
-# CONFIG_TIPC is not set
-# CONFIG_ATM is not set
-# CONFIG_L2TP is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_NET_DSA is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_PHONET is not set
-# CONFIG_IEEE802154 is not set
-# CONFIG_NET_SCHED is not set
-# CONFIG_DCB is not set
-# CONFIG_BATMAN_ADV is not set
-CONFIG_RPS=y
-CONFIG_RFS_ACCEL=y
-CONFIG_XPS=y
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_CAN is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_AF_RXRPC is not set
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_NETLABEL=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=m
+CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NETFILTER_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_SCTP=y
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+CONFIG_NF_CONNTRACK_IPV4=m
+# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_SECURITY=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+CONFIG_RDS=m
+CONFIG_RDS_TCP=m
+CONFIG_BRIDGE=m
+CONFIG_NET_DSA=y
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_PHONET=m
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_NET_CLS_IND=y
+CONFIG_DCB=y
 # CONFIG_WIRELESS is not set
-# CONFIG_WIMAX is not set
-# CONFIG_RFKILL is not set
-# CONFIG_NET_9P is not set
-# CONFIG_CAIF is not set
-# CONFIG_CEPH_LIB is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_DEVTMPFS is not set
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=y
-CONFIG_FIRMWARE_IN_KERNEL=y
-CONFIG_EXTRA_FIRMWARE=""
-# CONFIG_DEBUG_DRIVER is not set
-# CONFIG_DEBUG_DEVRES is not set
-# CONFIG_SYS_HYPERVISOR is not set
-# CONFIG_CONNECTOR is not set
-# CONFIG_MTD is not set
-# CONFIG_PARPORT is not set
-CONFIG_BLK_DEV=y
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
-
-#
-# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
-#
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_SX8 is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_ATA_OVER_ETH is not set
-# CONFIG_BLK_DEV_RBD is not set
-# CONFIG_SENSORS_LIS3LV02D is not set
-CONFIG_MISC_DEVICES=y
-# CONFIG_PHANTOM is not set
-# CONFIG_SGI_IOC4 is not set
-# CONFIG_TIFM_CORE is not set
-# CONFIG_ENCLOSURE_SERVICES is not set
-# CONFIG_HP_ILO is not set
-# CONFIG_PCH_PHUB is not set
-# CONFIG_C2PORT is not set
-
-#
-# EEPROM support
-#
-# CONFIG_EEPROM_93CX6 is not set
-# CONFIG_CB710_CORE is not set
-
-#
-# Texas Instruments shared transport line discipline
-#
-
-#
-# SCSI device support
-#
-CONFIG_SCSI_MOD=y
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=y
-CONFIG_SCSI_DMA=y
-# CONFIG_SCSI_TGT is not set
-# CONFIG_SCSI_NETLINK is not set
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_CONNECTOR=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_ATA_OVER_ETH=m
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI_TGT=m
 CONFIG_BLK_DEV_SD=y
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_CHR_DEV_SCH is not set
-# CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
-# CONFIG_SCSI_SCAN_ASYNC is not set
-CONFIG_SCSI_WAIT_SCAN=m
-
-#
-# SCSI Transports
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
-# CONFIG_SCSI_SAS_LIBSAS is not set
-# CONFIG_SCSI_SRP_ATTRS is not set
-CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_ISCSI_BOOT_SYSFS is not set
-# CONFIG_SCSI_CXGB3_ISCSI is not set
-# CONFIG_SCSI_CXGB4_ISCSI is not set
-# CONFIG_SCSI_BNX2_ISCSI is not set
-# CONFIG_SCSI_BNX2X_FCOE is not set
-# CONFIG_BE2ISCSI is not set
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_HPSA is not set
-# CONFIG_SCSI_3W_9XXX is not set
-# CONFIG_SCSI_3W_SAS is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_AIC94XX is not set
-# CONFIG_SCSI_MVSAS is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_ARCMSR is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_MPT2SAS is not set
-# CONFIG_SCSI_HPTIOP is not set
-# CONFIG_LIBFC is not set
-# CONFIG_LIBFCOE is not set
-# CONFIG_FCOE is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_STEX is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLA_FC is not set
-# CONFIG_SCSI_QLA_ISCSI is not set
-# CONFIG_SCSI_LPFC is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_PMCRAID is not set
-# CONFIG_SCSI_PM8001 is not set
-# CONFIG_SCSI_SRP is not set
-# CONFIG_SCSI_BFA_FC is not set
-# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
-# CONFIG_SCSI_DH is not set
-# CONFIG_SCSI_OSD_INITIATOR is not set
-# CONFIG_ATA is not set
-# CONFIG_MD is not set
-# CONFIG_TARGET_CORE is not set
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_FIREWIRE is not set
-# CONFIG_FIREWIRE_NOSY is not set
-# CONFIG_I2O is not set
+CONFIG_ATA=y
+CONFIG_SATA_SIL24=y
+# CONFIG_ATA_SFF is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_MULTICORE_RAID456=y
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_QL=m
+CONFIG_DM_MULTIPATH_ST=m
+CONFIG_DM_DELAY=m
+CONFIG_DM_UEVENT=y
+CONFIG_FUSION=y
+CONFIG_FUSION_SAS=y
 CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_MACVLAN is not set
-# CONFIG_EQUALIZER is not set
+CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_IFB=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_NETCONSOLE=m
+CONFIG_NETCONSOLE_DYNAMIC=y
+CONFIG_NETPOLL_TRAP=y
 CONFIG_TUN=y
-# CONFIG_VETH is not set
-# CONFIG_ARCNET is not set
-# CONFIG_MII is not set
-# CONFIG_PHYLIB is not set
-# CONFIG_NET_ETHERNET is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_E1000E is not set
-# CONFIG_IP1000 is not set
-# CONFIG_IGB is not set
-# CONFIG_IGBVF is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
-# CONFIG_SKGE is not set
-# CONFIG_SKY2 is not set
-# CONFIG_VIA_VELOCITY is not set
-# CONFIG_TIGON3 is not set
-# CONFIG_BNX2 is not set
-# CONFIG_CNIC is not set
-# CONFIG_QLA3XXX is not set
-# CONFIG_ATL1 is not set
-# CONFIG_ATL1E is not set
-# CONFIG_ATL1C is not set
-# CONFIG_JME is not set
-# CONFIG_STMMAC_ETH is not set
-# CONFIG_PCH_GBE is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_TR is not set
+CONFIG_VETH=m
+CONFIG_NET_DSA_MV88E6060=y
+CONFIG_NET_DSA_MV88E6131=y
+CONFIG_NET_DSA_MV88E6123_61_65=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_NET_VENDOR_DEC is not set
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+# CONFIG_NET_VENDOR_HP is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_REALTEK is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_VIA is not set
 # CONFIG_WLAN is not set
-
-#
-# Enable WiMAX (Networking options) to see the WiMAX drivers
-#
-# CONFIG_WAN is not set
-
-#
-# CAIF transport drivers
-#
-CONFIG_TILE_NET=y
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_NET_FC is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_VMXNET3 is not set
-# CONFIG_ISDN is not set
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_POLLDEV is not set
-# CONFIG_INPUT_SPARSEKMAP is not set
-
-#
-# Userland interfaces
-#
 # CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
 # CONFIG_SERIO is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
 # CONFIG_VT is not set
-CONFIG_UNIX98_PTYS=y
-# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_NOZOMI is not set
-# CONFIG_N_GSM is not set
-CONFIG_DEVKMEM=y
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-# CONFIG_SERIAL_MFD_HSU is not set
-# CONFIG_SERIAL_JSM is not set
-# CONFIG_SERIAL_TIMBERDALE is not set
-# CONFIG_SERIAL_ALTERA_JTAGUART is not set
-# CONFIG_SERIAL_ALTERA_UART is not set
-# CONFIG_SERIAL_PCH_UART is not set
-# CONFIG_TTY_PRINTK is not set
-CONFIG_HVC_DRIVER=y
-# CONFIG_IPMI_HANDLER is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# PCMCIA character devices
-#
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_TCG_TPM is not set
-CONFIG_DEVPORT=y
-# CONFIG_RAMOOPS is not set
-# CONFIG_I2C is not set
-# CONFIG_SPI is not set
-
-#
-# PPS support
-#
-# CONFIG_PPS is not set
-
-#
-# PPS generators support
-#
-# CONFIG_W1 is not set
-# CONFIG_POWER_SUPPLY is not set
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-
-#
-# Native drivers
-#
-# CONFIG_SENSORS_I5K_AMB is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_F71882FG is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_PC87427 is not set
-# CONFIG_SENSORS_SIS5595 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
-# CONFIG_SENSORS_SCH5627 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_SENSORS_VT8231 is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_THERMAL is not set
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
 CONFIG_WATCHDOG_NOWAYOUT=y
-
-#
-# Watchdog Device Drivers
-#
-# CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_ALIM7101_WDT is not set
-
-#
-# PCI-based Watchdog Cards
-#
-# CONFIG_PCIPCWATCHDOG is not set
-# CONFIG_WDTPCI is not set
-CONFIG_SSB_POSSIBLE=y
-
-#
-# Sonics Silicon Backplane
-#
-# CONFIG_SSB is not set
-CONFIG_MFD_SUPPORT=y
-# CONFIG_MFD_CORE is not set
-# CONFIG_MFD_SM501 is not set
-# CONFIG_HTC_PASIC3 is not set
-# CONFIG_MFD_TMIO is not set
-# CONFIG_ABX500_CORE is not set
-# CONFIG_LPC_SCH is not set
-# CONFIG_MFD_RDC321X is not set
-# CONFIG_MFD_JANZ_CMODIO is not set
-# CONFIG_MFD_VX855 is not set
-# CONFIG_REGULATOR is not set
-# CONFIG_MEDIA_SUPPORT is not set
-
-#
-# Graphics support
-#
-CONFIG_VGA_ARB=y
-CONFIG_VGA_ARB_MAX_GPUS=16
-# CONFIG_DRM is not set
-# CONFIG_STUB_POULSBO is not set
-# CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Display device support
-#
-# CONFIG_DISPLAY_SUPPORT is not set
-# CONFIG_SOUND is not set
+# CONFIG_VGA_ARB is not set
 # CONFIG_HID_SUPPORT is not set
-CONFIG_USB_SUPPORT=y
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-CONFIG_USB_ARCH_HAS_EHCI=y
-# CONFIG_USB is not set
-# CONFIG_USB_OTG_WHITELIST is not set
-# CONFIG_USB_OTG_BLACKLIST_HUB is not set
-
-#
-# Enable Host or Gadget support to see Inventra options
-#
-
-#
-# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# OTG and related infrastructure
-#
-# CONFIG_UWB is not set
-# CONFIG_MMC is not set
-# CONFIG_MEMSTICK is not set
-# CONFIG_NEW_LEDS is not set
-# CONFIG_NFC_DEVICES is not set
-# CONFIG_ACCESSIBILITY is not set
-# CONFIG_INFINIBAND is not set
+# CONFIG_USB_SUPPORT is not set
 CONFIG_EDAC=y
-
-#
-# Reporting subsystems
-#
-# CONFIG_EDAC_DEBUG is not set
 CONFIG_EDAC_MM_EDAC=y
-CONFIG_EDAC_TILE=y
-CONFIG_RTC_LIB=y
 CONFIG_RTC_CLASS=y
-CONFIG_RTC_HCTOSYS=y
-CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-# CONFIG_RTC_DEBUG is not set
-
-#
-# RTC interfaces
-#
-# CONFIG_RTC_INTF_SYSFS is not set
-# CONFIG_RTC_INTF_PROC is not set
-CONFIG_RTC_INTF_DEV=y
-# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
-# CONFIG_RTC_DRV_TEST is not set
-
-#
-# SPI RTC drivers
-#
-
-#
-# Platform RTC drivers
-#
-# CONFIG_RTC_DRV_DS1286 is not set
-# CONFIG_RTC_DRV_DS1511 is not set
-# CONFIG_RTC_DRV_DS1553 is not set
-# CONFIG_RTC_DRV_DS1742 is not set
-# CONFIG_RTC_DRV_STK17TA8 is not set
-# CONFIG_RTC_DRV_M48T86 is not set
-# CONFIG_RTC_DRV_M48T35 is not set
-# CONFIG_RTC_DRV_M48T59 is not set
-# CONFIG_RTC_DRV_MSM6242 is not set
-# CONFIG_RTC_DRV_BQ4802 is not set
-# CONFIG_RTC_DRV_RP5C01 is not set
-# CONFIG_RTC_DRV_V3020 is not set
-
-#
-# on-CPU RTC drivers
-#
 CONFIG_RTC_DRV_TILE=y
-# CONFIG_DMADEVICES is not set
-# CONFIG_AUXDISPLAY is not set
-# CONFIG_UIO is not set
-# CONFIG_STAGING is not set
-
-#
-# File systems
-#
 CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT2_FS_XIP=y
 CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-# CONFIG_EXT4_FS is not set
-CONFIG_JBD=y
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_GFS2_FS is not set
-# CONFIG_BTRFS_FS is not set
-# CONFIG_NILFS2_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
-CONFIG_EXPORTFS=y
-CONFIG_FILE_LOCKING=y
-CONFIG_FSNOTIFY=y
-CONFIG_DNOTIFY=y
-CONFIG_INOTIFY_USER=y
-# CONFIG_FANOTIFY is not set
-# CONFIG_QUOTA is not set
-# CONFIG_QUOTACTL is not set
-# CONFIG_AUTOFS4_FS is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_XFS_FS=y
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_GFS2_FS=m
+CONFIG_GFS2_FS_LOCKING_DLM=y
+CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS_POSIX_ACL=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+CONFIG_QFMT_V2=y
+CONFIG_AUTOFS4_FS=m
 CONFIG_FUSE_FS=y
-# CONFIG_CUSE is not set
-
-#
-# Caches
-#
-# CONFIG_FSCACHE is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+CONFIG_CUSE=m
+CONFIG_FSCACHE=m
+CONFIG_FSCACHE_STATS=y
+CONFIG_CACHEFILES=m
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_MSDOS_FS=m
 CONFIG_VFAT_FS=m
-CONFIG_FAT_DEFAULT_CODEPAGE=437
-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_PROC_KCORE is not set
-CONFIG_PROC_SYSCTL=y
-CONFIG_PROC_PAGE_MONITOR=y
-CONFIG_SYSFS=y
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_HUGETLBFS=y
-CONFIG_HUGETLB_PAGE=y
-# CONFIG_CONFIGFS_FS is not set
-CONFIG_MISC_FILESYSTEMS=y
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_LOGFS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_SQUASHFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_OMFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_PSTORE is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_ECRYPT_FS=m
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=m
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_LOCKD=m
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=m
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_CEPH_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_FSCACHE=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_CIFS_FSCACHE=y
 CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_DEFAULT="utf8"
 CONFIG_NLS_CODEPAGE_437=y
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1250 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ASCII is not set
-CONFIG_NLS_ISO8859_1=y
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
-CONFIG_ENABLE_WARN_DEPRECATED=y
-CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+CONFIG_DLM_DEBUG=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
 CONFIG_FRAME_WARN=2048
 CONFIG_MAGIC_SYSRQ=y
-# CONFIG_STRIP_ASM_SYMS is not set
-# CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_HEADERS_CHECK is not set
-# CONFIG_DEBUG_SECTION_MISMATCH is not set
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
-# CONFIG_LOCKUP_DETECTOR is not set
-# CONFIG_HARDLOCKUP_DETECTOR is not set
-CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
-CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
-CONFIG_SCHED_DEBUG=y
-# CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
-# CONFIG_DEBUG_OBJECTS is not set
-# CONFIG_SLUB_DEBUG_ON is not set
-# CONFIG_SLUB_STATS is not set
-# CONFIG_DEBUG_KMEMLEAK is not set
-# CONFIG_DEBUG_RT_MUTEXES is not set
-# CONFIG_RT_MUTEX_TESTER is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_MUTEXES is not set
-# CONFIG_DEBUG_LOCK_ALLOC is not set
-# CONFIG_PROVE_LOCKING is not set
-# CONFIG_SPARSE_RCU_POINTER is not set
-# CONFIG_LOCK_STAT is not set
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-CONFIG_STACKTRACE=y
-# CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_DEBUG_FS=y
+CONFIG_HEADERS_CHECK=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_DEBUG_INFO_REDUCED is not set
+CONFIG_DEBUG_INFO_REDUCED=y
 CONFIG_DEBUG_VM=y
-# CONFIG_DEBUG_WRITECOUNT is not set
-# CONFIG_DEBUG_MEMORY_INIT is not set
-# CONFIG_DEBUG_LIST is not set
-# CONFIG_TEST_LIST_SORT is not set
-# CONFIG_DEBUG_SG is not set
-# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_DEBUG_CREDENTIALS is not set
-# CONFIG_RCU_TORTURE_TEST is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_BACKTRACE_SELF_TEST is not set
-# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
-# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
-# CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
-# CONFIG_DEBUG_PAGEALLOC is not set
-CONFIG_TRACING_SUPPORT=y
-CONFIG_FTRACE=y
-# CONFIG_IRQSOFF_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_ENABLE_DEFAULT_TRACERS is not set
-CONFIG_BRANCH_PROFILE_NONE=y
-# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
-# CONFIG_PROFILE_ALL_BRANCHES is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_ATOMIC64_SELFTEST is not set
-# CONFIG_SAMPLES is not set
-# CONFIG_TEST_KSTRTOX is not set
-CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+CONFIG_DEBUG_CREDENTIALS=y
+CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_DEBUG_STACKOVERFLOW=y
-# CONFIG_DEBUG_STACK_USAGE is not set
-CONFIG_DEBUG_EXTRA_FLAGS="-femit-struct-debug-baseonly"
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY_DMESG_RESTRICT is not set
-# CONFIG_SECURITY is not set
-# CONFIG_SECURITYFS is not set
-CONFIG_DEFAULT_SECURITY_DAC=y
-CONFIG_DEFAULT_SECURITY=""
-CONFIG_CRYPTO=y
-
-#
-# Crypto core or helper
-#
-# CONFIG_CRYPTO_FIPS is not set
-CONFIG_CRYPTO_ALGAPI=m
-CONFIG_CRYPTO_ALGAPI2=m
-CONFIG_CRYPTO_RNG=m
-CONFIG_CRYPTO_RNG2=m
-# CONFIG_CRYPTO_MANAGER is not set
-# CONFIG_CRYPTO_MANAGER2 is not set
-# CONFIG_CRYPTO_GF128MUL is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_PCRYPT is not set
-# CONFIG_CRYPTO_CRYPTD is not set
-# CONFIG_CRYPTO_AUTHENC is not set
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Authenticated Encryption with Associated Data
-#
-# CONFIG_CRYPTO_CCM is not set
-# CONFIG_CRYPTO_GCM is not set
-# CONFIG_CRYPTO_SEQIV is not set
-
-#
-# Block modes
-#
-# CONFIG_CRYPTO_CBC is not set
-# CONFIG_CRYPTO_CTR is not set
-# CONFIG_CRYPTO_CTS is not set
-# CONFIG_CRYPTO_ECB is not set
-# CONFIG_CRYPTO_LRW is not set
-# CONFIG_CRYPTO_PCBC is not set
-# CONFIG_CRYPTO_XTS is not set
-
-#
-# Hash modes
-#
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_XCBC is not set
-# CONFIG_CRYPTO_VMAC is not set
-
-#
-# Digest
-#
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_GHASH is not set
-# CONFIG_CRYPTO_MD4 is not set
-# CONFIG_CRYPTO_MD5 is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_RMD128 is not set
-# CONFIG_CRYPTO_RMD160 is not set
-# CONFIG_CRYPTO_RMD256 is not set
-# CONFIG_CRYPTO_RMD320 is not set
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_WP512 is not set
-
-#
-# Ciphers
-#
-CONFIG_CRYPTO_AES=m
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_CAMELLIA is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_DES is not set
-# CONFIG_CRYPTO_FCRYPT is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_SALSA20 is not set
-# CONFIG_CRYPTO_SEED is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-
-#
-# Compression
-#
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_ZLIB is not set
-# CONFIG_CRYPTO_LZO is not set
-
-#
-# Random Number Generation
-#
-CONFIG_CRYPTO_ANSI_CPRNG=m
-# CONFIG_CRYPTO_USER_API_HASH is not set
-# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
-CONFIG_CRYPTO_HW=y
-# CONFIG_CRYPTO_DEV_HIFN_795X is not set
-# CONFIG_BINARY_PRINTF is not set
-
-#
-# Library routines
-#
-CONFIG_BITREVERSE=y
-CONFIG_GENERIC_FIND_FIRST_BIT=y
-CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_FIND_LAST_BIT=y
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
-# CONFIG_CRC_T10DIF is not set
-# CONFIG_CRC_ITU_T is not set
-CONFIG_CRC32=y
-# CONFIG_CRC7 is not set
-# CONFIG_LIBCRC32C is not set
-CONFIG_ZLIB_INFLATE=y
-# CONFIG_XZ_DEC is not set
-# CONFIG_XZ_DEC_BCJ is not set
-CONFIG_DECOMPRESS_GZIP=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
-CONFIG_HAS_DMA=y
-CONFIG_CPU_RMAP=y
-CONFIG_NLATTR=y
-# CONFIG_AVERAGE is not set
-CONFIG_HAVE_KVM=y
-# CONFIG_VIRTUALIZATION is not set
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+CONFIG_SECURITY=y
+CONFIG_SECURITYFS=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_PCRYPT=m
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ZLIB=m
+CONFIG_CRYPTO_LZO=m
+CONFIG_CRC_CCITT=m
+CONFIG_CRC7=m
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
index a7869ad..77763cc 100644
--- a/arch/tile/kernel/compat_signal.c
+++ b/arch/tile/kernel/compat_signal.c
@@ -303,10 +303,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index 4c1ac6e..6ae495e 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -108,9 +108,7 @@
 		}
 		rcu_idle_exit();
 		tick_nohz_idle_exit();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c
index bedaf4e..f79d4b8 100644
--- a/arch/tile/kernel/signal.c
+++ b/arch/tile/kernel/signal.c
@@ -97,10 +97,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
@@ -286,13 +283,7 @@
 		 * the work_pending path in the return-to-user code, and
 		 * either way we can re-enable interrupts unconditionally.
 		 */
-		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked,
-			  &current->blocked, &ka->sa.sa_mask);
-		if (!(ka->sa.sa_flags & SA_NODEFER))
-			sigaddset(&current->blocked, sig);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
+		block_sigmask(ka, sig);
 	}
 
 	return ret;
diff --git a/arch/tile/kernel/sysfs.c b/arch/tile/kernel/sysfs.c
index f862b00..71ae728 100644
--- a/arch/tile/kernel/sysfs.c
+++ b/arch/tile/kernel/sysfs.c
@@ -163,7 +163,7 @@
 
 #define create_hv_attr(name)						\
 	if (!err)							\
-		err = sysfs_create_file(hypervisor_kobj, &dev_attr_##name);
+		err = sysfs_create_file(hypervisor_kobj, &dev_attr_##name.attr);
 	create_hv_attr(type);
 	create_hv_attr(version);
 	create_hv_attr(config_version);
diff --git a/arch/tile/lib/spinlock_32.c b/arch/tile/lib/spinlock_32.c
index cb0999f..b16ac49 100644
--- a/arch/tile/lib/spinlock_32.c
+++ b/arch/tile/lib/spinlock_32.c
@@ -144,7 +144,7 @@
 	for (;;) {
 		__insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 1);
 		val = __insn_tns((int *)&rwlock->lock);
-		if (likely(val & 1) == 0) {
+		if (likely((val & 1) == 0)) {
 			rwlock->lock = val - (1 << _RD_COUNT_SHIFT);
 			__insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0);
 			break;
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 5bed94e..d523a6c 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -82,6 +82,7 @@
 	select CLKEVT_I8253
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG
 	select GENERIC_IOMAP
+	select DCACHE_WORD_ACCESS if !DEBUG_PAGEALLOC
 
 config INSTRUCTION_DECODER
 	def_bool (KPROBES || PERF_EVENTS)
@@ -179,6 +180,9 @@
 config ARCH_HAS_CACHE_LINE_SIZE
 	def_bool y
 
+config ARCH_HAS_CPU_AUTOPROBE
+	def_bool y
+
 config HAVE_SETUP_PER_CPU_AREA
 	def_bool y
 
diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c
index 545d0ce..b3350bd 100644
--- a/arch/x86/crypto/aesni-intel_glue.c
+++ b/arch/x86/crypto/aesni-intel_glue.c
@@ -28,6 +28,7 @@
 #include <crypto/aes.h>
 #include <crypto/cryptd.h>
 #include <crypto/ctr.h>
+#include <asm/cpu_device_id.h>
 #include <asm/i387.h>
 #include <asm/aes.h>
 #include <crypto/scatterwalk.h>
@@ -1253,14 +1254,19 @@
 };
 #endif
 
+
+static const struct x86_cpu_id aesni_cpu_id[] = {
+	X86_FEATURE_MATCH(X86_FEATURE_AES),
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, aesni_cpu_id);
+
 static int __init aesni_init(void)
 {
 	int err;
 
-	if (!cpu_has_aes) {
-		printk(KERN_INFO "Intel AES-NI instructions are not detected.\n");
+	if (!x86_match_cpu(aesni_cpu_id))
 		return -ENODEV;
-	}
 
 	if ((err = crypto_fpu_init()))
 		goto fpu_err;
diff --git a/arch/x86/crypto/crc32c-intel.c b/arch/x86/crypto/crc32c-intel.c
index b9d0026..493f959 100644
--- a/arch/x86/crypto/crc32c-intel.c
+++ b/arch/x86/crypto/crc32c-intel.c
@@ -31,6 +31,7 @@
 #include <crypto/internal/hash.h>
 
 #include <asm/cpufeature.h>
+#include <asm/cpu_device_id.h>
 
 #define CHKSUM_BLOCK_SIZE	1
 #define CHKSUM_DIGEST_SIZE	4
@@ -173,13 +174,17 @@
 	}
 };
 
+static const struct x86_cpu_id crc32c_cpu_id[] = {
+	X86_FEATURE_MATCH(X86_FEATURE_XMM4_2),
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, crc32c_cpu_id);
 
 static int __init crc32c_intel_mod_init(void)
 {
-	if (cpu_has_xmm4_2)
-		return crypto_register_shash(&alg);
-	else
+	if (!x86_match_cpu(crc32c_cpu_id))
 		return -ENODEV;
+	return crypto_register_shash(&alg);
 }
 
 static void __exit crc32c_intel_mod_fini(void)
diff --git a/arch/x86/crypto/ghash-clmulni-intel_glue.c b/arch/x86/crypto/ghash-clmulni-intel_glue.c
index 976aa64..b4bf0a6 100644
--- a/arch/x86/crypto/ghash-clmulni-intel_glue.c
+++ b/arch/x86/crypto/ghash-clmulni-intel_glue.c
@@ -20,6 +20,7 @@
 #include <crypto/gf128mul.h>
 #include <crypto/internal/hash.h>
 #include <asm/i387.h>
+#include <asm/cpu_device_id.h>
 
 #define GHASH_BLOCK_SIZE	16
 #define GHASH_DIGEST_SIZE	16
@@ -294,15 +295,18 @@
 	},
 };
 
+static const struct x86_cpu_id pcmul_cpu_id[] = {
+	X86_FEATURE_MATCH(X86_FEATURE_PCLMULQDQ), /* Pickle-Mickle-Duck */
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, pcmul_cpu_id);
+
 static int __init ghash_pclmulqdqni_mod_init(void)
 {
 	int err;
 
-	if (!cpu_has_pclmulqdq) {
-		printk(KERN_INFO "Intel PCLMULQDQ-NI instructions are not"
-		       " detected.\n");
+	if (!x86_match_cpu(pcmul_cpu_id))
 		return -ENODEV;
-	}
 
 	err = crypto_register_shash(&ghash_alg);
 	if (err)
diff --git a/arch/x86/include/asm/cpu_device_id.h b/arch/x86/include/asm/cpu_device_id.h
new file mode 100644
index 0000000..ff501e5
--- /dev/null
+++ b/arch/x86/include/asm/cpu_device_id.h
@@ -0,0 +1,13 @@
+#ifndef _CPU_DEVICE_ID
+#define _CPU_DEVICE_ID 1
+
+/*
+ * Declare drivers belonging to specific x86 CPUs
+ * Similar in spirit to pci_device_id and related PCI functions
+ */
+
+#include <linux/mod_devicetable.h>
+
+extern const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match);
+
+#endif
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 8d67d42..dcb839e 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -177,6 +177,7 @@
 #define X86_FEATURE_PLN		(7*32+ 5) /* Intel Power Limit Notification */
 #define X86_FEATURE_PTS		(7*32+ 6) /* Intel Package Thermal Status */
 #define X86_FEATURE_DTS		(7*32+ 7) /* Digital Thermal Sensor */
+#define X86_FEATURE_HW_PSTATE	(7*32+ 8) /* AMD HW-PState */
 
 /* Virtualization flags: Linux defined, word 8 */
 #define X86_FEATURE_TPR_SHADOW  (8*32+ 0) /* Intel TPR Shadow */
diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
index da0b3ca..382f75d 100644
--- a/arch/x86/include/asm/hardirq.h
+++ b/arch/x86/include/asm/hardirq.h
@@ -7,7 +7,6 @@
 typedef struct {
 	unsigned int __softirq_pending;
 	unsigned int __nmi_count;	/* arch dependent */
-	unsigned int irq0_irqs;
 #ifdef CONFIG_X86_LOCAL_APIC
 	unsigned int apic_timer_irqs;	/* arch dependent */
 	unsigned int irq_spurious_count;
diff --git a/arch/x86/include/asm/inat.h b/arch/x86/include/asm/inat.h
index 205b063..74a2e31 100644
--- a/arch/x86/include/asm/inat.h
+++ b/arch/x86/include/asm/inat.h
@@ -97,11 +97,12 @@
 
 /* Attribute search APIs */
 extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode);
+extern int inat_get_last_prefix_id(insn_byte_t last_pfx);
 extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode,
-					     insn_byte_t last_pfx,
+					     int lpfx_id,
 					     insn_attr_t esc_attr);
 extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm,
-					    insn_byte_t last_pfx,
+					    int lpfx_id,
 					    insn_attr_t esc_attr);
 extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode,
 					  insn_byte_t vex_m,
diff --git a/arch/x86/include/asm/insn.h b/arch/x86/include/asm/insn.h
index 74df3f1..48eb30a 100644
--- a/arch/x86/include/asm/insn.h
+++ b/arch/x86/include/asm/insn.h
@@ -96,12 +96,6 @@
 #define X86_VEX_P(vex)	((vex) & 0x03)		/* VEX3 Byte2, VEX2 Byte1 */
 #define X86_VEX_M_MAX	0x1f			/* VEX3.M Maximum value */
 
-/* The last prefix is needed for two-byte and three-byte opcodes */
-static inline insn_byte_t insn_last_prefix(struct insn *insn)
-{
-	return insn->prefixes.bytes[3];
-}
-
 extern void insn_init(struct insn *insn, const void *kaddr, int x86_64);
 extern void insn_get_prefixes(struct insn *insn);
 extern void insn_get_opcode(struct insn *insn);
@@ -160,6 +154,18 @@
 		return X86_VEX_P(insn->vex_prefix.bytes[2]);
 }
 
+/* Get the last prefix id from last prefix or VEX prefix */
+static inline int insn_last_prefix_id(struct insn *insn)
+{
+	if (insn_is_avx(insn))
+		return insn_vex_p_bits(insn);	/* VEX_p is a SIMD prefix id */
+
+	if (insn->prefixes.bytes[3])
+		return inat_get_last_prefix_id(insn->prefixes.bytes[3]);
+
+	return 0;
+}
+
 /* Offset of each field from kaddr */
 static inline int insn_offset_rex_prefix(struct insn *insn)
 {
diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h
index a32b18c..3a16c14 100644
--- a/arch/x86/include/asm/jump_label.h
+++ b/arch/x86/include/asm/jump_label.h
@@ -9,12 +9,12 @@
 
 #define JUMP_LABEL_NOP_SIZE 5
 
-#define JUMP_LABEL_INITIAL_NOP ".byte 0xe9 \n\t .long 0\n\t"
+#define STATIC_KEY_INITIAL_NOP ".byte 0xe9 \n\t .long 0\n\t"
 
-static __always_inline bool arch_static_branch(struct jump_label_key *key)
+static __always_inline bool arch_static_branch(struct static_key *key)
 {
 	asm goto("1:"
-		JUMP_LABEL_INITIAL_NOP
+		STATIC_KEY_INITIAL_NOP
 		".pushsection __jump_table,  \"aw\" \n\t"
 		_ASM_ALIGN "\n\t"
 		_ASM_PTR "1b, %l[l_yes], %c0 \n\t"
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index a6962d9..ccb8059 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -56,6 +56,13 @@
 #define MSR_OFFCORE_RSP_0		0x000001a6
 #define MSR_OFFCORE_RSP_1		0x000001a7
 
+#define MSR_LBR_SELECT			0x000001c8
+#define MSR_LBR_TOS			0x000001c9
+#define MSR_LBR_NHM_FROM		0x00000680
+#define MSR_LBR_NHM_TO			0x000006c0
+#define MSR_LBR_CORE_FROM		0x00000040
+#define MSR_LBR_CORE_TO			0x00000060
+
 #define MSR_IA32_PEBS_ENABLE		0x000003f1
 #define MSR_IA32_DS_AREA		0x00000600
 #define MSR_IA32_PERF_CAPABILITIES	0x00000345
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index a7d2db9..c0180fd 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -230,9 +230,9 @@
 	return PVOP_CALL0(unsigned long long, pv_time_ops.sched_clock);
 }
 
-struct jump_label_key;
-extern struct jump_label_key paravirt_steal_enabled;
-extern struct jump_label_key paravirt_steal_rq_enabled;
+struct static_key;
+extern struct static_key paravirt_steal_enabled;
+extern struct static_key paravirt_steal_rq_enabled;
 
 static inline u64 paravirt_steal_clock(int cpu)
 {
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index 461ce43..e8fb2c7 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -188,8 +188,6 @@
 #ifdef CONFIG_PERF_EVENTS
 extern void perf_events_lapic_init(void);
 
-#define PERF_EVENT_INDEX_OFFSET			0
-
 /*
  * Abuse bit 3 of the cpu eflags register to indicate proper PEBS IP fixups.
  * This flag is otherwise unused and ABI specified to be 0, so nobody should
diff --git a/arch/x86/include/asm/timer.h b/arch/x86/include/asm/timer.h
index 431793e..34baa0e 100644
--- a/arch/x86/include/asm/timer.h
+++ b/arch/x86/include/asm/timer.h
@@ -57,14 +57,10 @@
 
 static inline unsigned long long __cycles_2_ns(unsigned long long cyc)
 {
-	unsigned long long quot;
-	unsigned long long rem;
 	int cpu = smp_processor_id();
 	unsigned long long ns = per_cpu(cyc2ns_offset, cpu);
-	quot = (cyc >> CYC2NS_SCALE_FACTOR);
-	rem = cyc & ((1ULL << CYC2NS_SCALE_FACTOR) - 1);
-	ns += quot * per_cpu(cyc2ns, cpu) +
-		((rem * per_cpu(cyc2ns, cpu)) >> CYC2NS_SCALE_FACTOR);
+	ns += mult_frac(cyc, per_cpu(cyc2ns, cpu),
+			(1UL << CYC2NS_SCALE_FACTOR));
 	return ns;
 }
 
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 5369059..532d2e0 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -69,6 +69,7 @@
 obj-$(CONFIG_KEXEC)		+= relocate_kernel_$(BITS).o crash.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump_$(BITS).o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
+obj-$(CONFIG_OPTPROBES)		+= kprobes-opt.o
 obj-$(CONFIG_MODULES)		+= module.o
 obj-$(CONFIG_DOUBLEFAULT) 	+= doublefault_32.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index 25f24dc..6ab6aa2 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -16,6 +16,7 @@
 obj-y			+= proc.o capflags.o powerflags.o common.o
 obj-y			+= vmware.o hypervisor.o sched.o mshyperv.o
 obj-y			+= rdrand.o
+obj-y			+= match.o
 
 obj-$(CONFIG_X86_32)	+= bugs.o
 obj-$(CONFIG_X86_64)	+= bugs_64.o
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index f4773f4..0a44b90 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -5,6 +5,7 @@
 #include <linux/mm.h>
 
 #include <linux/io.h>
+#include <linux/sched.h>
 #include <asm/processor.h>
 #include <asm/apic.h>
 #include <asm/cpu.h>
@@ -456,6 +457,8 @@
 	if (c->x86_power & (1 << 8)) {
 		set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
 		set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC);
+		if (!check_tsc_unstable())
+			sched_clock_stable = 1;
 	}
 
 #ifdef CONFIG_X86_64
diff --git a/arch/x86/kernel/cpu/match.c b/arch/x86/kernel/cpu/match.c
new file mode 100644
index 0000000..5502b28
--- /dev/null
+++ b/arch/x86/kernel/cpu/match.c
@@ -0,0 +1,91 @@
+#include <asm/cpu_device_id.h>
+#include <asm/processor.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+/**
+ * x86_match_cpu - match current CPU again an array of x86_cpu_ids
+ * @match: Pointer to array of x86_cpu_ids. Last entry terminated with
+ *         {}.
+ *
+ * Return the entry if the current CPU matches the entries in the
+ * passed x86_cpu_id match table. Otherwise NULL.  The match table
+ * contains vendor (X86_VENDOR_*), family, model and feature bits or
+ * respective wildcard entries.
+ *
+ * A typical table entry would be to match a specific CPU
+ * { X86_VENDOR_INTEL, 6, 0x12 }
+ * or to match a specific CPU feature
+ * { X86_FEATURE_MATCH(X86_FEATURE_FOOBAR) }
+ *
+ * Fields can be wildcarded with %X86_VENDOR_ANY, %X86_FAMILY_ANY,
+ * %X86_MODEL_ANY, %X86_FEATURE_ANY or 0 (except for vendor)
+ *
+ * Arrays used to match for this should also be declared using
+ * MODULE_DEVICE_TABLE(x86_cpu, ...)
+ *
+ * This always matches against the boot cpu, assuming models and features are
+ * consistent over all CPUs.
+ */
+const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match)
+{
+	const struct x86_cpu_id *m;
+	struct cpuinfo_x86 *c = &boot_cpu_data;
+
+	for (m = match; m->vendor | m->family | m->model | m->feature; m++) {
+		if (m->vendor != X86_VENDOR_ANY && c->x86_vendor != m->vendor)
+			continue;
+		if (m->family != X86_FAMILY_ANY && c->x86 != m->family)
+			continue;
+		if (m->model != X86_MODEL_ANY && c->x86_model != m->model)
+			continue;
+		if (m->feature != X86_FEATURE_ANY && !cpu_has(c, m->feature))
+			continue;
+		return m;
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(x86_match_cpu);
+
+ssize_t arch_print_cpu_modalias(struct device *dev,
+				struct device_attribute *attr,
+				char *bufptr)
+{
+	int size = PAGE_SIZE;
+	int i, n;
+	char *buf = bufptr;
+
+	n = snprintf(buf, size, "x86cpu:vendor:%04X:family:%04X:"
+		     "model:%04X:feature:",
+		boot_cpu_data.x86_vendor,
+		boot_cpu_data.x86,
+		boot_cpu_data.x86_model);
+	size -= n;
+	buf += n;
+	size -= 1;
+	for (i = 0; i < NCAPINTS*32; i++) {
+		if (boot_cpu_has(i)) {
+			n = snprintf(buf, size, ",%04X", i);
+			if (n >= size) {
+				WARN(1, "x86 features overflow page\n");
+				break;
+			}
+			size -= n;
+			buf += n;
+		}
+	}
+	*buf++ = '\n';
+	return buf - bufptr;
+}
+
+int arch_cpu_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (buf) {
+		arch_print_cpu_modalias(NULL, NULL, buf);
+		add_uevent_var(env, "MODALIAS=%s", buf);
+		kfree(buf);
+	}
+	return 0;
+}
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 5adce10..0a18d16 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/cpu.h>
 #include <linux/bitops.h>
+#include <linux/device.h>
 
 #include <asm/apic.h>
 #include <asm/stacktrace.h>
@@ -31,6 +32,7 @@
 #include <asm/compat.h>
 #include <asm/smp.h>
 #include <asm/alternative.h>
+#include <asm/timer.h>
 
 #include "perf_event.h"
 
@@ -351,6 +353,36 @@
 	return 0;
 }
 
+/*
+ * check that branch_sample_type is compatible with
+ * settings needed for precise_ip > 1 which implies
+ * using the LBR to capture ALL taken branches at the
+ * priv levels of the measurement
+ */
+static inline int precise_br_compat(struct perf_event *event)
+{
+	u64 m = event->attr.branch_sample_type;
+	u64 b = 0;
+
+	/* must capture all branches */
+	if (!(m & PERF_SAMPLE_BRANCH_ANY))
+		return 0;
+
+	m &= PERF_SAMPLE_BRANCH_KERNEL | PERF_SAMPLE_BRANCH_USER;
+
+	if (!event->attr.exclude_user)
+		b |= PERF_SAMPLE_BRANCH_USER;
+
+	if (!event->attr.exclude_kernel)
+		b |= PERF_SAMPLE_BRANCH_KERNEL;
+
+	/*
+	 * ignore PERF_SAMPLE_BRANCH_HV, not supported on x86
+	 */
+
+	return m == b;
+}
+
 int x86_pmu_hw_config(struct perf_event *event)
 {
 	if (event->attr.precise_ip) {
@@ -367,6 +399,36 @@
 
 		if (event->attr.precise_ip > precise)
 			return -EOPNOTSUPP;
+		/*
+		 * check that PEBS LBR correction does not conflict with
+		 * whatever the user is asking with attr->branch_sample_type
+		 */
+		if (event->attr.precise_ip > 1) {
+			u64 *br_type = &event->attr.branch_sample_type;
+
+			if (has_branch_stack(event)) {
+				if (!precise_br_compat(event))
+					return -EOPNOTSUPP;
+
+				/* branch_sample_type is compatible */
+
+			} else {
+				/*
+				 * user did not specify  branch_sample_type
+				 *
+				 * For PEBS fixups, we capture all
+				 * the branches at the priv level of the
+				 * event.
+				 */
+				*br_type = PERF_SAMPLE_BRANCH_ANY;
+
+				if (!event->attr.exclude_user)
+					*br_type |= PERF_SAMPLE_BRANCH_USER;
+
+				if (!event->attr.exclude_kernel)
+					*br_type |= PERF_SAMPLE_BRANCH_KERNEL;
+			}
+		}
 	}
 
 	/*
@@ -424,6 +486,10 @@
 	/* mark unused */
 	event->hw.extra_reg.idx = EXTRA_REG_NONE;
 
+	/* mark not used */
+	event->hw.extra_reg.idx = EXTRA_REG_NONE;
+	event->hw.branch_reg.idx = EXTRA_REG_NONE;
+
 	return x86_pmu.hw_config(event);
 }
 
@@ -1210,6 +1276,8 @@
 		break;
 
 	case CPU_STARTING:
+		if (x86_pmu.attr_rdpmc)
+			set_in_cr4(X86_CR4_PCE);
 		if (x86_pmu.cpu_starting)
 			x86_pmu.cpu_starting(cpu);
 		break;
@@ -1319,6 +1387,8 @@
 		}
 	}
 
+	x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
+
 	pr_info("... version:                %d\n",     x86_pmu.version);
 	pr_info("... bit width:              %d\n",     x86_pmu.cntval_bits);
 	pr_info("... generic registers:      %d\n",     x86_pmu.num_counters);
@@ -1542,23 +1612,106 @@
 	return err;
 }
 
+static int x86_pmu_event_idx(struct perf_event *event)
+{
+	int idx = event->hw.idx;
+
+	if (x86_pmu.num_counters_fixed && idx >= X86_PMC_IDX_FIXED) {
+		idx -= X86_PMC_IDX_FIXED;
+		idx |= 1 << 30;
+	}
+
+	return idx + 1;
+}
+
+static ssize_t get_attr_rdpmc(struct device *cdev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	return snprintf(buf, 40, "%d\n", x86_pmu.attr_rdpmc);
+}
+
+static void change_rdpmc(void *info)
+{
+	bool enable = !!(unsigned long)info;
+
+	if (enable)
+		set_in_cr4(X86_CR4_PCE);
+	else
+		clear_in_cr4(X86_CR4_PCE);
+}
+
+static ssize_t set_attr_rdpmc(struct device *cdev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	unsigned long val = simple_strtoul(buf, NULL, 0);
+
+	if (!!val != !!x86_pmu.attr_rdpmc) {
+		x86_pmu.attr_rdpmc = !!val;
+		smp_call_function(change_rdpmc, (void *)val, 1);
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(rdpmc, S_IRUSR | S_IWUSR, get_attr_rdpmc, set_attr_rdpmc);
+
+static struct attribute *x86_pmu_attrs[] = {
+	&dev_attr_rdpmc.attr,
+	NULL,
+};
+
+static struct attribute_group x86_pmu_attr_group = {
+	.attrs = x86_pmu_attrs,
+};
+
+static const struct attribute_group *x86_pmu_attr_groups[] = {
+	&x86_pmu_attr_group,
+	NULL,
+};
+
+static void x86_pmu_flush_branch_stack(void)
+{
+	if (x86_pmu.flush_branch_stack)
+		x86_pmu.flush_branch_stack();
+}
+
 static struct pmu pmu = {
-	.pmu_enable	= x86_pmu_enable,
-	.pmu_disable	= x86_pmu_disable,
+	.pmu_enable		= x86_pmu_enable,
+	.pmu_disable		= x86_pmu_disable,
+
+	.attr_groups	= x86_pmu_attr_groups,
 
 	.event_init	= x86_pmu_event_init,
 
-	.add		= x86_pmu_add,
-	.del		= x86_pmu_del,
-	.start		= x86_pmu_start,
-	.stop		= x86_pmu_stop,
-	.read		= x86_pmu_read,
+	.add			= x86_pmu_add,
+	.del			= x86_pmu_del,
+	.start			= x86_pmu_start,
+	.stop			= x86_pmu_stop,
+	.read			= x86_pmu_read,
 
 	.start_txn	= x86_pmu_start_txn,
 	.cancel_txn	= x86_pmu_cancel_txn,
 	.commit_txn	= x86_pmu_commit_txn,
+
+	.event_idx	= x86_pmu_event_idx,
+	.flush_branch_stack	= x86_pmu_flush_branch_stack,
 };
 
+void perf_update_user_clock(struct perf_event_mmap_page *userpg, u64 now)
+{
+	if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
+		return;
+
+	if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
+		return;
+
+	userpg->time_mult = this_cpu_read(cyc2ns);
+	userpg->time_shift = CYC2NS_SCALE_FACTOR;
+	userpg->time_offset = this_cpu_read(cyc2ns_offset) - now;
+}
+
 /*
  * callchain support
  */
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index c30c807..8484e77 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -33,6 +33,7 @@
 
 	EXTRA_REG_RSP_0 = 0,	/* offcore_response_0 */
 	EXTRA_REG_RSP_1 = 1,	/* offcore_response_1 */
+	EXTRA_REG_LBR   = 2,	/* lbr_select */
 
 	EXTRA_REG_MAX		/* number of entries needed */
 };
@@ -130,6 +131,8 @@
 	void				*lbr_context;
 	struct perf_branch_stack	lbr_stack;
 	struct perf_branch_entry	lbr_entries[MAX_LBR_ENTRIES];
+	struct er_account		*lbr_sel;
+	u64				br_sel;
 
 	/*
 	 * Intel host/guest exclude bits
@@ -268,6 +271,29 @@
 	void (*func)(void);
 };
 
+union x86_pmu_config {
+	struct {
+		u64 event:8,
+		    umask:8,
+		    usr:1,
+		    os:1,
+		    edge:1,
+		    pc:1,
+		    interrupt:1,
+		    __reserved1:1,
+		    en:1,
+		    inv:1,
+		    cmask:8,
+		    event2:4,
+		    __reserved2:4,
+		    go:1,
+		    ho:1;
+	} bits;
+	u64 value;
+};
+
+#define X86_CONFIG(args...) ((union x86_pmu_config){.bits = {args}}).value
+
 /*
  * struct x86_pmu - generic x86 pmu
  */
@@ -309,10 +335,19 @@
 	struct x86_pmu_quirk *quirks;
 	int		perfctr_second_write;
 
+	/*
+	 * sysfs attrs
+	 */
+	int		attr_rdpmc;
+
+	/*
+	 * CPU Hotplug hooks
+	 */
 	int		(*cpu_prepare)(int cpu);
 	void		(*cpu_starting)(int cpu);
 	void		(*cpu_dying)(int cpu);
 	void		(*cpu_dead)(int cpu);
+	void		(*flush_branch_stack)(void);
 
 	/*
 	 * Intel Arch Perfmon v2+
@@ -334,6 +369,8 @@
 	 */
 	unsigned long	lbr_tos, lbr_from, lbr_to; /* MSR base regs       */
 	int		lbr_nr;			   /* hardware stack size */
+	u64		lbr_sel_mask;		   /* LBR_SELECT valid bits */
+	const int	*lbr_sel_map;		   /* lbr_select mappings */
 
 	/*
 	 * Extra registers for events
@@ -447,6 +484,15 @@
 
 extern struct event_constraint unconstrained;
 
+static inline bool kernel_ip(unsigned long ip)
+{
+#ifdef CONFIG_X86_32
+	return ip > PAGE_OFFSET;
+#else
+	return (long)ip < 0;
+#endif
+}
+
 #ifdef CONFIG_CPU_SUP_AMD
 
 int amd_pmu_init(void);
@@ -527,6 +573,10 @@
 
 void intel_pmu_lbr_init_atom(void);
 
+void intel_pmu_lbr_init_snb(void);
+
+int intel_pmu_setup_lbr_filter(struct perf_event *event);
+
 int p4_pmu_init(void);
 
 int p6_pmu_init(void);
diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c
index 67250a5..dd002fa 100644
--- a/arch/x86/kernel/cpu/perf_event_amd.c
+++ b/arch/x86/kernel/cpu/perf_event_amd.c
@@ -139,6 +139,9 @@
 	if (ret)
 		return ret;
 
+	if (has_branch_stack(event))
+		return -EOPNOTSUPP;
+
 	if (event->attr.exclude_host && event->attr.exclude_guest)
 		/*
 		 * When HO == GO == 1 the hardware treats that as GO == HO == 0
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index 3bd37bd..6a84e7f 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -385,14 +385,15 @@
 #define NHM_LOCAL_DRAM		(1 << 14)
 #define NHM_NON_DRAM		(1 << 15)
 
-#define NHM_ALL_DRAM		(NHM_REMOTE_DRAM|NHM_LOCAL_DRAM)
+#define NHM_LOCAL		(NHM_LOCAL_DRAM|NHM_REMOTE_CACHE_FWD)
+#define NHM_REMOTE		(NHM_REMOTE_DRAM)
 
 #define NHM_DMND_READ		(NHM_DMND_DATA_RD)
 #define NHM_DMND_WRITE		(NHM_DMND_RFO|NHM_DMND_WB)
 #define NHM_DMND_PREFETCH	(NHM_PF_DATA_RD|NHM_PF_DATA_RFO)
 
 #define NHM_L3_HIT	(NHM_UNCORE_HIT|NHM_OTHER_CORE_HIT_SNP|NHM_OTHER_CORE_HITM)
-#define NHM_L3_MISS	(NHM_NON_DRAM|NHM_ALL_DRAM|NHM_REMOTE_CACHE_FWD)
+#define NHM_L3_MISS	(NHM_NON_DRAM|NHM_LOCAL_DRAM|NHM_REMOTE_DRAM|NHM_REMOTE_CACHE_FWD)
 #define NHM_L3_ACCESS	(NHM_L3_HIT|NHM_L3_MISS)
 
 static __initconst const u64 nehalem_hw_cache_extra_regs
@@ -416,16 +417,16 @@
  },
  [ C(NODE) ] = {
 	[ C(OP_READ) ] = {
-		[ C(RESULT_ACCESS) ] = NHM_DMND_READ|NHM_ALL_DRAM,
-		[ C(RESULT_MISS)   ] = NHM_DMND_READ|NHM_REMOTE_DRAM,
+		[ C(RESULT_ACCESS) ] = NHM_DMND_READ|NHM_LOCAL|NHM_REMOTE,
+		[ C(RESULT_MISS)   ] = NHM_DMND_READ|NHM_REMOTE,
 	},
 	[ C(OP_WRITE) ] = {
-		[ C(RESULT_ACCESS) ] = NHM_DMND_WRITE|NHM_ALL_DRAM,
-		[ C(RESULT_MISS)   ] = NHM_DMND_WRITE|NHM_REMOTE_DRAM,
+		[ C(RESULT_ACCESS) ] = NHM_DMND_WRITE|NHM_LOCAL|NHM_REMOTE,
+		[ C(RESULT_MISS)   ] = NHM_DMND_WRITE|NHM_REMOTE,
 	},
 	[ C(OP_PREFETCH) ] = {
-		[ C(RESULT_ACCESS) ] = NHM_DMND_PREFETCH|NHM_ALL_DRAM,
-		[ C(RESULT_MISS)   ] = NHM_DMND_PREFETCH|NHM_REMOTE_DRAM,
+		[ C(RESULT_ACCESS) ] = NHM_DMND_PREFETCH|NHM_LOCAL|NHM_REMOTE,
+		[ C(RESULT_MISS)   ] = NHM_DMND_PREFETCH|NHM_REMOTE,
 	},
  },
 };
@@ -727,6 +728,19 @@
  },
 };
 
+static inline bool intel_pmu_needs_lbr_smpl(struct perf_event *event)
+{
+	/* user explicitly requested branch sampling */
+	if (has_branch_stack(event))
+		return true;
+
+	/* implicit branch sampling to correct PEBS skid */
+	if (x86_pmu.intel_cap.pebs_trap && event->attr.precise_ip > 1)
+		return true;
+
+	return false;
+}
+
 static void intel_pmu_disable_all(void)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
@@ -881,6 +895,13 @@
 	cpuc->intel_ctrl_guest_mask &= ~(1ull << hwc->idx);
 	cpuc->intel_ctrl_host_mask &= ~(1ull << hwc->idx);
 
+	/*
+	 * must disable before any actual event
+	 * because any event may be combined with LBR
+	 */
+	if (intel_pmu_needs_lbr_smpl(event))
+		intel_pmu_lbr_disable(event);
+
 	if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
 		intel_pmu_disable_fixed(hwc);
 		return;
@@ -935,6 +956,12 @@
 		intel_pmu_enable_bts(hwc->config);
 		return;
 	}
+	/*
+	 * must enabled before any actual event
+	 * because any event may be combined with LBR
+	 */
+	if (intel_pmu_needs_lbr_smpl(event))
+		intel_pmu_lbr_enable(event);
 
 	if (event->attr.exclude_host)
 		cpuc->intel_ctrl_guest_mask |= (1ull << hwc->idx);
@@ -1057,6 +1084,9 @@
 
 		data.period = event->hw.last_period;
 
+		if (has_branch_stack(event))
+			data.br_stack = &cpuc->lbr_stack;
+
 		if (perf_event_overflow(event, &data, regs))
 			x86_pmu_stop(event, 0);
 	}
@@ -1123,17 +1153,17 @@
  */
 static struct event_constraint *
 __intel_shared_reg_get_constraints(struct cpu_hw_events *cpuc,
-				   struct perf_event *event)
+				   struct perf_event *event,
+				   struct hw_perf_event_extra *reg)
 {
 	struct event_constraint *c = &emptyconstraint;
-	struct hw_perf_event_extra *reg = &event->hw.extra_reg;
 	struct er_account *era;
 	unsigned long flags;
 	int orig_idx = reg->idx;
 
 	/* already allocated shared msr */
 	if (reg->alloc)
-		return &unconstrained;
+		return NULL; /* call x86_get_event_constraint() */
 
 again:
 	era = &cpuc->shared_regs->regs[reg->idx];
@@ -1156,14 +1186,10 @@
 		reg->alloc = 1;
 
 		/*
-		 * All events using extra_reg are unconstrained.
-		 * Avoids calling x86_get_event_constraints()
-		 *
-		 * Must revisit if extra_reg controlling events
-		 * ever have constraints. Worst case we go through
-		 * the regular event constraint table.
+		 * need to call x86_get_event_constraint()
+		 * to check if associated event has constraints
 		 */
-		c = &unconstrained;
+		c = NULL;
 	} else if (intel_try_alt_er(event, orig_idx)) {
 		raw_spin_unlock_irqrestore(&era->lock, flags);
 		goto again;
@@ -1200,11 +1226,23 @@
 intel_shared_regs_constraints(struct cpu_hw_events *cpuc,
 			      struct perf_event *event)
 {
-	struct event_constraint *c = NULL;
+	struct event_constraint *c = NULL, *d;
+	struct hw_perf_event_extra *xreg, *breg;
 
-	if (event->hw.extra_reg.idx != EXTRA_REG_NONE)
-		c = __intel_shared_reg_get_constraints(cpuc, event);
-
+	xreg = &event->hw.extra_reg;
+	if (xreg->idx != EXTRA_REG_NONE) {
+		c = __intel_shared_reg_get_constraints(cpuc, event, xreg);
+		if (c == &emptyconstraint)
+			return c;
+	}
+	breg = &event->hw.branch_reg;
+	if (breg->idx != EXTRA_REG_NONE) {
+		d = __intel_shared_reg_get_constraints(cpuc, event, breg);
+		if (d == &emptyconstraint) {
+			__intel_shared_reg_put_constraints(cpuc, xreg);
+			c = d;
+		}
+	}
 	return c;
 }
 
@@ -1252,6 +1290,10 @@
 	reg = &event->hw.extra_reg;
 	if (reg->idx != EXTRA_REG_NONE)
 		__intel_shared_reg_put_constraints(cpuc, reg);
+
+	reg = &event->hw.branch_reg;
+	if (reg->idx != EXTRA_REG_NONE)
+		__intel_shared_reg_put_constraints(cpuc, reg);
 }
 
 static void intel_put_event_constraints(struct cpu_hw_events *cpuc,
@@ -1287,12 +1329,19 @@
 		 *
 		 * Thereby we gain a PEBS capable cycle counter.
 		 */
-		u64 alt_config = 0x108000c0; /* INST_RETIRED.TOTAL_CYCLES */
+		u64 alt_config = X86_CONFIG(.event=0xc0, .inv=1, .cmask=16);
+
 
 		alt_config |= (event->hw.config & ~X86_RAW_EVENT_MASK);
 		event->hw.config = alt_config;
 	}
 
+	if (intel_pmu_needs_lbr_smpl(event)) {
+		ret = intel_pmu_setup_lbr_filter(event);
+		if (ret)
+			return ret;
+	}
+
 	if (event->attr.type != PERF_TYPE_RAW)
 		return 0;
 
@@ -1431,7 +1480,7 @@
 {
 	struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
 
-	if (!x86_pmu.extra_regs)
+	if (!(x86_pmu.extra_regs || x86_pmu.lbr_sel_map))
 		return NOTIFY_OK;
 
 	cpuc->shared_regs = allocate_shared_regs(cpu);
@@ -1453,22 +1502,28 @@
 	 */
 	intel_pmu_lbr_reset();
 
-	if (!cpuc->shared_regs || (x86_pmu.er_flags & ERF_NO_HT_SHARING))
+	cpuc->lbr_sel = NULL;
+
+	if (!cpuc->shared_regs)
 		return;
 
-	for_each_cpu(i, topology_thread_cpumask(cpu)) {
-		struct intel_shared_regs *pc;
+	if (!(x86_pmu.er_flags & ERF_NO_HT_SHARING)) {
+		for_each_cpu(i, topology_thread_cpumask(cpu)) {
+			struct intel_shared_regs *pc;
 
-		pc = per_cpu(cpu_hw_events, i).shared_regs;
-		if (pc && pc->core_id == core_id) {
-			cpuc->kfree_on_online = cpuc->shared_regs;
-			cpuc->shared_regs = pc;
-			break;
+			pc = per_cpu(cpu_hw_events, i).shared_regs;
+			if (pc && pc->core_id == core_id) {
+				cpuc->kfree_on_online = cpuc->shared_regs;
+				cpuc->shared_regs = pc;
+				break;
+			}
 		}
+		cpuc->shared_regs->core_id = core_id;
+		cpuc->shared_regs->refcnt++;
 	}
 
-	cpuc->shared_regs->core_id = core_id;
-	cpuc->shared_regs->refcnt++;
+	if (x86_pmu.lbr_sel_map)
+		cpuc->lbr_sel = &cpuc->shared_regs->regs[EXTRA_REG_LBR];
 }
 
 static void intel_pmu_cpu_dying(int cpu)
@@ -1486,6 +1541,18 @@
 	fini_debug_store_on_cpu(cpu);
 }
 
+static void intel_pmu_flush_branch_stack(void)
+{
+	/*
+	 * Intel LBR does not tag entries with the
+	 * PID of the current task, then we need to
+	 * flush it on ctxsw
+	 * For now, we simply reset it
+	 */
+	if (x86_pmu.lbr_nr)
+		intel_pmu_lbr_reset();
+}
+
 static __initconst const struct x86_pmu intel_pmu = {
 	.name			= "Intel",
 	.handle_irq		= intel_pmu_handle_irq,
@@ -1513,6 +1580,7 @@
 	.cpu_starting		= intel_pmu_cpu_starting,
 	.cpu_dying		= intel_pmu_cpu_dying,
 	.guest_get_msrs		= intel_guest_get_msrs,
+	.flush_branch_stack	= intel_pmu_flush_branch_stack,
 };
 
 static __init void intel_clovertown_quirk(void)
@@ -1689,9 +1757,11 @@
 		x86_pmu.extra_regs = intel_nehalem_extra_regs;
 
 		/* UOPS_ISSUED.STALLED_CYCLES */
-		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x180010e;
+		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =
+			X86_CONFIG(.event=0x0e, .umask=0x01, .inv=1, .cmask=1);
 		/* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */
-		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1;
+		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] =
+			X86_CONFIG(.event=0xb1, .umask=0x3f, .inv=1, .cmask=1);
 
 		x86_add_quirk(intel_nehalem_quirk);
 
@@ -1726,9 +1796,11 @@
 		x86_pmu.er_flags |= ERF_HAS_RSP_1;
 
 		/* UOPS_ISSUED.STALLED_CYCLES */
-		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x180010e;
+		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =
+			X86_CONFIG(.event=0x0e, .umask=0x01, .inv=1, .cmask=1);
 		/* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */
-		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1;
+		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] =
+			X86_CONFIG(.event=0xb1, .umask=0x3f, .inv=1, .cmask=1);
 
 		pr_cont("Westmere events, ");
 		break;
@@ -1739,7 +1811,7 @@
 		memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
 		       sizeof(hw_cache_event_ids));
 
-		intel_pmu_lbr_init_nhm();
+		intel_pmu_lbr_init_snb();
 
 		x86_pmu.event_constraints = intel_snb_event_constraints;
 		x86_pmu.pebs_constraints = intel_snb_pebs_event_constraints;
@@ -1749,9 +1821,11 @@
 		x86_pmu.er_flags |= ERF_NO_HT_SHARING;
 
 		/* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */
-		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x180010e;
+		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =
+			X86_CONFIG(.event=0x0e, .umask=0x01, .inv=1, .cmask=1);
 		/* UOPS_DISPATCHED.THREAD,c=1,i=1 to count stall cycles*/
-		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x18001b1;
+		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] =
+			X86_CONFIG(.event=0xb1, .umask=0x01, .inv=1, .cmask=1);
 
 		pr_cont("SandyBridge events, ");
 		break;
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index d6bd49f..7f64df1 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -3,6 +3,7 @@
 #include <linux/slab.h>
 
 #include <asm/perf_event.h>
+#include <asm/insn.h>
 
 #include "perf_event.h"
 
@@ -439,9 +440,6 @@
 	hwc->config &= ~ARCH_PERFMON_EVENTSEL_INT;
 
 	cpuc->pebs_enabled |= 1ULL << hwc->idx;
-
-	if (x86_pmu.intel_cap.pebs_trap && event->attr.precise_ip > 1)
-		intel_pmu_lbr_enable(event);
 }
 
 void intel_pmu_pebs_disable(struct perf_event *event)
@@ -454,9 +452,6 @@
 		wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled);
 
 	hwc->config |= ARCH_PERFMON_EVENTSEL_INT;
-
-	if (x86_pmu.intel_cap.pebs_trap && event->attr.precise_ip > 1)
-		intel_pmu_lbr_disable(event);
 }
 
 void intel_pmu_pebs_enable_all(void)
@@ -475,17 +470,6 @@
 		wrmsrl(MSR_IA32_PEBS_ENABLE, 0);
 }
 
-#include <asm/insn.h>
-
-static inline bool kernel_ip(unsigned long ip)
-{
-#ifdef CONFIG_X86_32
-	return ip > PAGE_OFFSET;
-#else
-	return (long)ip < 0;
-#endif
-}
-
 static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
@@ -572,6 +556,7 @@
 	 * both formats and we don't use the other fields in this
 	 * routine.
 	 */
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	struct pebs_record_core *pebs = __pebs;
 	struct perf_sample_data data;
 	struct pt_regs regs;
@@ -602,6 +587,9 @@
 	else
 		regs.flags &= ~PERF_EFLAGS_EXACT;
 
+	if (has_branch_stack(event))
+		data.br_stack = &cpuc->lbr_stack;
+
 	if (perf_event_overflow(event, &data, &regs))
 		x86_pmu_stop(event, 0);
 }
diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
index 47a7e63..520b426 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
@@ -3,6 +3,7 @@
 
 #include <asm/perf_event.h>
 #include <asm/msr.h>
+#include <asm/insn.h>
 
 #include "perf_event.h"
 
@@ -14,6 +15,100 @@
 };
 
 /*
+ * Intel LBR_SELECT bits
+ * Intel Vol3a, April 2011, Section 16.7 Table 16-10
+ *
+ * Hardware branch filter (not available on all CPUs)
+ */
+#define LBR_KERNEL_BIT		0 /* do not capture at ring0 */
+#define LBR_USER_BIT		1 /* do not capture at ring > 0 */
+#define LBR_JCC_BIT		2 /* do not capture conditional branches */
+#define LBR_REL_CALL_BIT	3 /* do not capture relative calls */
+#define LBR_IND_CALL_BIT	4 /* do not capture indirect calls */
+#define LBR_RETURN_BIT		5 /* do not capture near returns */
+#define LBR_IND_JMP_BIT		6 /* do not capture indirect jumps */
+#define LBR_REL_JMP_BIT		7 /* do not capture relative jumps */
+#define LBR_FAR_BIT		8 /* do not capture far branches */
+
+#define LBR_KERNEL	(1 << LBR_KERNEL_BIT)
+#define LBR_USER	(1 << LBR_USER_BIT)
+#define LBR_JCC		(1 << LBR_JCC_BIT)
+#define LBR_REL_CALL	(1 << LBR_REL_CALL_BIT)
+#define LBR_IND_CALL	(1 << LBR_IND_CALL_BIT)
+#define LBR_RETURN	(1 << LBR_RETURN_BIT)
+#define LBR_REL_JMP	(1 << LBR_REL_JMP_BIT)
+#define LBR_IND_JMP	(1 << LBR_IND_JMP_BIT)
+#define LBR_FAR		(1 << LBR_FAR_BIT)
+
+#define LBR_PLM (LBR_KERNEL | LBR_USER)
+
+#define LBR_SEL_MASK	0x1ff	/* valid bits in LBR_SELECT */
+#define LBR_NOT_SUPP	-1	/* LBR filter not supported */
+#define LBR_IGN		0	/* ignored */
+
+#define LBR_ANY		 \
+	(LBR_JCC	|\
+	 LBR_REL_CALL	|\
+	 LBR_IND_CALL	|\
+	 LBR_RETURN	|\
+	 LBR_REL_JMP	|\
+	 LBR_IND_JMP	|\
+	 LBR_FAR)
+
+#define LBR_FROM_FLAG_MISPRED  (1ULL << 63)
+
+#define for_each_branch_sample_type(x) \
+	for ((x) = PERF_SAMPLE_BRANCH_USER; \
+	     (x) < PERF_SAMPLE_BRANCH_MAX; (x) <<= 1)
+
+/*
+ * x86control flow change classification
+ * x86control flow changes include branches, interrupts, traps, faults
+ */
+enum {
+	X86_BR_NONE     = 0,      /* unknown */
+
+	X86_BR_USER     = 1 << 0, /* branch target is user */
+	X86_BR_KERNEL   = 1 << 1, /* branch target is kernel */
+
+	X86_BR_CALL     = 1 << 2, /* call */
+	X86_BR_RET      = 1 << 3, /* return */
+	X86_BR_SYSCALL  = 1 << 4, /* syscall */
+	X86_BR_SYSRET   = 1 << 5, /* syscall return */
+	X86_BR_INT      = 1 << 6, /* sw interrupt */
+	X86_BR_IRET     = 1 << 7, /* return from interrupt */
+	X86_BR_JCC      = 1 << 8, /* conditional */
+	X86_BR_JMP      = 1 << 9, /* jump */
+	X86_BR_IRQ      = 1 << 10,/* hw interrupt or trap or fault */
+	X86_BR_IND_CALL = 1 << 11,/* indirect calls */
+};
+
+#define X86_BR_PLM (X86_BR_USER | X86_BR_KERNEL)
+
+#define X86_BR_ANY       \
+	(X86_BR_CALL    |\
+	 X86_BR_RET     |\
+	 X86_BR_SYSCALL |\
+	 X86_BR_SYSRET  |\
+	 X86_BR_INT     |\
+	 X86_BR_IRET    |\
+	 X86_BR_JCC     |\
+	 X86_BR_JMP	 |\
+	 X86_BR_IRQ	 |\
+	 X86_BR_IND_CALL)
+
+#define X86_BR_ALL (X86_BR_PLM | X86_BR_ANY)
+
+#define X86_BR_ANY_CALL		 \
+	(X86_BR_CALL		|\
+	 X86_BR_IND_CALL	|\
+	 X86_BR_SYSCALL		|\
+	 X86_BR_IRQ		|\
+	 X86_BR_INT)
+
+static void intel_pmu_lbr_filter(struct cpu_hw_events *cpuc);
+
+/*
  * We only support LBR implementations that have FREEZE_LBRS_ON_PMI
  * otherwise it becomes near impossible to get a reliable stack.
  */
@@ -21,6 +116,10 @@
 static void __intel_pmu_lbr_enable(void)
 {
 	u64 debugctl;
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+
+	if (cpuc->lbr_sel)
+		wrmsrl(MSR_LBR_SELECT, cpuc->lbr_sel->config);
 
 	rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
 	debugctl |= (DEBUGCTLMSR_LBR | DEBUGCTLMSR_FREEZE_LBRS_ON_PMI);
@@ -76,11 +175,11 @@
 	 * Reset the LBR stack if we changed task context to
 	 * avoid data leaks.
 	 */
-
 	if (event->ctx->task && cpuc->lbr_context != event->ctx) {
 		intel_pmu_lbr_reset();
 		cpuc->lbr_context = event->ctx;
 	}
+	cpuc->br_sel = event->hw.branch_reg.reg;
 
 	cpuc->lbr_users++;
 }
@@ -95,8 +194,11 @@
 	cpuc->lbr_users--;
 	WARN_ON_ONCE(cpuc->lbr_users < 0);
 
-	if (cpuc->enabled && !cpuc->lbr_users)
+	if (cpuc->enabled && !cpuc->lbr_users) {
 		__intel_pmu_lbr_disable();
+		/* avoid stale pointer */
+		cpuc->lbr_context = NULL;
+	}
 }
 
 void intel_pmu_lbr_enable_all(void)
@@ -115,6 +217,9 @@
 		__intel_pmu_lbr_disable();
 }
 
+/*
+ * TOS = most recently recorded branch
+ */
 static inline u64 intel_pmu_lbr_tos(void)
 {
 	u64 tos;
@@ -142,15 +247,15 @@
 
 		rdmsrl(x86_pmu.lbr_from + lbr_idx, msr_lastbranch.lbr);
 
-		cpuc->lbr_entries[i].from  = msr_lastbranch.from;
-		cpuc->lbr_entries[i].to    = msr_lastbranch.to;
-		cpuc->lbr_entries[i].flags = 0;
+		cpuc->lbr_entries[i].from	= msr_lastbranch.from;
+		cpuc->lbr_entries[i].to		= msr_lastbranch.to;
+		cpuc->lbr_entries[i].mispred	= 0;
+		cpuc->lbr_entries[i].predicted	= 0;
+		cpuc->lbr_entries[i].reserved	= 0;
 	}
 	cpuc->lbr_stack.nr = i;
 }
 
-#define LBR_FROM_FLAG_MISPRED  (1ULL << 63)
-
 /*
  * Due to lack of segmentation in Linux the effective address (offset)
  * is the same as the linear address, allowing us to merge the LIP and EIP
@@ -165,19 +270,22 @@
 
 	for (i = 0; i < x86_pmu.lbr_nr; i++) {
 		unsigned long lbr_idx = (tos - i) & mask;
-		u64 from, to, flags = 0;
+		u64 from, to, mis = 0, pred = 0;
 
 		rdmsrl(x86_pmu.lbr_from + lbr_idx, from);
 		rdmsrl(x86_pmu.lbr_to   + lbr_idx, to);
 
 		if (lbr_format == LBR_FORMAT_EIP_FLAGS) {
-			flags = !!(from & LBR_FROM_FLAG_MISPRED);
+			mis = !!(from & LBR_FROM_FLAG_MISPRED);
+			pred = !mis;
 			from = (u64)((((s64)from) << 1) >> 1);
 		}
 
-		cpuc->lbr_entries[i].from  = from;
-		cpuc->lbr_entries[i].to    = to;
-		cpuc->lbr_entries[i].flags = flags;
+		cpuc->lbr_entries[i].from	= from;
+		cpuc->lbr_entries[i].to		= to;
+		cpuc->lbr_entries[i].mispred	= mis;
+		cpuc->lbr_entries[i].predicted	= pred;
+		cpuc->lbr_entries[i].reserved	= 0;
 	}
 	cpuc->lbr_stack.nr = i;
 }
@@ -193,28 +301,404 @@
 		intel_pmu_lbr_read_32(cpuc);
 	else
 		intel_pmu_lbr_read_64(cpuc);
+
+	intel_pmu_lbr_filter(cpuc);
 }
 
+/*
+ * SW filter is used:
+ * - in case there is no HW filter
+ * - in case the HW filter has errata or limitations
+ */
+static void intel_pmu_setup_sw_lbr_filter(struct perf_event *event)
+{
+	u64 br_type = event->attr.branch_sample_type;
+	int mask = 0;
+
+	if (br_type & PERF_SAMPLE_BRANCH_USER)
+		mask |= X86_BR_USER;
+
+	if (br_type & PERF_SAMPLE_BRANCH_KERNEL)
+		mask |= X86_BR_KERNEL;
+
+	/* we ignore BRANCH_HV here */
+
+	if (br_type & PERF_SAMPLE_BRANCH_ANY)
+		mask |= X86_BR_ANY;
+
+	if (br_type & PERF_SAMPLE_BRANCH_ANY_CALL)
+		mask |= X86_BR_ANY_CALL;
+
+	if (br_type & PERF_SAMPLE_BRANCH_ANY_RETURN)
+		mask |= X86_BR_RET | X86_BR_IRET | X86_BR_SYSRET;
+
+	if (br_type & PERF_SAMPLE_BRANCH_IND_CALL)
+		mask |= X86_BR_IND_CALL;
+	/*
+	 * stash actual user request into reg, it may
+	 * be used by fixup code for some CPU
+	 */
+	event->hw.branch_reg.reg = mask;
+}
+
+/*
+ * setup the HW LBR filter
+ * Used only when available, may not be enough to disambiguate
+ * all branches, may need the help of the SW filter
+ */
+static int intel_pmu_setup_hw_lbr_filter(struct perf_event *event)
+{
+	struct hw_perf_event_extra *reg;
+	u64 br_type = event->attr.branch_sample_type;
+	u64 mask = 0, m;
+	u64 v;
+
+	for_each_branch_sample_type(m) {
+		if (!(br_type & m))
+			continue;
+
+		v = x86_pmu.lbr_sel_map[m];
+		if (v == LBR_NOT_SUPP)
+			return -EOPNOTSUPP;
+
+		if (v != LBR_IGN)
+			mask |= v;
+	}
+	reg = &event->hw.branch_reg;
+	reg->idx = EXTRA_REG_LBR;
+
+	/* LBR_SELECT operates in suppress mode so invert mask */
+	reg->config = ~mask & x86_pmu.lbr_sel_mask;
+
+	return 0;
+}
+
+int intel_pmu_setup_lbr_filter(struct perf_event *event)
+{
+	int ret = 0;
+
+	/*
+	 * no LBR on this PMU
+	 */
+	if (!x86_pmu.lbr_nr)
+		return -EOPNOTSUPP;
+
+	/*
+	 * setup SW LBR filter
+	 */
+	intel_pmu_setup_sw_lbr_filter(event);
+
+	/*
+	 * setup HW LBR filter, if any
+	 */
+	if (x86_pmu.lbr_sel_map)
+		ret = intel_pmu_setup_hw_lbr_filter(event);
+
+	return ret;
+}
+
+/*
+ * return the type of control flow change at address "from"
+ * intruction is not necessarily a branch (in case of interrupt).
+ *
+ * The branch type returned also includes the priv level of the
+ * target of the control flow change (X86_BR_USER, X86_BR_KERNEL).
+ *
+ * If a branch type is unknown OR the instruction cannot be
+ * decoded (e.g., text page not present), then X86_BR_NONE is
+ * returned.
+ */
+static int branch_type(unsigned long from, unsigned long to)
+{
+	struct insn insn;
+	void *addr;
+	int bytes, size = MAX_INSN_SIZE;
+	int ret = X86_BR_NONE;
+	int ext, to_plm, from_plm;
+	u8 buf[MAX_INSN_SIZE];
+	int is64 = 0;
+
+	to_plm = kernel_ip(to) ? X86_BR_KERNEL : X86_BR_USER;
+	from_plm = kernel_ip(from) ? X86_BR_KERNEL : X86_BR_USER;
+
+	/*
+	 * maybe zero if lbr did not fill up after a reset by the time
+	 * we get a PMU interrupt
+	 */
+	if (from == 0 || to == 0)
+		return X86_BR_NONE;
+
+	if (from_plm == X86_BR_USER) {
+		/*
+		 * can happen if measuring at the user level only
+		 * and we interrupt in a kernel thread, e.g., idle.
+		 */
+		if (!current->mm)
+			return X86_BR_NONE;
+
+		/* may fail if text not present */
+		bytes = copy_from_user_nmi(buf, (void __user *)from, size);
+		if (bytes != size)
+			return X86_BR_NONE;
+
+		addr = buf;
+	} else
+		addr = (void *)from;
+
+	/*
+	 * decoder needs to know the ABI especially
+	 * on 64-bit systems running 32-bit apps
+	 */
+#ifdef CONFIG_X86_64
+	is64 = kernel_ip((unsigned long)addr) || !test_thread_flag(TIF_IA32);
+#endif
+	insn_init(&insn, addr, is64);
+	insn_get_opcode(&insn);
+
+	switch (insn.opcode.bytes[0]) {
+	case 0xf:
+		switch (insn.opcode.bytes[1]) {
+		case 0x05: /* syscall */
+		case 0x34: /* sysenter */
+			ret = X86_BR_SYSCALL;
+			break;
+		case 0x07: /* sysret */
+		case 0x35: /* sysexit */
+			ret = X86_BR_SYSRET;
+			break;
+		case 0x80 ... 0x8f: /* conditional */
+			ret = X86_BR_JCC;
+			break;
+		default:
+			ret = X86_BR_NONE;
+		}
+		break;
+	case 0x70 ... 0x7f: /* conditional */
+		ret = X86_BR_JCC;
+		break;
+	case 0xc2: /* near ret */
+	case 0xc3: /* near ret */
+	case 0xca: /* far ret */
+	case 0xcb: /* far ret */
+		ret = X86_BR_RET;
+		break;
+	case 0xcf: /* iret */
+		ret = X86_BR_IRET;
+		break;
+	case 0xcc ... 0xce: /* int */
+		ret = X86_BR_INT;
+		break;
+	case 0xe8: /* call near rel */
+	case 0x9a: /* call far absolute */
+		ret = X86_BR_CALL;
+		break;
+	case 0xe0 ... 0xe3: /* loop jmp */
+		ret = X86_BR_JCC;
+		break;
+	case 0xe9 ... 0xeb: /* jmp */
+		ret = X86_BR_JMP;
+		break;
+	case 0xff: /* call near absolute, call far absolute ind */
+		insn_get_modrm(&insn);
+		ext = (insn.modrm.bytes[0] >> 3) & 0x7;
+		switch (ext) {
+		case 2: /* near ind call */
+		case 3: /* far ind call */
+			ret = X86_BR_IND_CALL;
+			break;
+		case 4:
+		case 5:
+			ret = X86_BR_JMP;
+			break;
+		}
+		break;
+	default:
+		ret = X86_BR_NONE;
+	}
+	/*
+	 * interrupts, traps, faults (and thus ring transition) may
+	 * occur on any instructions. Thus, to classify them correctly,
+	 * we need to first look at the from and to priv levels. If they
+	 * are different and to is in the kernel, then it indicates
+	 * a ring transition. If the from instruction is not a ring
+	 * transition instr (syscall, systenter, int), then it means
+	 * it was a irq, trap or fault.
+	 *
+	 * we have no way of detecting kernel to kernel faults.
+	 */
+	if (from_plm == X86_BR_USER && to_plm == X86_BR_KERNEL
+	    && ret != X86_BR_SYSCALL && ret != X86_BR_INT)
+		ret = X86_BR_IRQ;
+
+	/*
+	 * branch priv level determined by target as
+	 * is done by HW when LBR_SELECT is implemented
+	 */
+	if (ret != X86_BR_NONE)
+		ret |= to_plm;
+
+	return ret;
+}
+
+/*
+ * implement actual branch filter based on user demand.
+ * Hardware may not exactly satisfy that request, thus
+ * we need to inspect opcodes. Mismatched branches are
+ * discarded. Therefore, the number of branches returned
+ * in PERF_SAMPLE_BRANCH_STACK sample may vary.
+ */
+static void
+intel_pmu_lbr_filter(struct cpu_hw_events *cpuc)
+{
+	u64 from, to;
+	int br_sel = cpuc->br_sel;
+	int i, j, type;
+	bool compress = false;
+
+	/* if sampling all branches, then nothing to filter */
+	if ((br_sel & X86_BR_ALL) == X86_BR_ALL)
+		return;
+
+	for (i = 0; i < cpuc->lbr_stack.nr; i++) {
+
+		from = cpuc->lbr_entries[i].from;
+		to = cpuc->lbr_entries[i].to;
+
+		type = branch_type(from, to);
+
+		/* if type does not correspond, then discard */
+		if (type == X86_BR_NONE || (br_sel & type) != type) {
+			cpuc->lbr_entries[i].from = 0;
+			compress = true;
+		}
+	}
+
+	if (!compress)
+		return;
+
+	/* remove all entries with from=0 */
+	for (i = 0; i < cpuc->lbr_stack.nr; ) {
+		if (!cpuc->lbr_entries[i].from) {
+			j = i;
+			while (++j < cpuc->lbr_stack.nr)
+				cpuc->lbr_entries[j-1] = cpuc->lbr_entries[j];
+			cpuc->lbr_stack.nr--;
+			if (!cpuc->lbr_entries[i].from)
+				continue;
+		}
+		i++;
+	}
+}
+
+/*
+ * Map interface branch filters onto LBR filters
+ */
+static const int nhm_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX] = {
+	[PERF_SAMPLE_BRANCH_ANY]	= LBR_ANY,
+	[PERF_SAMPLE_BRANCH_USER]	= LBR_USER,
+	[PERF_SAMPLE_BRANCH_KERNEL]	= LBR_KERNEL,
+	[PERF_SAMPLE_BRANCH_HV]		= LBR_IGN,
+	[PERF_SAMPLE_BRANCH_ANY_RETURN]	= LBR_RETURN | LBR_REL_JMP
+					| LBR_IND_JMP | LBR_FAR,
+	/*
+	 * NHM/WSM erratum: must include REL_JMP+IND_JMP to get CALL branches
+	 */
+	[PERF_SAMPLE_BRANCH_ANY_CALL] =
+	 LBR_REL_CALL | LBR_IND_CALL | LBR_REL_JMP | LBR_IND_JMP | LBR_FAR,
+	/*
+	 * NHM/WSM erratum: must include IND_JMP to capture IND_CALL
+	 */
+	[PERF_SAMPLE_BRANCH_IND_CALL] = LBR_IND_CALL | LBR_IND_JMP,
+};
+
+static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX] = {
+	[PERF_SAMPLE_BRANCH_ANY]	= LBR_ANY,
+	[PERF_SAMPLE_BRANCH_USER]	= LBR_USER,
+	[PERF_SAMPLE_BRANCH_KERNEL]	= LBR_KERNEL,
+	[PERF_SAMPLE_BRANCH_HV]		= LBR_IGN,
+	[PERF_SAMPLE_BRANCH_ANY_RETURN]	= LBR_RETURN | LBR_FAR,
+	[PERF_SAMPLE_BRANCH_ANY_CALL]	= LBR_REL_CALL | LBR_IND_CALL
+					| LBR_FAR,
+	[PERF_SAMPLE_BRANCH_IND_CALL]	= LBR_IND_CALL,
+};
+
+/* core */
 void intel_pmu_lbr_init_core(void)
 {
 	x86_pmu.lbr_nr     = 4;
-	x86_pmu.lbr_tos    = 0x01c9;
-	x86_pmu.lbr_from   = 0x40;
-	x86_pmu.lbr_to     = 0x60;
+	x86_pmu.lbr_tos    = MSR_LBR_TOS;
+	x86_pmu.lbr_from   = MSR_LBR_CORE_FROM;
+	x86_pmu.lbr_to     = MSR_LBR_CORE_TO;
+
+	/*
+	 * SW branch filter usage:
+	 * - compensate for lack of HW filter
+	 */
+	pr_cont("4-deep LBR, ");
 }
 
+/* nehalem/westmere */
 void intel_pmu_lbr_init_nhm(void)
 {
 	x86_pmu.lbr_nr     = 16;
-	x86_pmu.lbr_tos    = 0x01c9;
-	x86_pmu.lbr_from   = 0x680;
-	x86_pmu.lbr_to     = 0x6c0;
+	x86_pmu.lbr_tos    = MSR_LBR_TOS;
+	x86_pmu.lbr_from   = MSR_LBR_NHM_FROM;
+	x86_pmu.lbr_to     = MSR_LBR_NHM_TO;
+
+	x86_pmu.lbr_sel_mask = LBR_SEL_MASK;
+	x86_pmu.lbr_sel_map  = nhm_lbr_sel_map;
+
+	/*
+	 * SW branch filter usage:
+	 * - workaround LBR_SEL errata (see above)
+	 * - support syscall, sysret capture.
+	 *   That requires LBR_FAR but that means far
+	 *   jmp need to be filtered out
+	 */
+	pr_cont("16-deep LBR, ");
 }
 
+/* sandy bridge */
+void intel_pmu_lbr_init_snb(void)
+{
+	x86_pmu.lbr_nr	 = 16;
+	x86_pmu.lbr_tos	 = MSR_LBR_TOS;
+	x86_pmu.lbr_from = MSR_LBR_NHM_FROM;
+	x86_pmu.lbr_to   = MSR_LBR_NHM_TO;
+
+	x86_pmu.lbr_sel_mask = LBR_SEL_MASK;
+	x86_pmu.lbr_sel_map  = snb_lbr_sel_map;
+
+	/*
+	 * SW branch filter usage:
+	 * - support syscall, sysret capture.
+	 *   That requires LBR_FAR but that means far
+	 *   jmp need to be filtered out
+	 */
+	pr_cont("16-deep LBR, ");
+}
+
+/* atom */
 void intel_pmu_lbr_init_atom(void)
 {
+	/*
+	 * only models starting at stepping 10 seems
+	 * to have an operational LBR which can freeze
+	 * on PMU interrupt
+	 */
+	if (boot_cpu_data.x86_mask < 10) {
+		pr_cont("LBR disabled due to erratum");
+		return;
+	}
+
 	x86_pmu.lbr_nr	   = 8;
-	x86_pmu.lbr_tos    = 0x01c9;
-	x86_pmu.lbr_from   = 0x40;
-	x86_pmu.lbr_to     = 0x60;
+	x86_pmu.lbr_tos    = MSR_LBR_TOS;
+	x86_pmu.lbr_from   = MSR_LBR_CORE_FROM;
+	x86_pmu.lbr_to     = MSR_LBR_CORE_TO;
+
+	/*
+	 * SW branch filter usage:
+	 * - compensate for lack of HW filter
+	 */
+	pr_cont("8-deep LBR, ");
 }
diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
index c7f64e6..addf9e8 100644
--- a/arch/x86/kernel/cpu/scattered.c
+++ b/arch/x86/kernel/cpu/scattered.c
@@ -40,6 +40,7 @@
 		{ X86_FEATURE_EPB,		CR_ECX, 3, 0x00000006, 0 },
 		{ X86_FEATURE_XSAVEOPT,		CR_EAX,	0, 0x0000000d, 1 },
 		{ X86_FEATURE_CPB,		CR_EDX, 9, 0x80000007, 0 },
+		{ X86_FEATURE_HW_PSTATE,	CR_EDX, 7, 0x80000007, 0 },
 		{ X86_FEATURE_NPT,		CR_EDX, 0, 0x8000000a, 0 },
 		{ X86_FEATURE_LBRV,		CR_EDX, 1, 0x8000000a, 0 },
 		{ X86_FEATURE_SVML,		CR_EDX, 2, 0x8000000a, 0 },
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c
index 40fc861..58b7f27 100644
--- a/arch/x86/kernel/irq_32.c
+++ b/arch/x86/kernel/irq_32.c
@@ -100,13 +100,8 @@
 	irqctx->tinfo.task = curctx->tinfo.task;
 	irqctx->tinfo.previous_esp = current_stack_pointer;
 
-	/*
-	 * Copy the softirq bits in preempt_count so that the
-	 * softirq checks work in the hardirq context.
-	 */
-	irqctx->tinfo.preempt_count =
-		(irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) |
-		(curctx->tinfo.preempt_count & SOFTIRQ_MASK);
+	/* Copy the preempt_count so that the [soft]irq checks work. */
+	irqctx->tinfo.preempt_count = curctx->tinfo.preempt_count;
 
 	if (unlikely(overflow))
 		call_on_stack(print_stack_overflow, isp);
@@ -196,7 +191,7 @@
 	if (unlikely(!desc))
 		return false;
 
-	if (!execute_on_irq_stack(overflow, desc, irq)) {
+	if (user_mode_vm(regs) || !execute_on_irq_stack(overflow, desc, irq)) {
 		if (unlikely(overflow))
 			print_stack_overflow();
 		desc->handle_irq(irq, desc);
diff --git a/arch/x86/kernel/kprobes-common.h b/arch/x86/kernel/kprobes-common.h
new file mode 100644
index 0000000..3230b68
--- /dev/null
+++ b/arch/x86/kernel/kprobes-common.h
@@ -0,0 +1,102 @@
+#ifndef __X86_KERNEL_KPROBES_COMMON_H
+#define __X86_KERNEL_KPROBES_COMMON_H
+
+/* Kprobes and Optprobes common header */
+
+#ifdef CONFIG_X86_64
+#define SAVE_REGS_STRING			\
+	/* Skip cs, ip, orig_ax. */		\
+	"	subq $24, %rsp\n"		\
+	"	pushq %rdi\n"			\
+	"	pushq %rsi\n"			\
+	"	pushq %rdx\n"			\
+	"	pushq %rcx\n"			\
+	"	pushq %rax\n"			\
+	"	pushq %r8\n"			\
+	"	pushq %r9\n"			\
+	"	pushq %r10\n"			\
+	"	pushq %r11\n"			\
+	"	pushq %rbx\n"			\
+	"	pushq %rbp\n"			\
+	"	pushq %r12\n"			\
+	"	pushq %r13\n"			\
+	"	pushq %r14\n"			\
+	"	pushq %r15\n"
+#define RESTORE_REGS_STRING			\
+	"	popq %r15\n"			\
+	"	popq %r14\n"			\
+	"	popq %r13\n"			\
+	"	popq %r12\n"			\
+	"	popq %rbp\n"			\
+	"	popq %rbx\n"			\
+	"	popq %r11\n"			\
+	"	popq %r10\n"			\
+	"	popq %r9\n"			\
+	"	popq %r8\n"			\
+	"	popq %rax\n"			\
+	"	popq %rcx\n"			\
+	"	popq %rdx\n"			\
+	"	popq %rsi\n"			\
+	"	popq %rdi\n"			\
+	/* Skip orig_ax, ip, cs */		\
+	"	addq $24, %rsp\n"
+#else
+#define SAVE_REGS_STRING			\
+	/* Skip cs, ip, orig_ax and gs. */	\
+	"	subl $16, %esp\n"		\
+	"	pushl %fs\n"			\
+	"	pushl %es\n"			\
+	"	pushl %ds\n"			\
+	"	pushl %eax\n"			\
+	"	pushl %ebp\n"			\
+	"	pushl %edi\n"			\
+	"	pushl %esi\n"			\
+	"	pushl %edx\n"			\
+	"	pushl %ecx\n"			\
+	"	pushl %ebx\n"
+#define RESTORE_REGS_STRING			\
+	"	popl %ebx\n"			\
+	"	popl %ecx\n"			\
+	"	popl %edx\n"			\
+	"	popl %esi\n"			\
+	"	popl %edi\n"			\
+	"	popl %ebp\n"			\
+	"	popl %eax\n"			\
+	/* Skip ds, es, fs, gs, orig_ax, and ip. Note: don't pop cs here*/\
+	"	addl $24, %esp\n"
+#endif
+
+/* Ensure if the instruction can be boostable */
+extern int can_boost(kprobe_opcode_t *instruction);
+/* Recover instruction if given address is probed */
+extern unsigned long recover_probed_instruction(kprobe_opcode_t *buf,
+					 unsigned long addr);
+/*
+ * Copy an instruction and adjust the displacement if the instruction
+ * uses the %rip-relative addressing mode.
+ */
+extern int __copy_instruction(u8 *dest, u8 *src);
+
+/* Generate a relative-jump/call instruction */
+extern void synthesize_reljump(void *from, void *to);
+extern void synthesize_relcall(void *from, void *to);
+
+#ifdef	CONFIG_OPTPROBES
+extern int arch_init_optprobes(void);
+extern int setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter);
+extern unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr);
+#else	/* !CONFIG_OPTPROBES */
+static inline int arch_init_optprobes(void)
+{
+	return 0;
+}
+static inline int setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter)
+{
+	return 0;
+}
+static inline unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr)
+{
+	return addr;
+}
+#endif
+#endif
diff --git a/arch/x86/kernel/kprobes-opt.c b/arch/x86/kernel/kprobes-opt.c
new file mode 100644
index 0000000..c5e410e
--- /dev/null
+++ b/arch/x86/kernel/kprobes-opt.c
@@ -0,0 +1,512 @@
+/*
+ *  Kernel Probes Jump Optimization (Optprobes)
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2002, 2004
+ * Copyright (C) Hitachi Ltd., 2012
+ */
+#include <linux/kprobes.h>
+#include <linux/ptrace.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/hardirq.h>
+#include <linux/preempt.h>
+#include <linux/module.h>
+#include <linux/kdebug.h>
+#include <linux/kallsyms.h>
+#include <linux/ftrace.h>
+
+#include <asm/cacheflush.h>
+#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/alternative.h>
+#include <asm/insn.h>
+#include <asm/debugreg.h>
+
+#include "kprobes-common.h"
+
+unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr)
+{
+	struct optimized_kprobe *op;
+	struct kprobe *kp;
+	long offs;
+	int i;
+
+	for (i = 0; i < RELATIVEJUMP_SIZE; i++) {
+		kp = get_kprobe((void *)addr - i);
+		/* This function only handles jump-optimized kprobe */
+		if (kp && kprobe_optimized(kp)) {
+			op = container_of(kp, struct optimized_kprobe, kp);
+			/* If op->list is not empty, op is under optimizing */
+			if (list_empty(&op->list))
+				goto found;
+		}
+	}
+
+	return addr;
+found:
+	/*
+	 * If the kprobe can be optimized, original bytes which can be
+	 * overwritten by jump destination address. In this case, original
+	 * bytes must be recovered from op->optinsn.copied_insn buffer.
+	 */
+	memcpy(buf, (void *)addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+	if (addr == (unsigned long)kp->addr) {
+		buf[0] = kp->opcode;
+		memcpy(buf + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE);
+	} else {
+		offs = addr - (unsigned long)kp->addr - 1;
+		memcpy(buf, op->optinsn.copied_insn + offs, RELATIVE_ADDR_SIZE - offs);
+	}
+
+	return (unsigned long)buf;
+}
+
+/* Insert a move instruction which sets a pointer to eax/rdi (1st arg). */
+static void __kprobes synthesize_set_arg1(kprobe_opcode_t *addr, unsigned long val)
+{
+#ifdef CONFIG_X86_64
+	*addr++ = 0x48;
+	*addr++ = 0xbf;
+#else
+	*addr++ = 0xb8;
+#endif
+	*(unsigned long *)addr = val;
+}
+
+static void __used __kprobes kprobes_optinsn_template_holder(void)
+{
+	asm volatile (
+			".global optprobe_template_entry\n"
+			"optprobe_template_entry:\n"
+#ifdef CONFIG_X86_64
+			/* We don't bother saving the ss register */
+			"	pushq %rsp\n"
+			"	pushfq\n"
+			SAVE_REGS_STRING
+			"	movq %rsp, %rsi\n"
+			".global optprobe_template_val\n"
+			"optprobe_template_val:\n"
+			ASM_NOP5
+			ASM_NOP5
+			".global optprobe_template_call\n"
+			"optprobe_template_call:\n"
+			ASM_NOP5
+			/* Move flags to rsp */
+			"	movq 144(%rsp), %rdx\n"
+			"	movq %rdx, 152(%rsp)\n"
+			RESTORE_REGS_STRING
+			/* Skip flags entry */
+			"	addq $8, %rsp\n"
+			"	popfq\n"
+#else /* CONFIG_X86_32 */
+			"	pushf\n"
+			SAVE_REGS_STRING
+			"	movl %esp, %edx\n"
+			".global optprobe_template_val\n"
+			"optprobe_template_val:\n"
+			ASM_NOP5
+			".global optprobe_template_call\n"
+			"optprobe_template_call:\n"
+			ASM_NOP5
+			RESTORE_REGS_STRING
+			"	addl $4, %esp\n"	/* skip cs */
+			"	popf\n"
+#endif
+			".global optprobe_template_end\n"
+			"optprobe_template_end:\n");
+}
+
+#define TMPL_MOVE_IDX \
+	((long)&optprobe_template_val - (long)&optprobe_template_entry)
+#define TMPL_CALL_IDX \
+	((long)&optprobe_template_call - (long)&optprobe_template_entry)
+#define TMPL_END_IDX \
+	((long)&optprobe_template_end - (long)&optprobe_template_entry)
+
+#define INT3_SIZE sizeof(kprobe_opcode_t)
+
+/* Optimized kprobe call back function: called from optinsn */
+static void __kprobes optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
+{
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	unsigned long flags;
+
+	/* This is possible if op is under delayed unoptimizing */
+	if (kprobe_disabled(&op->kp))
+		return;
+
+	local_irq_save(flags);
+	if (kprobe_running()) {
+		kprobes_inc_nmissed_count(&op->kp);
+	} else {
+		/* Save skipped registers */
+#ifdef CONFIG_X86_64
+		regs->cs = __KERNEL_CS;
+#else
+		regs->cs = __KERNEL_CS | get_kernel_rpl();
+		regs->gs = 0;
+#endif
+		regs->ip = (unsigned long)op->kp.addr + INT3_SIZE;
+		regs->orig_ax = ~0UL;
+
+		__this_cpu_write(current_kprobe, &op->kp);
+		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+		opt_pre_handler(&op->kp, regs);
+		__this_cpu_write(current_kprobe, NULL);
+	}
+	local_irq_restore(flags);
+}
+
+static int __kprobes copy_optimized_instructions(u8 *dest, u8 *src)
+{
+	int len = 0, ret;
+
+	while (len < RELATIVEJUMP_SIZE) {
+		ret = __copy_instruction(dest + len, src + len);
+		if (!ret || !can_boost(dest + len))
+			return -EINVAL;
+		len += ret;
+	}
+	/* Check whether the address range is reserved */
+	if (ftrace_text_reserved(src, src + len - 1) ||
+	    alternatives_text_reserved(src, src + len - 1) ||
+	    jump_label_text_reserved(src, src + len - 1))
+		return -EBUSY;
+
+	return len;
+}
+
+/* Check whether insn is indirect jump */
+static int __kprobes insn_is_indirect_jump(struct insn *insn)
+{
+	return ((insn->opcode.bytes[0] == 0xff &&
+		(X86_MODRM_REG(insn->modrm.value) & 6) == 4) || /* Jump */
+		insn->opcode.bytes[0] == 0xea);	/* Segment based jump */
+}
+
+/* Check whether insn jumps into specified address range */
+static int insn_jump_into_range(struct insn *insn, unsigned long start, int len)
+{
+	unsigned long target = 0;
+
+	switch (insn->opcode.bytes[0]) {
+	case 0xe0:	/* loopne */
+	case 0xe1:	/* loope */
+	case 0xe2:	/* loop */
+	case 0xe3:	/* jcxz */
+	case 0xe9:	/* near relative jump */
+	case 0xeb:	/* short relative jump */
+		break;
+	case 0x0f:
+		if ((insn->opcode.bytes[1] & 0xf0) == 0x80) /* jcc near */
+			break;
+		return 0;
+	default:
+		if ((insn->opcode.bytes[0] & 0xf0) == 0x70) /* jcc short */
+			break;
+		return 0;
+	}
+	target = (unsigned long)insn->next_byte + insn->immediate.value;
+
+	return (start <= target && target <= start + len);
+}
+
+/* Decode whole function to ensure any instructions don't jump into target */
+static int __kprobes can_optimize(unsigned long paddr)
+{
+	unsigned long addr, size = 0, offset = 0;
+	struct insn insn;
+	kprobe_opcode_t buf[MAX_INSN_SIZE];
+
+	/* Lookup symbol including addr */
+	if (!kallsyms_lookup_size_offset(paddr, &size, &offset))
+		return 0;
+
+	/*
+	 * Do not optimize in the entry code due to the unstable
+	 * stack handling.
+	 */
+	if ((paddr >= (unsigned long)__entry_text_start) &&
+	    (paddr <  (unsigned long)__entry_text_end))
+		return 0;
+
+	/* Check there is enough space for a relative jump. */
+	if (size - offset < RELATIVEJUMP_SIZE)
+		return 0;
+
+	/* Decode instructions */
+	addr = paddr - offset;
+	while (addr < paddr - offset + size) { /* Decode until function end */
+		if (search_exception_tables(addr))
+			/*
+			 * Since some fixup code will jumps into this function,
+			 * we can't optimize kprobe in this function.
+			 */
+			return 0;
+		kernel_insn_init(&insn, (void *)recover_probed_instruction(buf, addr));
+		insn_get_length(&insn);
+		/* Another subsystem puts a breakpoint */
+		if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION)
+			return 0;
+		/* Recover address */
+		insn.kaddr = (void *)addr;
+		insn.next_byte = (void *)(addr + insn.length);
+		/* Check any instructions don't jump into target */
+		if (insn_is_indirect_jump(&insn) ||
+		    insn_jump_into_range(&insn, paddr + INT3_SIZE,
+					 RELATIVE_ADDR_SIZE))
+			return 0;
+		addr += insn.length;
+	}
+
+	return 1;
+}
+
+/* Check optimized_kprobe can actually be optimized. */
+int __kprobes arch_check_optimized_kprobe(struct optimized_kprobe *op)
+{
+	int i;
+	struct kprobe *p;
+
+	for (i = 1; i < op->optinsn.size; i++) {
+		p = get_kprobe(op->kp.addr + i);
+		if (p && !kprobe_disabled(p))
+			return -EEXIST;
+	}
+
+	return 0;
+}
+
+/* Check the addr is within the optimized instructions. */
+int __kprobes
+arch_within_optimized_kprobe(struct optimized_kprobe *op, unsigned long addr)
+{
+	return ((unsigned long)op->kp.addr <= addr &&
+		(unsigned long)op->kp.addr + op->optinsn.size > addr);
+}
+
+/* Free optimized instruction slot */
+static __kprobes
+void __arch_remove_optimized_kprobe(struct optimized_kprobe *op, int dirty)
+{
+	if (op->optinsn.insn) {
+		free_optinsn_slot(op->optinsn.insn, dirty);
+		op->optinsn.insn = NULL;
+		op->optinsn.size = 0;
+	}
+}
+
+void __kprobes arch_remove_optimized_kprobe(struct optimized_kprobe *op)
+{
+	__arch_remove_optimized_kprobe(op, 1);
+}
+
+/*
+ * Copy replacing target instructions
+ * Target instructions MUST be relocatable (checked inside)
+ * This is called when new aggr(opt)probe is allocated or reused.
+ */
+int __kprobes arch_prepare_optimized_kprobe(struct optimized_kprobe *op)
+{
+	u8 *buf;
+	int ret;
+	long rel;
+
+	if (!can_optimize((unsigned long)op->kp.addr))
+		return -EILSEQ;
+
+	op->optinsn.insn = get_optinsn_slot();
+	if (!op->optinsn.insn)
+		return -ENOMEM;
+
+	/*
+	 * Verify if the address gap is in 2GB range, because this uses
+	 * a relative jump.
+	 */
+	rel = (long)op->optinsn.insn - (long)op->kp.addr + RELATIVEJUMP_SIZE;
+	if (abs(rel) > 0x7fffffff)
+		return -ERANGE;
+
+	buf = (u8 *)op->optinsn.insn;
+
+	/* Copy instructions into the out-of-line buffer */
+	ret = copy_optimized_instructions(buf + TMPL_END_IDX, op->kp.addr);
+	if (ret < 0) {
+		__arch_remove_optimized_kprobe(op, 0);
+		return ret;
+	}
+	op->optinsn.size = ret;
+
+	/* Copy arch-dep-instance from template */
+	memcpy(buf, &optprobe_template_entry, TMPL_END_IDX);
+
+	/* Set probe information */
+	synthesize_set_arg1(buf + TMPL_MOVE_IDX, (unsigned long)op);
+
+	/* Set probe function call */
+	synthesize_relcall(buf + TMPL_CALL_IDX, optimized_callback);
+
+	/* Set returning jmp instruction at the tail of out-of-line buffer */
+	synthesize_reljump(buf + TMPL_END_IDX + op->optinsn.size,
+			   (u8 *)op->kp.addr + op->optinsn.size);
+
+	flush_icache_range((unsigned long) buf,
+			   (unsigned long) buf + TMPL_END_IDX +
+			   op->optinsn.size + RELATIVEJUMP_SIZE);
+	return 0;
+}
+
+#define MAX_OPTIMIZE_PROBES 256
+static struct text_poke_param *jump_poke_params;
+static struct jump_poke_buffer {
+	u8 buf[RELATIVEJUMP_SIZE];
+} *jump_poke_bufs;
+
+static void __kprobes setup_optimize_kprobe(struct text_poke_param *tprm,
+					    u8 *insn_buf,
+					    struct optimized_kprobe *op)
+{
+	s32 rel = (s32)((long)op->optinsn.insn -
+			((long)op->kp.addr + RELATIVEJUMP_SIZE));
+
+	/* Backup instructions which will be replaced by jump address */
+	memcpy(op->optinsn.copied_insn, op->kp.addr + INT3_SIZE,
+	       RELATIVE_ADDR_SIZE);
+
+	insn_buf[0] = RELATIVEJUMP_OPCODE;
+	*(s32 *)(&insn_buf[1]) = rel;
+
+	tprm->addr = op->kp.addr;
+	tprm->opcode = insn_buf;
+	tprm->len = RELATIVEJUMP_SIZE;
+}
+
+/*
+ * Replace breakpoints (int3) with relative jumps.
+ * Caller must call with locking kprobe_mutex and text_mutex.
+ */
+void __kprobes arch_optimize_kprobes(struct list_head *oplist)
+{
+	struct optimized_kprobe *op, *tmp;
+	int c = 0;
+
+	list_for_each_entry_safe(op, tmp, oplist, list) {
+		WARN_ON(kprobe_disabled(&op->kp));
+		/* Setup param */
+		setup_optimize_kprobe(&jump_poke_params[c],
+				      jump_poke_bufs[c].buf, op);
+		list_del_init(&op->list);
+		if (++c >= MAX_OPTIMIZE_PROBES)
+			break;
+	}
+
+	/*
+	 * text_poke_smp doesn't support NMI/MCE code modifying.
+	 * However, since kprobes itself also doesn't support NMI/MCE
+	 * code probing, it's not a problem.
+	 */
+	text_poke_smp_batch(jump_poke_params, c);
+}
+
+static void __kprobes setup_unoptimize_kprobe(struct text_poke_param *tprm,
+					      u8 *insn_buf,
+					      struct optimized_kprobe *op)
+{
+	/* Set int3 to first byte for kprobes */
+	insn_buf[0] = BREAKPOINT_INSTRUCTION;
+	memcpy(insn_buf + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE);
+
+	tprm->addr = op->kp.addr;
+	tprm->opcode = insn_buf;
+	tprm->len = RELATIVEJUMP_SIZE;
+}
+
+/*
+ * Recover original instructions and breakpoints from relative jumps.
+ * Caller must call with locking kprobe_mutex.
+ */
+extern void arch_unoptimize_kprobes(struct list_head *oplist,
+				    struct list_head *done_list)
+{
+	struct optimized_kprobe *op, *tmp;
+	int c = 0;
+
+	list_for_each_entry_safe(op, tmp, oplist, list) {
+		/* Setup param */
+		setup_unoptimize_kprobe(&jump_poke_params[c],
+					jump_poke_bufs[c].buf, op);
+		list_move(&op->list, done_list);
+		if (++c >= MAX_OPTIMIZE_PROBES)
+			break;
+	}
+
+	/*
+	 * text_poke_smp doesn't support NMI/MCE code modifying.
+	 * However, since kprobes itself also doesn't support NMI/MCE
+	 * code probing, it's not a problem.
+	 */
+	text_poke_smp_batch(jump_poke_params, c);
+}
+
+/* Replace a relative jump with a breakpoint (int3).  */
+void __kprobes arch_unoptimize_kprobe(struct optimized_kprobe *op)
+{
+	u8 buf[RELATIVEJUMP_SIZE];
+
+	/* Set int3 to first byte for kprobes */
+	buf[0] = BREAKPOINT_INSTRUCTION;
+	memcpy(buf + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE);
+	text_poke_smp(op->kp.addr, buf, RELATIVEJUMP_SIZE);
+}
+
+int  __kprobes
+setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter)
+{
+	struct optimized_kprobe *op;
+
+	if (p->flags & KPROBE_FLAG_OPTIMIZED) {
+		/* This kprobe is really able to run optimized path. */
+		op = container_of(p, struct optimized_kprobe, kp);
+		/* Detour through copied instructions */
+		regs->ip = (unsigned long)op->optinsn.insn + TMPL_END_IDX;
+		if (!reenter)
+			reset_current_kprobe();
+		preempt_enable_no_resched();
+		return 1;
+	}
+	return 0;
+}
+
+int __kprobes arch_init_optprobes(void)
+{
+	/* Allocate code buffer and parameter array */
+	jump_poke_bufs = kmalloc(sizeof(struct jump_poke_buffer) *
+				 MAX_OPTIMIZE_PROBES, GFP_KERNEL);
+	if (!jump_poke_bufs)
+		return -ENOMEM;
+
+	jump_poke_params = kmalloc(sizeof(struct text_poke_param) *
+				   MAX_OPTIMIZE_PROBES, GFP_KERNEL);
+	if (!jump_poke_params) {
+		kfree(jump_poke_bufs);
+		jump_poke_bufs = NULL;
+		return -ENOMEM;
+	}
+
+	return 0;
+}
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
index 7da647d..e213fc8 100644
--- a/arch/x86/kernel/kprobes.c
+++ b/arch/x86/kernel/kprobes.c
@@ -30,16 +30,15 @@
  *		<jkenisto@us.ibm.com> and Prasanna S Panchamukhi
  *		<prasanna@in.ibm.com> added function-return probes.
  * 2005-May	Rusty Lynch <rusty.lynch@intel.com>
- * 		Added function return probes functionality
+ *		Added function return probes functionality
  * 2006-Feb	Masami Hiramatsu <hiramatu@sdl.hitachi.co.jp> added
- * 		kprobe-booster and kretprobe-booster for i386.
+ *		kprobe-booster and kretprobe-booster for i386.
  * 2007-Dec	Masami Hiramatsu <mhiramat@redhat.com> added kprobe-booster
- * 		and kretprobe-booster for x86-64
+ *		and kretprobe-booster for x86-64
  * 2007-Dec	Masami Hiramatsu <mhiramat@redhat.com>, Arjan van de Ven
- * 		<arjan@infradead.org> and Jim Keniston <jkenisto@us.ibm.com>
- * 		unified x86 kprobes code.
+ *		<arjan@infradead.org> and Jim Keniston <jkenisto@us.ibm.com>
+ *		unified x86 kprobes code.
  */
-
 #include <linux/kprobes.h>
 #include <linux/ptrace.h>
 #include <linux/string.h>
@@ -59,6 +58,8 @@
 #include <asm/insn.h>
 #include <asm/debugreg.h>
 
+#include "kprobes-common.h"
+
 void jprobe_return_end(void);
 
 DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
@@ -108,6 +109,7 @@
 			      doesn't switch kernel stack.*/
 	{NULL, NULL}	/* Terminator */
 };
+
 const int kretprobe_blacklist_size = ARRAY_SIZE(kretprobe_blacklist);
 
 static void __kprobes __synthesize_relative_insn(void *from, void *to, u8 op)
@@ -123,11 +125,17 @@
 }
 
 /* Insert a jump instruction at address 'from', which jumps to address 'to'.*/
-static void __kprobes synthesize_reljump(void *from, void *to)
+void __kprobes synthesize_reljump(void *from, void *to)
 {
 	__synthesize_relative_insn(from, to, RELATIVEJUMP_OPCODE);
 }
 
+/* Insert a call instruction at address 'from', which calls address 'to'.*/
+void __kprobes synthesize_relcall(void *from, void *to)
+{
+	__synthesize_relative_insn(from, to, RELATIVECALL_OPCODE);
+}
+
 /*
  * Skip the prefixes of the instruction.
  */
@@ -151,7 +159,7 @@
  * Returns non-zero if opcode is boostable.
  * RIP relative instructions are adjusted at copying time in 64 bits mode
  */
-static int __kprobes can_boost(kprobe_opcode_t *opcodes)
+int __kprobes can_boost(kprobe_opcode_t *opcodes)
 {
 	kprobe_opcode_t opcode;
 	kprobe_opcode_t *orig_opcodes = opcodes;
@@ -207,13 +215,15 @@
 	}
 }
 
-/* Recover the probed instruction at addr for further analysis. */
-static int recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr)
+static unsigned long
+__recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)
 {
 	struct kprobe *kp;
+
 	kp = get_kprobe((void *)addr);
+	/* There is no probe, return original address */
 	if (!kp)
-		return -EINVAL;
+		return addr;
 
 	/*
 	 *  Basically, kp->ainsn.insn has an original instruction.
@@ -230,14 +240,29 @@
 	 */
 	memcpy(buf, kp->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
 	buf[0] = kp->opcode;
-	return 0;
+	return (unsigned long)buf;
+}
+
+/*
+ * Recover the probed instruction at addr for further analysis.
+ * Caller must lock kprobes by kprobe_mutex, or disable preemption
+ * for preventing to release referencing kprobes.
+ */
+unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr)
+{
+	unsigned long __addr;
+
+	__addr = __recover_optprobed_insn(buf, addr);
+	if (__addr != addr)
+		return __addr;
+
+	return __recover_probed_insn(buf, addr);
 }
 
 /* Check if paddr is at an instruction boundary */
 static int __kprobes can_probe(unsigned long paddr)
 {
-	int ret;
-	unsigned long addr, offset = 0;
+	unsigned long addr, __addr, offset = 0;
 	struct insn insn;
 	kprobe_opcode_t buf[MAX_INSN_SIZE];
 
@@ -247,26 +272,24 @@
 	/* Decode instructions */
 	addr = paddr - offset;
 	while (addr < paddr) {
-		kernel_insn_init(&insn, (void *)addr);
-		insn_get_opcode(&insn);
-
 		/*
 		 * Check if the instruction has been modified by another
 		 * kprobe, in which case we replace the breakpoint by the
 		 * original instruction in our buffer.
+		 * Also, jump optimization will change the breakpoint to
+		 * relative-jump. Since the relative-jump itself is
+		 * normally used, we just go through if there is no kprobe.
 		 */
-		if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION) {
-			ret = recover_probed_instruction(buf, addr);
-			if (ret)
-				/*
-				 * Another debugging subsystem might insert
-				 * this breakpoint. In that case, we can't
-				 * recover it.
-				 */
-				return 0;
-			kernel_insn_init(&insn, buf);
-		}
+		__addr = recover_probed_instruction(buf, addr);
+		kernel_insn_init(&insn, (void *)__addr);
 		insn_get_length(&insn);
+
+		/*
+		 * Another debugging subsystem might insert this breakpoint.
+		 * In that case, we can't recover it.
+		 */
+		if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION)
+			return 0;
 		addr += insn.length;
 	}
 
@@ -299,24 +322,16 @@
  * If not, return null.
  * Only applicable to 64-bit x86.
  */
-static int __kprobes __copy_instruction(u8 *dest, u8 *src, int recover)
+int __kprobes __copy_instruction(u8 *dest, u8 *src)
 {
 	struct insn insn;
-	int ret;
 	kprobe_opcode_t buf[MAX_INSN_SIZE];
 
-	kernel_insn_init(&insn, src);
-	if (recover) {
-		insn_get_opcode(&insn);
-		if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION) {
-			ret = recover_probed_instruction(buf,
-							 (unsigned long)src);
-			if (ret)
-				return 0;
-			kernel_insn_init(&insn, buf);
-		}
-	}
+	kernel_insn_init(&insn, (void *)recover_probed_instruction(buf, (unsigned long)src));
 	insn_get_length(&insn);
+	/* Another subsystem puts a breakpoint, failed to recover */
+	if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION)
+		return 0;
 	memcpy(dest, insn.kaddr, insn.length);
 
 #ifdef CONFIG_X86_64
@@ -337,8 +352,7 @@
 		 * extension of the original signed 32-bit displacement would
 		 * have given.
 		 */
-		newdisp = (u8 *) src + (s64) insn.displacement.value -
-			  (u8 *) dest;
+		newdisp = (u8 *) src + (s64) insn.displacement.value - (u8 *) dest;
 		BUG_ON((s64) (s32) newdisp != newdisp); /* Sanity check.  */
 		disp = (u8 *) dest + insn_offset_displacement(&insn);
 		*(s32 *) disp = (s32) newdisp;
@@ -349,18 +363,20 @@
 
 static void __kprobes arch_copy_kprobe(struct kprobe *p)
 {
-	/*
-	 * Copy an instruction without recovering int3, because it will be
-	 * put by another subsystem.
-	 */
-	__copy_instruction(p->ainsn.insn, p->addr, 0);
+	/* Copy an instruction with recovering if other optprobe modifies it.*/
+	__copy_instruction(p->ainsn.insn, p->addr);
 
-	if (can_boost(p->addr))
+	/*
+	 * __copy_instruction can modify the displacement of the instruction,
+	 * but it doesn't affect boostable check.
+	 */
+	if (can_boost(p->ainsn.insn))
 		p->ainsn.boostable = 0;
 	else
 		p->ainsn.boostable = -1;
 
-	p->opcode = *p->addr;
+	/* Also, displacement change doesn't affect the first byte */
+	p->opcode = p->ainsn.insn[0];
 }
 
 int __kprobes arch_prepare_kprobe(struct kprobe *p)
@@ -442,8 +458,8 @@
 	}
 }
 
-void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
-				      struct pt_regs *regs)
+void __kprobes
+arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
 	unsigned long *sara = stack_addr(regs);
 
@@ -453,16 +469,8 @@
 	*sara = (unsigned long) &kretprobe_trampoline;
 }
 
-#ifdef CONFIG_OPTPROBES
-static int  __kprobes setup_detour_execution(struct kprobe *p,
-					     struct pt_regs *regs,
-					     int reenter);
-#else
-#define setup_detour_execution(p, regs, reenter) (0)
-#endif
-
-static void __kprobes setup_singlestep(struct kprobe *p, struct pt_regs *regs,
-				       struct kprobe_ctlblk *kcb, int reenter)
+static void __kprobes
+setup_singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb, int reenter)
 {
 	if (setup_detour_execution(p, regs, reenter))
 		return;
@@ -504,8 +512,8 @@
  * within the handler. We save the original kprobes variables and just single
  * step on the instruction of the new probe without calling any user handlers.
  */
-static int __kprobes reenter_kprobe(struct kprobe *p, struct pt_regs *regs,
-				    struct kprobe_ctlblk *kcb)
+static int __kprobes
+reenter_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb)
 {
 	switch (kcb->kprobe_status) {
 	case KPROBE_HIT_SSDONE:
@@ -600,69 +608,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_X86_64
-#define SAVE_REGS_STRING		\
-	/* Skip cs, ip, orig_ax. */	\
-	"	subq $24, %rsp\n"	\
-	"	pushq %rdi\n"		\
-	"	pushq %rsi\n"		\
-	"	pushq %rdx\n"		\
-	"	pushq %rcx\n"		\
-	"	pushq %rax\n"		\
-	"	pushq %r8\n"		\
-	"	pushq %r9\n"		\
-	"	pushq %r10\n"		\
-	"	pushq %r11\n"		\
-	"	pushq %rbx\n"		\
-	"	pushq %rbp\n"		\
-	"	pushq %r12\n"		\
-	"	pushq %r13\n"		\
-	"	pushq %r14\n"		\
-	"	pushq %r15\n"
-#define RESTORE_REGS_STRING		\
-	"	popq %r15\n"		\
-	"	popq %r14\n"		\
-	"	popq %r13\n"		\
-	"	popq %r12\n"		\
-	"	popq %rbp\n"		\
-	"	popq %rbx\n"		\
-	"	popq %r11\n"		\
-	"	popq %r10\n"		\
-	"	popq %r9\n"		\
-	"	popq %r8\n"		\
-	"	popq %rax\n"		\
-	"	popq %rcx\n"		\
-	"	popq %rdx\n"		\
-	"	popq %rsi\n"		\
-	"	popq %rdi\n"		\
-	/* Skip orig_ax, ip, cs */	\
-	"	addq $24, %rsp\n"
-#else
-#define SAVE_REGS_STRING		\
-	/* Skip cs, ip, orig_ax and gs. */	\
-	"	subl $16, %esp\n"	\
-	"	pushl %fs\n"		\
-	"	pushl %es\n"		\
-	"	pushl %ds\n"		\
-	"	pushl %eax\n"		\
-	"	pushl %ebp\n"		\
-	"	pushl %edi\n"		\
-	"	pushl %esi\n"		\
-	"	pushl %edx\n"		\
-	"	pushl %ecx\n"		\
-	"	pushl %ebx\n"
-#define RESTORE_REGS_STRING		\
-	"	popl %ebx\n"		\
-	"	popl %ecx\n"		\
-	"	popl %edx\n"		\
-	"	popl %esi\n"		\
-	"	popl %edi\n"		\
-	"	popl %ebp\n"		\
-	"	popl %eax\n"		\
-	/* Skip ds, es, fs, gs, orig_ax, and ip. Note: don't pop cs here*/\
-	"	addl $24, %esp\n"
-#endif
-
 /*
  * When a retprobed function returns, this code saves registers and
  * calls trampoline_handler() runs, which calls the kretprobe's handler.
@@ -816,8 +761,8 @@
  * jump instruction after the copied instruction, that jumps to the next
  * instruction after the probepoint.
  */
-static void __kprobes resume_execution(struct kprobe *p,
-		struct pt_regs *regs, struct kprobe_ctlblk *kcb)
+static void __kprobes
+resume_execution(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb)
 {
 	unsigned long *tos = stack_addr(regs);
 	unsigned long copy_ip = (unsigned long)p->ainsn.insn;
@@ -996,8 +941,8 @@
 /*
  * Wrapper routine for handling exceptions.
  */
-int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
-				       unsigned long val, void *data)
+int __kprobes
+kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *data)
 {
 	struct die_args *args = data;
 	int ret = NOTIFY_DONE;
@@ -1107,466 +1052,9 @@
 	return 0;
 }
 
-
-#ifdef CONFIG_OPTPROBES
-
-/* Insert a call instruction at address 'from', which calls address 'to'.*/
-static void __kprobes synthesize_relcall(void *from, void *to)
-{
-	__synthesize_relative_insn(from, to, RELATIVECALL_OPCODE);
-}
-
-/* Insert a move instruction which sets a pointer to eax/rdi (1st arg). */
-static void __kprobes synthesize_set_arg1(kprobe_opcode_t *addr,
-					  unsigned long val)
-{
-#ifdef CONFIG_X86_64
-	*addr++ = 0x48;
-	*addr++ = 0xbf;
-#else
-	*addr++ = 0xb8;
-#endif
-	*(unsigned long *)addr = val;
-}
-
-static void __used __kprobes kprobes_optinsn_template_holder(void)
-{
-	asm volatile (
-			".global optprobe_template_entry\n"
-			"optprobe_template_entry: \n"
-#ifdef CONFIG_X86_64
-			/* We don't bother saving the ss register */
-			"	pushq %rsp\n"
-			"	pushfq\n"
-			SAVE_REGS_STRING
-			"	movq %rsp, %rsi\n"
-			".global optprobe_template_val\n"
-			"optprobe_template_val: \n"
-			ASM_NOP5
-			ASM_NOP5
-			".global optprobe_template_call\n"
-			"optprobe_template_call: \n"
-			ASM_NOP5
-			/* Move flags to rsp */
-			"	movq 144(%rsp), %rdx\n"
-			"	movq %rdx, 152(%rsp)\n"
-			RESTORE_REGS_STRING
-			/* Skip flags entry */
-			"	addq $8, %rsp\n"
-			"	popfq\n"
-#else /* CONFIG_X86_32 */
-			"	pushf\n"
-			SAVE_REGS_STRING
-			"	movl %esp, %edx\n"
-			".global optprobe_template_val\n"
-			"optprobe_template_val: \n"
-			ASM_NOP5
-			".global optprobe_template_call\n"
-			"optprobe_template_call: \n"
-			ASM_NOP5
-			RESTORE_REGS_STRING
-			"	addl $4, %esp\n"	/* skip cs */
-			"	popf\n"
-#endif
-			".global optprobe_template_end\n"
-			"optprobe_template_end: \n");
-}
-
-#define TMPL_MOVE_IDX \
-	((long)&optprobe_template_val - (long)&optprobe_template_entry)
-#define TMPL_CALL_IDX \
-	((long)&optprobe_template_call - (long)&optprobe_template_entry)
-#define TMPL_END_IDX \
-	((long)&optprobe_template_end - (long)&optprobe_template_entry)
-
-#define INT3_SIZE sizeof(kprobe_opcode_t)
-
-/* Optimized kprobe call back function: called from optinsn */
-static void __kprobes optimized_callback(struct optimized_kprobe *op,
-					 struct pt_regs *regs)
-{
-	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
-	unsigned long flags;
-
-	/* This is possible if op is under delayed unoptimizing */
-	if (kprobe_disabled(&op->kp))
-		return;
-
-	local_irq_save(flags);
-	if (kprobe_running()) {
-		kprobes_inc_nmissed_count(&op->kp);
-	} else {
-		/* Save skipped registers */
-#ifdef CONFIG_X86_64
-		regs->cs = __KERNEL_CS;
-#else
-		regs->cs = __KERNEL_CS | get_kernel_rpl();
-		regs->gs = 0;
-#endif
-		regs->ip = (unsigned long)op->kp.addr + INT3_SIZE;
-		regs->orig_ax = ~0UL;
-
-		__this_cpu_write(current_kprobe, &op->kp);
-		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
-		opt_pre_handler(&op->kp, regs);
-		__this_cpu_write(current_kprobe, NULL);
-	}
-	local_irq_restore(flags);
-}
-
-static int __kprobes copy_optimized_instructions(u8 *dest, u8 *src)
-{
-	int len = 0, ret;
-
-	while (len < RELATIVEJUMP_SIZE) {
-		ret = __copy_instruction(dest + len, src + len, 1);
-		if (!ret || !can_boost(dest + len))
-			return -EINVAL;
-		len += ret;
-	}
-	/* Check whether the address range is reserved */
-	if (ftrace_text_reserved(src, src + len - 1) ||
-	    alternatives_text_reserved(src, src + len - 1) ||
-	    jump_label_text_reserved(src, src + len - 1))
-		return -EBUSY;
-
-	return len;
-}
-
-/* Check whether insn is indirect jump */
-static int __kprobes insn_is_indirect_jump(struct insn *insn)
-{
-	return ((insn->opcode.bytes[0] == 0xff &&
-		(X86_MODRM_REG(insn->modrm.value) & 6) == 4) || /* Jump */
-		insn->opcode.bytes[0] == 0xea);	/* Segment based jump */
-}
-
-/* Check whether insn jumps into specified address range */
-static int insn_jump_into_range(struct insn *insn, unsigned long start, int len)
-{
-	unsigned long target = 0;
-
-	switch (insn->opcode.bytes[0]) {
-	case 0xe0:	/* loopne */
-	case 0xe1:	/* loope */
-	case 0xe2:	/* loop */
-	case 0xe3:	/* jcxz */
-	case 0xe9:	/* near relative jump */
-	case 0xeb:	/* short relative jump */
-		break;
-	case 0x0f:
-		if ((insn->opcode.bytes[1] & 0xf0) == 0x80) /* jcc near */
-			break;
-		return 0;
-	default:
-		if ((insn->opcode.bytes[0] & 0xf0) == 0x70) /* jcc short */
-			break;
-		return 0;
-	}
-	target = (unsigned long)insn->next_byte + insn->immediate.value;
-
-	return (start <= target && target <= start + len);
-}
-
-/* Decode whole function to ensure any instructions don't jump into target */
-static int __kprobes can_optimize(unsigned long paddr)
-{
-	int ret;
-	unsigned long addr, size = 0, offset = 0;
-	struct insn insn;
-	kprobe_opcode_t buf[MAX_INSN_SIZE];
-
-	/* Lookup symbol including addr */
-	if (!kallsyms_lookup_size_offset(paddr, &size, &offset))
-		return 0;
-
-	/*
-	 * Do not optimize in the entry code due to the unstable
-	 * stack handling.
-	 */
-	if ((paddr >= (unsigned long )__entry_text_start) &&
-	    (paddr <  (unsigned long )__entry_text_end))
-		return 0;
-
-	/* Check there is enough space for a relative jump. */
-	if (size - offset < RELATIVEJUMP_SIZE)
-		return 0;
-
-	/* Decode instructions */
-	addr = paddr - offset;
-	while (addr < paddr - offset + size) { /* Decode until function end */
-		if (search_exception_tables(addr))
-			/*
-			 * Since some fixup code will jumps into this function,
-			 * we can't optimize kprobe in this function.
-			 */
-			return 0;
-		kernel_insn_init(&insn, (void *)addr);
-		insn_get_opcode(&insn);
-		if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION) {
-			ret = recover_probed_instruction(buf, addr);
-			if (ret)
-				return 0;
-			kernel_insn_init(&insn, buf);
-		}
-		insn_get_length(&insn);
-		/* Recover address */
-		insn.kaddr = (void *)addr;
-		insn.next_byte = (void *)(addr + insn.length);
-		/* Check any instructions don't jump into target */
-		if (insn_is_indirect_jump(&insn) ||
-		    insn_jump_into_range(&insn, paddr + INT3_SIZE,
-					 RELATIVE_ADDR_SIZE))
-			return 0;
-		addr += insn.length;
-	}
-
-	return 1;
-}
-
-/* Check optimized_kprobe can actually be optimized. */
-int __kprobes arch_check_optimized_kprobe(struct optimized_kprobe *op)
-{
-	int i;
-	struct kprobe *p;
-
-	for (i = 1; i < op->optinsn.size; i++) {
-		p = get_kprobe(op->kp.addr + i);
-		if (p && !kprobe_disabled(p))
-			return -EEXIST;
-	}
-
-	return 0;
-}
-
-/* Check the addr is within the optimized instructions. */
-int __kprobes arch_within_optimized_kprobe(struct optimized_kprobe *op,
-					   unsigned long addr)
-{
-	return ((unsigned long)op->kp.addr <= addr &&
-		(unsigned long)op->kp.addr + op->optinsn.size > addr);
-}
-
-/* Free optimized instruction slot */
-static __kprobes
-void __arch_remove_optimized_kprobe(struct optimized_kprobe *op, int dirty)
-{
-	if (op->optinsn.insn) {
-		free_optinsn_slot(op->optinsn.insn, dirty);
-		op->optinsn.insn = NULL;
-		op->optinsn.size = 0;
-	}
-}
-
-void __kprobes arch_remove_optimized_kprobe(struct optimized_kprobe *op)
-{
-	__arch_remove_optimized_kprobe(op, 1);
-}
-
-/*
- * Copy replacing target instructions
- * Target instructions MUST be relocatable (checked inside)
- */
-int __kprobes arch_prepare_optimized_kprobe(struct optimized_kprobe *op)
-{
-	u8 *buf;
-	int ret;
-	long rel;
-
-	if (!can_optimize((unsigned long)op->kp.addr))
-		return -EILSEQ;
-
-	op->optinsn.insn = get_optinsn_slot();
-	if (!op->optinsn.insn)
-		return -ENOMEM;
-
-	/*
-	 * Verify if the address gap is in 2GB range, because this uses
-	 * a relative jump.
-	 */
-	rel = (long)op->optinsn.insn - (long)op->kp.addr + RELATIVEJUMP_SIZE;
-	if (abs(rel) > 0x7fffffff)
-		return -ERANGE;
-
-	buf = (u8 *)op->optinsn.insn;
-
-	/* Copy instructions into the out-of-line buffer */
-	ret = copy_optimized_instructions(buf + TMPL_END_IDX, op->kp.addr);
-	if (ret < 0) {
-		__arch_remove_optimized_kprobe(op, 0);
-		return ret;
-	}
-	op->optinsn.size = ret;
-
-	/* Copy arch-dep-instance from template */
-	memcpy(buf, &optprobe_template_entry, TMPL_END_IDX);
-
-	/* Set probe information */
-	synthesize_set_arg1(buf + TMPL_MOVE_IDX, (unsigned long)op);
-
-	/* Set probe function call */
-	synthesize_relcall(buf + TMPL_CALL_IDX, optimized_callback);
-
-	/* Set returning jmp instruction at the tail of out-of-line buffer */
-	synthesize_reljump(buf + TMPL_END_IDX + op->optinsn.size,
-			   (u8 *)op->kp.addr + op->optinsn.size);
-
-	flush_icache_range((unsigned long) buf,
-			   (unsigned long) buf + TMPL_END_IDX +
-			   op->optinsn.size + RELATIVEJUMP_SIZE);
-	return 0;
-}
-
-#define MAX_OPTIMIZE_PROBES 256
-static struct text_poke_param *jump_poke_params;
-static struct jump_poke_buffer {
-	u8 buf[RELATIVEJUMP_SIZE];
-} *jump_poke_bufs;
-
-static void __kprobes setup_optimize_kprobe(struct text_poke_param *tprm,
-					    u8 *insn_buf,
-					    struct optimized_kprobe *op)
-{
-	s32 rel = (s32)((long)op->optinsn.insn -
-			((long)op->kp.addr + RELATIVEJUMP_SIZE));
-
-	/* Backup instructions which will be replaced by jump address */
-	memcpy(op->optinsn.copied_insn, op->kp.addr + INT3_SIZE,
-	       RELATIVE_ADDR_SIZE);
-
-	insn_buf[0] = RELATIVEJUMP_OPCODE;
-	*(s32 *)(&insn_buf[1]) = rel;
-
-	tprm->addr = op->kp.addr;
-	tprm->opcode = insn_buf;
-	tprm->len = RELATIVEJUMP_SIZE;
-}
-
-/*
- * Replace breakpoints (int3) with relative jumps.
- * Caller must call with locking kprobe_mutex and text_mutex.
- */
-void __kprobes arch_optimize_kprobes(struct list_head *oplist)
-{
-	struct optimized_kprobe *op, *tmp;
-	int c = 0;
-
-	list_for_each_entry_safe(op, tmp, oplist, list) {
-		WARN_ON(kprobe_disabled(&op->kp));
-		/* Setup param */
-		setup_optimize_kprobe(&jump_poke_params[c],
-				      jump_poke_bufs[c].buf, op);
-		list_del_init(&op->list);
-		if (++c >= MAX_OPTIMIZE_PROBES)
-			break;
-	}
-
-	/*
-	 * text_poke_smp doesn't support NMI/MCE code modifying.
-	 * However, since kprobes itself also doesn't support NMI/MCE
-	 * code probing, it's not a problem.
-	 */
-	text_poke_smp_batch(jump_poke_params, c);
-}
-
-static void __kprobes setup_unoptimize_kprobe(struct text_poke_param *tprm,
-					      u8 *insn_buf,
-					      struct optimized_kprobe *op)
-{
-	/* Set int3 to first byte for kprobes */
-	insn_buf[0] = BREAKPOINT_INSTRUCTION;
-	memcpy(insn_buf + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE);
-
-	tprm->addr = op->kp.addr;
-	tprm->opcode = insn_buf;
-	tprm->len = RELATIVEJUMP_SIZE;
-}
-
-/*
- * Recover original instructions and breakpoints from relative jumps.
- * Caller must call with locking kprobe_mutex.
- */
-extern void arch_unoptimize_kprobes(struct list_head *oplist,
-				    struct list_head *done_list)
-{
-	struct optimized_kprobe *op, *tmp;
-	int c = 0;
-
-	list_for_each_entry_safe(op, tmp, oplist, list) {
-		/* Setup param */
-		setup_unoptimize_kprobe(&jump_poke_params[c],
-					jump_poke_bufs[c].buf, op);
-		list_move(&op->list, done_list);
-		if (++c >= MAX_OPTIMIZE_PROBES)
-			break;
-	}
-
-	/*
-	 * text_poke_smp doesn't support NMI/MCE code modifying.
-	 * However, since kprobes itself also doesn't support NMI/MCE
-	 * code probing, it's not a problem.
-	 */
-	text_poke_smp_batch(jump_poke_params, c);
-}
-
-/* Replace a relative jump with a breakpoint (int3).  */
-void __kprobes arch_unoptimize_kprobe(struct optimized_kprobe *op)
-{
-	u8 buf[RELATIVEJUMP_SIZE];
-
-	/* Set int3 to first byte for kprobes */
-	buf[0] = BREAKPOINT_INSTRUCTION;
-	memcpy(buf + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE);
-	text_poke_smp(op->kp.addr, buf, RELATIVEJUMP_SIZE);
-}
-
-static int  __kprobes setup_detour_execution(struct kprobe *p,
-					     struct pt_regs *regs,
-					     int reenter)
-{
-	struct optimized_kprobe *op;
-
-	if (p->flags & KPROBE_FLAG_OPTIMIZED) {
-		/* This kprobe is really able to run optimized path. */
-		op = container_of(p, struct optimized_kprobe, kp);
-		/* Detour through copied instructions */
-		regs->ip = (unsigned long)op->optinsn.insn + TMPL_END_IDX;
-		if (!reenter)
-			reset_current_kprobe();
-		preempt_enable_no_resched();
-		return 1;
-	}
-	return 0;
-}
-
-static int __kprobes init_poke_params(void)
-{
-	/* Allocate code buffer and parameter array */
-	jump_poke_bufs = kmalloc(sizeof(struct jump_poke_buffer) *
-				 MAX_OPTIMIZE_PROBES, GFP_KERNEL);
-	if (!jump_poke_bufs)
-		return -ENOMEM;
-
-	jump_poke_params = kmalloc(sizeof(struct text_poke_param) *
-				   MAX_OPTIMIZE_PROBES, GFP_KERNEL);
-	if (!jump_poke_params) {
-		kfree(jump_poke_bufs);
-		jump_poke_bufs = NULL;
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-#else	/* !CONFIG_OPTPROBES */
-static int __kprobes init_poke_params(void)
-{
-	return 0;
-}
-#endif
-
 int __init arch_init_kprobes(void)
 {
-	return init_poke_params();
+	return arch_init_optprobes();
 }
 
 int __kprobes arch_trampoline_kprobe(struct kprobe *p)
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index f0c6fd6..694d801 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -438,9 +438,9 @@
 static __init int activate_jump_labels(void)
 {
 	if (has_steal_clock) {
-		jump_label_inc(&paravirt_steal_enabled);
+		static_key_slow_inc(&paravirt_steal_enabled);
 		if (steal_acc)
-			jump_label_inc(&paravirt_steal_rq_enabled);
+			static_key_slow_inc(&paravirt_steal_rq_enabled);
 	}
 
 	return 0;
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c
index fda91c3..87a0f86 100644
--- a/arch/x86/kernel/microcode_core.c
+++ b/arch/x86/kernel/microcode_core.c
@@ -86,6 +86,7 @@
 
 #include <asm/microcode.h>
 #include <asm/processor.h>
+#include <asm/cpu_device_id.h>
 
 MODULE_DESCRIPTION("Microcode Update Driver");
 MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
@@ -504,6 +505,20 @@
 	.notifier_call	= mc_cpu_callback,
 };
 
+#ifdef MODULE
+/* Autoload on Intel and AMD systems */
+static const struct x86_cpu_id microcode_id[] = {
+#ifdef CONFIG_MICROCODE_INTEL
+	{ X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, },
+#endif
+#ifdef CONFIG_MICROCODE_AMD
+	{ X86_VENDOR_AMD, X86_FAMILY_ANY, X86_MODEL_ANY, },
+#endif
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, microcode_id);
+#endif
+
 static int __init microcode_init(void)
 {
 	struct cpuinfo_x86 *c = &cpu_data(0);
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index d90272e..ada2f99 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -202,8 +202,8 @@
 	__native_flush_tlb_single(addr);
 }
 
-struct jump_label_key paravirt_steal_enabled;
-struct jump_label_key paravirt_steal_rq_enabled;
+struct static_key paravirt_steal_enabled;
+struct static_key paravirt_steal_rq_enabled;
 
 static u64 native_steal_clock(int cpu)
 {
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 15763af..44eefde 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -377,8 +377,8 @@
 void default_idle(void)
 {
 	if (hlt_use_halt()) {
-		trace_power_start(POWER_CSTATE, 1, smp_processor_id());
-		trace_cpu_idle(1, smp_processor_id());
+		trace_power_start_rcuidle(POWER_CSTATE, 1, smp_processor_id());
+		trace_cpu_idle_rcuidle(1, smp_processor_id());
 		current_thread_info()->status &= ~TS_POLLING;
 		/*
 		 * TS_POLLING-cleared state must be visible before we
@@ -391,8 +391,8 @@
 		else
 			local_irq_enable();
 		current_thread_info()->status |= TS_POLLING;
-		trace_power_end(smp_processor_id());
-		trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
+		trace_power_end_rcuidle(smp_processor_id());
+		trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
 	} else {
 		local_irq_enable();
 		/* loop is done by the caller */
@@ -450,8 +450,8 @@
 static void mwait_idle(void)
 {
 	if (!need_resched()) {
-		trace_power_start(POWER_CSTATE, 1, smp_processor_id());
-		trace_cpu_idle(1, smp_processor_id());
+		trace_power_start_rcuidle(POWER_CSTATE, 1, smp_processor_id());
+		trace_cpu_idle_rcuidle(1, smp_processor_id());
 		if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR))
 			clflush((void *)&current_thread_info()->flags);
 
@@ -461,8 +461,8 @@
 			__sti_mwait(0, 0);
 		else
 			local_irq_enable();
-		trace_power_end(smp_processor_id());
-		trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
+		trace_power_end_rcuidle(smp_processor_id());
+		trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
 	} else
 		local_irq_enable();
 }
@@ -474,13 +474,13 @@
  */
 static void poll_idle(void)
 {
-	trace_power_start(POWER_CSTATE, 0, smp_processor_id());
-	trace_cpu_idle(0, smp_processor_id());
+	trace_power_start_rcuidle(POWER_CSTATE, 0, smp_processor_id());
+	trace_cpu_idle_rcuidle(0, smp_processor_id());
 	local_irq_enable();
 	while (!need_resched())
 		cpu_relax();
-	trace_power_end(smp_processor_id());
-	trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
+	trace_power_end_rcuidle(smp_processor_id());
+	trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
 }
 
 /*
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index c08d1ff..49888fe 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -119,9 +119,7 @@
 		}
 		rcu_idle_exit();
 		tick_nohz_idle_exit();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index cfa5c90..e34257c 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -156,9 +156,7 @@
 		}
 
 		tick_nohz_idle_exit();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 66d250c..58f7816 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -291,19 +291,6 @@
 	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
 	x86_platform.nmi_init();
 
-	/*
-	 * Wait until the cpu which brought this one up marked it
-	 * online before enabling interrupts. If we don't do that then
-	 * we can end up waking up the softirq thread before this cpu
-	 * reached the active state, which makes the scheduler unhappy
-	 * and schedule the softirq thread on the wrong cpu. This is
-	 * only observable with forced threaded interrupts, but in
-	 * theory it could also happen w/o them. It's just way harder
-	 * to achieve.
-	 */
-	while (!cpumask_test_cpu(smp_processor_id(), cpu_active_mask))
-		cpu_relax();
-
 	/* enable local interrupts */
 	local_irq_enable();
 
diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c
index dd5fbf4..c6eba2b 100644
--- a/arch/x86/kernel/time.c
+++ b/arch/x86/kernel/time.c
@@ -57,9 +57,6 @@
  */
 static irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
-	/* Keep nmi watchdog up to date */
-	inc_irq_stat(irq0_irqs);
-
 	global_clock_event->event_handler(global_clock_event);
 
 	/* MCA bus quirk: Acknowledge irq0 by setting bit 7 in port 0x61 */
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index a62c201..183c592 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -620,7 +620,8 @@
 
 	if (cpu_khz) {
 		*scale = (NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR)/cpu_khz;
-		*offset = ns_now - (tsc_now * *scale >> CYC2NS_SCALE_FACTOR);
+		*offset = ns_now - mult_frac(tsc_now, *scale,
+					     (1UL << CYC2NS_SCALE_FACTOR));
 	}
 
 	sched_clock_idle_wakeup_event(0);
diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c
index 9eba29b..fc25e60 100644
--- a/arch/x86/kernel/tsc_sync.c
+++ b/arch/x86/kernel/tsc_sync.c
@@ -42,7 +42,7 @@
 /*
  * TSC-warp measurement loop running on both CPUs:
  */
-static __cpuinit void check_tsc_warp(void)
+static __cpuinit void check_tsc_warp(unsigned int timeout)
 {
 	cycles_t start, now, prev, end;
 	int i;
@@ -51,9 +51,9 @@
 	start = get_cycles();
 	rdtsc_barrier();
 	/*
-	 * The measurement runs for 20 msecs:
+	 * The measurement runs for 'timeout' msecs:
 	 */
-	end = start + tsc_khz * 20ULL;
+	end = start + (cycles_t) tsc_khz * timeout;
 	now = start;
 
 	for (i = 0; ; i++) {
@@ -99,6 +99,25 @@
 }
 
 /*
+ * If the target CPU coming online doesn't have any of its core-siblings
+ * online, a timeout of 20msec will be used for the TSC-warp measurement
+ * loop. Otherwise a smaller timeout of 2msec will be used, as we have some
+ * information about this socket already (and this information grows as we
+ * have more and more logical-siblings in that socket).
+ *
+ * Ideally we should be able to skip the TSC sync check on the other
+ * core-siblings, if the first logical CPU in a socket passed the sync test.
+ * But as the TSC is per-logical CPU and can potentially be modified wrongly
+ * by the bios, TSC sync test for smaller duration should be able
+ * to catch such errors. Also this will catch the condition where all the
+ * cores in the socket doesn't get reset at the same time.
+ */
+static inline unsigned int loop_timeout(int cpu)
+{
+	return (cpumask_weight(cpu_core_mask(cpu)) > 1) ? 2 : 20;
+}
+
+/*
  * Source CPU calls into this - it waits for the freshly booted
  * target CPU to arrive and then starts the measurement:
  */
@@ -135,7 +154,7 @@
 	 */
 	atomic_inc(&start_count);
 
-	check_tsc_warp();
+	check_tsc_warp(loop_timeout(cpu));
 
 	while (atomic_read(&stop_count) != cpus-1)
 		cpu_relax();
@@ -183,7 +202,7 @@
 	while (atomic_read(&start_count) != cpus)
 		cpu_relax();
 
-	check_tsc_warp();
+	check_tsc_warp(loop_timeout(smp_processor_id()));
 
 	/*
 	 * Ok, we are done:
diff --git a/arch/x86/kvm/mmu_audit.c b/arch/x86/kvm/mmu_audit.c
index fe15dcc..ea7b4fd 100644
--- a/arch/x86/kvm/mmu_audit.c
+++ b/arch/x86/kvm/mmu_audit.c
@@ -234,7 +234,7 @@
 }
 
 static bool mmu_audit;
-static struct jump_label_key mmu_audit_key;
+static struct static_key mmu_audit_key;
 
 static void __kvm_mmu_audit(struct kvm_vcpu *vcpu, int point)
 {
@@ -250,7 +250,7 @@
 
 static inline void kvm_mmu_audit(struct kvm_vcpu *vcpu, int point)
 {
-	if (static_branch((&mmu_audit_key)))
+	if (static_key_false((&mmu_audit_key)))
 		__kvm_mmu_audit(vcpu, point);
 }
 
@@ -259,7 +259,7 @@
 	if (mmu_audit)
 		return;
 
-	jump_label_inc(&mmu_audit_key);
+	static_key_slow_inc(&mmu_audit_key);
 	mmu_audit = true;
 }
 
@@ -268,7 +268,7 @@
 	if (!mmu_audit)
 		return;
 
-	jump_label_dec(&mmu_audit_key);
+	static_key_slow_dec(&mmu_audit_key);
 	mmu_audit = false;
 }
 
diff --git a/arch/x86/lib/inat.c b/arch/x86/lib/inat.c
index 88ad5fb..c1f01a8 100644
--- a/arch/x86/lib/inat.c
+++ b/arch/x86/lib/inat.c
@@ -29,46 +29,46 @@
 	return inat_primary_table[opcode];
 }
 
-insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, insn_byte_t last_pfx,
+int inat_get_last_prefix_id(insn_byte_t last_pfx)
+{
+	insn_attr_t lpfx_attr;
+
+	lpfx_attr = inat_get_opcode_attribute(last_pfx);
+	return inat_last_prefix_id(lpfx_attr);
+}
+
+insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, int lpfx_id,
 				      insn_attr_t esc_attr)
 {
 	const insn_attr_t *table;
-	insn_attr_t lpfx_attr;
-	int n, m = 0;
+	int n;
 
 	n = inat_escape_id(esc_attr);
-	if (last_pfx) {
-		lpfx_attr = inat_get_opcode_attribute(last_pfx);
-		m = inat_last_prefix_id(lpfx_attr);
-	}
+
 	table = inat_escape_tables[n][0];
 	if (!table)
 		return 0;
-	if (inat_has_variant(table[opcode]) && m) {
-		table = inat_escape_tables[n][m];
+	if (inat_has_variant(table[opcode]) && lpfx_id) {
+		table = inat_escape_tables[n][lpfx_id];
 		if (!table)
 			return 0;
 	}
 	return table[opcode];
 }
 
-insn_attr_t inat_get_group_attribute(insn_byte_t modrm, insn_byte_t last_pfx,
+insn_attr_t inat_get_group_attribute(insn_byte_t modrm, int lpfx_id,
 				     insn_attr_t grp_attr)
 {
 	const insn_attr_t *table;
-	insn_attr_t lpfx_attr;
-	int n, m = 0;
+	int n;
 
 	n = inat_group_id(grp_attr);
-	if (last_pfx) {
-		lpfx_attr = inat_get_opcode_attribute(last_pfx);
-		m = inat_last_prefix_id(lpfx_attr);
-	}
+
 	table = inat_group_tables[n][0];
 	if (!table)
 		return inat_group_common_attribute(grp_attr);
-	if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && m) {
-		table = inat_group_tables[n][m];
+	if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && lpfx_id) {
+		table = inat_group_tables[n][lpfx_id];
 		if (!table)
 			return inat_group_common_attribute(grp_attr);
 	}
diff --git a/arch/x86/lib/insn.c b/arch/x86/lib/insn.c
index 5a1f9f3..25feb1a 100644
--- a/arch/x86/lib/insn.c
+++ b/arch/x86/lib/insn.c
@@ -185,7 +185,8 @@
 void insn_get_opcode(struct insn *insn)
 {
 	struct insn_field *opcode = &insn->opcode;
-	insn_byte_t op, pfx;
+	insn_byte_t op;
+	int pfx_id;
 	if (opcode->got)
 		return;
 	if (!insn->prefixes.got)
@@ -212,8 +213,8 @@
 		/* Get escaped opcode */
 		op = get_next(insn_byte_t, insn);
 		opcode->bytes[opcode->nbytes++] = op;
-		pfx = insn_last_prefix(insn);
-		insn->attr = inat_get_escape_attribute(op, pfx, insn->attr);
+		pfx_id = insn_last_prefix_id(insn);
+		insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr);
 	}
 	if (inat_must_vex(insn->attr))
 		insn->attr = 0;	/* This instruction is bad */
@@ -235,7 +236,7 @@
 void insn_get_modrm(struct insn *insn)
 {
 	struct insn_field *modrm = &insn->modrm;
-	insn_byte_t pfx, mod;
+	insn_byte_t pfx_id, mod;
 	if (modrm->got)
 		return;
 	if (!insn->opcode.got)
@@ -246,8 +247,8 @@
 		modrm->value = mod;
 		modrm->nbytes = 1;
 		if (inat_is_group(insn->attr)) {
-			pfx = insn_last_prefix(insn);
-			insn->attr = inat_get_group_attribute(mod, pfx,
+			pfx_id = insn_last_prefix_id(insn);
+			insn->attr = inat_get_group_attribute(mod, pfx_id,
 							      insn->attr);
 			if (insn_is_avx(insn) && !inat_accept_vex(insn->attr))
 				insn->attr = 0;	/* This is bad */
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index 47041e7..2c90047 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -113,9 +113,7 @@
 	while (1) {
 		while (!need_resched())
 			platform_idle();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c
index 2c723e8..f9726f6 100644
--- a/arch/xtensa/platforms/iss/console.c
+++ b/arch/xtensa/platforms/iss/console.c
@@ -19,7 +19,6 @@
 #include <linux/param.h>
 #include <linux/seq_file.h>
 #include <linux/serial.h>
-#include <linux/serialP.h>
 
 #include <asm/uaccess.h>
 #include <asm/irq.h>
@@ -37,6 +36,7 @@
 #define SERIAL_TIMER_VALUE (20 * HZ)
 
 static struct tty_driver *serial_driver;
+static struct tty_port serial_port;
 static struct timer_list serial_timer;
 
 static DEFINE_SPINLOCK(timer_lock);
@@ -68,17 +68,10 @@
 
 static int rs_open(struct tty_struct *tty, struct file * filp)
 {
-	int line = tty->index;
-
-	if ((line < 0) || (line >= SERIAL_MAX_NUM_LINES))
-		return -ENODEV;
-
+	tty->port = &serial_port;
 	spin_lock(&timer_lock);
-
 	if (tty->count == 1) {
-		init_timer(&serial_timer);
-		serial_timer.data = (unsigned long) tty;
-		serial_timer.function = rs_poll;
+		setup_timer(&serial_timer, rs_poll, (unsigned long)tty);
 		mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
 	}
 	spin_unlock(&timer_lock);
@@ -99,10 +92,10 @@
  */
 static void rs_close(struct tty_struct *tty, struct file * filp)
 {
-	spin_lock(&timer_lock);
+	spin_lock_bh(&timer_lock);
 	if (tty->count == 1)
 		del_timer_sync(&serial_timer);
-	spin_unlock(&timer_lock);
+	spin_unlock_bh(&timer_lock);
 }
 
 
@@ -210,13 +203,14 @@
 
 int __init rs_init(void)
 {
-	serial_driver = alloc_tty_driver(1);
+	tty_port_init(&serial_port);
+
+	serial_driver = alloc_tty_driver(SERIAL_MAX_NUM_LINES);
 
 	printk ("%s %s\n", serial_name, serial_version);
 
 	/* Initialize the tty_driver structure */
 
-	serial_driver->owner = THIS_MODULE;
 	serial_driver->driver_name = "iss_serial";
 	serial_driver->name = "ttyS";
 	serial_driver->major = TTY_MAJOR;
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 75642a3..ea84a23 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -28,13 +28,10 @@
 struct blkio_cgroup blkio_root_cgroup = { .weight = 2*BLKIO_WEIGHT_DEFAULT };
 EXPORT_SYMBOL_GPL(blkio_root_cgroup);
 
-static struct cgroup_subsys_state *blkiocg_create(struct cgroup_subsys *,
-						  struct cgroup *);
-static int blkiocg_can_attach(struct cgroup_subsys *, struct cgroup *,
-			      struct cgroup_taskset *);
-static void blkiocg_attach(struct cgroup_subsys *, struct cgroup *,
-			   struct cgroup_taskset *);
-static void blkiocg_destroy(struct cgroup_subsys *, struct cgroup *);
+static struct cgroup_subsys_state *blkiocg_create(struct cgroup *);
+static int blkiocg_can_attach(struct cgroup *, struct cgroup_taskset *);
+static void blkiocg_attach(struct cgroup *, struct cgroup_taskset *);
+static void blkiocg_destroy(struct cgroup *);
 static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *);
 
 /* for encoding cft->private value on file */
@@ -1548,7 +1545,7 @@
 				ARRAY_SIZE(blkio_files));
 }
 
-static void blkiocg_destroy(struct cgroup_subsys *subsys, struct cgroup *cgroup)
+static void blkiocg_destroy(struct cgroup *cgroup)
 {
 	struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup);
 	unsigned long flags;
@@ -1598,8 +1595,7 @@
 		kfree(blkcg);
 }
 
-static struct cgroup_subsys_state *
-blkiocg_create(struct cgroup_subsys *subsys, struct cgroup *cgroup)
+static struct cgroup_subsys_state *blkiocg_create(struct cgroup *cgroup)
 {
 	struct blkio_cgroup *blkcg;
 	struct cgroup *parent = cgroup->parent;
@@ -1628,8 +1624,7 @@
  * of the main cic data structures.  For now we allow a task to change
  * its cgroup only if it's the only owner of its ioc.
  */
-static int blkiocg_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
-			      struct cgroup_taskset *tset)
+static int blkiocg_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
 {
 	struct task_struct *task;
 	struct io_context *ioc;
@@ -1648,8 +1643,7 @@
 	return ret;
 }
 
-static void blkiocg_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
-			   struct cgroup_taskset *tset)
+static void blkiocg_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
 {
 	struct task_struct *task;
 	struct io_context *ioc;
diff --git a/block/blk-ioc.c b/block/blk-ioc.c
index 8b782a6..fb95dd2 100644
--- a/block/blk-ioc.c
+++ b/block/blk-ioc.c
@@ -36,11 +36,23 @@
 	kmem_cache_free(icq->__rcu_icq_cache, icq);
 }
 
-/*
- * Exit and free an icq.  Called with both ioc and q locked.
- */
+/* Exit an icq. Called with both ioc and q locked. */
 static void ioc_exit_icq(struct io_cq *icq)
 {
+	struct elevator_type *et = icq->q->elevator->type;
+
+	if (icq->flags & ICQ_EXITED)
+		return;
+
+	if (et->ops.elevator_exit_icq_fn)
+		et->ops.elevator_exit_icq_fn(icq);
+
+	icq->flags |= ICQ_EXITED;
+}
+
+/* Release an icq.  Called with both ioc and q locked. */
+static void ioc_destroy_icq(struct io_cq *icq)
+{
 	struct io_context *ioc = icq->ioc;
 	struct request_queue *q = icq->q;
 	struct elevator_type *et = q->elevator->type;
@@ -60,8 +72,7 @@
 	if (rcu_dereference_raw(ioc->icq_hint) == icq)
 		rcu_assign_pointer(ioc->icq_hint, NULL);
 
-	if (et->ops.elevator_exit_icq_fn)
-		et->ops.elevator_exit_icq_fn(icq);
+	ioc_exit_icq(icq);
 
 	/*
 	 * @icq->q might have gone away by the time RCU callback runs
@@ -79,7 +90,6 @@
 {
 	struct io_context *ioc = container_of(work, struct io_context,
 					      release_work);
-	struct request_queue *last_q = NULL;
 	unsigned long flags;
 
 	/*
@@ -93,44 +103,19 @@
 	while (!hlist_empty(&ioc->icq_list)) {
 		struct io_cq *icq = hlist_entry(ioc->icq_list.first,
 						struct io_cq, ioc_node);
-		struct request_queue *this_q = icq->q;
+		struct request_queue *q = icq->q;
 
-		if (this_q != last_q) {
-			/*
-			 * Need to switch to @this_q.  Once we release
-			 * @ioc->lock, it can go away along with @cic.
-			 * Hold on to it.
-			 */
-			__blk_get_queue(this_q);
-
-			/*
-			 * blk_put_queue() might sleep thanks to kobject
-			 * idiocy.  Always release both locks, put and
-			 * restart.
-			 */
-			if (last_q) {
-				spin_unlock(last_q->queue_lock);
-				spin_unlock_irqrestore(&ioc->lock, flags);
-				blk_put_queue(last_q);
-			} else {
-				spin_unlock_irqrestore(&ioc->lock, flags);
-			}
-
-			last_q = this_q;
-			spin_lock_irqsave(this_q->queue_lock, flags);
-			spin_lock_nested(&ioc->lock, 1);
-			continue;
+		if (spin_trylock(q->queue_lock)) {
+			ioc_destroy_icq(icq);
+			spin_unlock(q->queue_lock);
+		} else {
+			spin_unlock_irqrestore(&ioc->lock, flags);
+			cpu_relax();
+			spin_lock_irqsave_nested(&ioc->lock, flags, 1);
 		}
-		ioc_exit_icq(icq);
 	}
 
-	if (last_q) {
-		spin_unlock(last_q->queue_lock);
-		spin_unlock_irqrestore(&ioc->lock, flags);
-		blk_put_queue(last_q);
-	} else {
-		spin_unlock_irqrestore(&ioc->lock, flags);
-	}
+	spin_unlock_irqrestore(&ioc->lock, flags);
 
 	kmem_cache_free(iocontext_cachep, ioc);
 }
@@ -145,6 +130,7 @@
 void put_io_context(struct io_context *ioc)
 {
 	unsigned long flags;
+	bool free_ioc = false;
 
 	if (ioc == NULL)
 		return;
@@ -159,8 +145,13 @@
 		spin_lock_irqsave(&ioc->lock, flags);
 		if (!hlist_empty(&ioc->icq_list))
 			schedule_work(&ioc->release_work);
+		else
+			free_ioc = true;
 		spin_unlock_irqrestore(&ioc->lock, flags);
 	}
+
+	if (free_ioc)
+		kmem_cache_free(iocontext_cachep, ioc);
 }
 EXPORT_SYMBOL(put_io_context);
 
@@ -168,13 +159,41 @@
 void exit_io_context(struct task_struct *task)
 {
 	struct io_context *ioc;
+	struct io_cq *icq;
+	struct hlist_node *n;
+	unsigned long flags;
 
 	task_lock(task);
 	ioc = task->io_context;
 	task->io_context = NULL;
 	task_unlock(task);
 
-	atomic_dec(&ioc->nr_tasks);
+	if (!atomic_dec_and_test(&ioc->nr_tasks)) {
+		put_io_context(ioc);
+		return;
+	}
+
+	/*
+	 * Need ioc lock to walk icq_list and q lock to exit icq.  Perform
+	 * reverse double locking.  Read comment in ioc_release_fn() for
+	 * explanation on the nested locking annotation.
+	 */
+retry:
+	spin_lock_irqsave_nested(&ioc->lock, flags, 1);
+	hlist_for_each_entry(icq, n, &ioc->icq_list, ioc_node) {
+		if (icq->flags & ICQ_EXITED)
+			continue;
+		if (spin_trylock(icq->q->queue_lock)) {
+			ioc_exit_icq(icq);
+			spin_unlock(icq->q->queue_lock);
+		} else {
+			spin_unlock_irqrestore(&ioc->lock, flags);
+			cpu_relax();
+			goto retry;
+		}
+	}
+	spin_unlock_irqrestore(&ioc->lock, flags);
+
 	put_io_context(ioc);
 }
 
@@ -194,7 +213,7 @@
 		struct io_context *ioc = icq->ioc;
 
 		spin_lock(&ioc->lock);
-		ioc_exit_icq(icq);
+		ioc_destroy_icq(icq);
 		spin_unlock(&ioc->lock);
 	}
 }
@@ -363,13 +382,13 @@
 	return icq;
 }
 
-void ioc_set_changed(struct io_context *ioc, int which)
+void ioc_set_icq_flags(struct io_context *ioc, unsigned int flags)
 {
 	struct io_cq *icq;
 	struct hlist_node *n;
 
 	hlist_for_each_entry(icq, n, &ioc->icq_list, ioc_node)
-		set_bit(which, &icq->changed);
+		icq->flags |= flags;
 }
 
 /**
@@ -387,7 +406,7 @@
 
 	spin_lock_irqsave(&ioc->lock, flags);
 	ioc->ioprio = ioprio;
-	ioc_set_changed(ioc, ICQ_IOPRIO_CHANGED);
+	ioc_set_icq_flags(ioc, ICQ_IOPRIO_CHANGED);
 	spin_unlock_irqrestore(&ioc->lock, flags);
 }
 
@@ -404,11 +423,33 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&ioc->lock, flags);
-	ioc_set_changed(ioc, ICQ_CGROUP_CHANGED);
+	ioc_set_icq_flags(ioc, ICQ_CGROUP_CHANGED);
 	spin_unlock_irqrestore(&ioc->lock, flags);
 }
 EXPORT_SYMBOL(ioc_cgroup_changed);
 
+/**
+ * icq_get_changed - fetch and clear icq changed mask
+ * @icq: icq of interest
+ *
+ * Fetch and clear ICQ_*_CHANGED bits from @icq.  Grabs and releases
+ * @icq->ioc->lock.
+ */
+unsigned icq_get_changed(struct io_cq *icq)
+{
+	unsigned int changed = 0;
+	unsigned long flags;
+
+	if (unlikely(icq->flags & ICQ_CHANGED_MASK)) {
+		spin_lock_irqsave(&icq->ioc->lock, flags);
+		changed = icq->flags & ICQ_CHANGED_MASK;
+		icq->flags &= ~ICQ_CHANGED_MASK;
+		spin_unlock_irqrestore(&icq->ioc->lock, flags);
+	}
+	return changed;
+}
+EXPORT_SYMBOL(icq_get_changed);
+
 static int __init blk_ioc_init(void)
 {
 	iocontext_cachep = kmem_cache_create("blkdev_ioc",
diff --git a/block/blk-softirq.c b/block/blk-softirq.c
index 1366a89..467c8de 100644
--- a/block/blk-softirq.c
+++ b/block/blk-softirq.c
@@ -8,6 +8,7 @@
 #include <linux/blkdev.h>
 #include <linux/interrupt.h>
 #include <linux/cpu.h>
+#include <linux/sched.h>
 
 #include "blk.h"
 
@@ -103,9 +104,10 @@
 
 void __blk_complete_request(struct request *req)
 {
-	int ccpu, cpu, group_cpu = NR_CPUS;
+	int ccpu, cpu;
 	struct request_queue *q = req->q;
 	unsigned long flags;
+	bool shared = false;
 
 	BUG_ON(!q->softirq_done_fn);
 
@@ -117,22 +119,20 @@
 	 */
 	if (req->cpu != -1) {
 		ccpu = req->cpu;
-		if (!test_bit(QUEUE_FLAG_SAME_FORCE, &q->queue_flags)) {
-			ccpu = blk_cpu_to_group(ccpu);
-			group_cpu = blk_cpu_to_group(cpu);
-		}
+		if (!test_bit(QUEUE_FLAG_SAME_FORCE, &q->queue_flags))
+			shared = cpus_share_cache(cpu, ccpu);
 	} else
 		ccpu = cpu;
 
 	/*
-	 * If current CPU and requested CPU are in the same group, running
-	 * softirq in current CPU. One might concern this is just like
+	 * If current CPU and requested CPU share a cache, run the softirq on
+	 * the current CPU. One might concern this is just like
 	 * QUEUE_FLAG_SAME_FORCE, but actually not. blk_complete_request() is
 	 * running in interrupt handler, and currently I/O controller doesn't
 	 * support multiple interrupts, so current CPU is unique actually. This
 	 * avoids IPI sending from current CPU to the first CPU of a group.
 	 */
-	if (ccpu == cpu || ccpu == group_cpu) {
+	if (ccpu == cpu || shared) {
 		struct list_head *list;
 do_local:
 		list = &__get_cpu_var(blk_cpu_done);
diff --git a/block/blk.h b/block/blk.h
index 9c12f80..d45be87 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -166,22 +166,6 @@
 	return q->nr_congestion_off;
 }
 
-static inline int blk_cpu_to_group(int cpu)
-{
-	int group = NR_CPUS;
-#ifdef CONFIG_SCHED_MC
-	const struct cpumask *mask = cpu_coregroup_mask(cpu);
-	group = cpumask_first(mask);
-#elif defined(CONFIG_SCHED_SMT)
-	group = cpumask_first(topology_thread_cpumask(cpu));
-#else
-	return cpu;
-#endif
-	if (likely(group < NR_CPUS))
-		return group;
-	return cpu;
-}
-
 /*
  * Contribute to IO statistics IFF:
  *
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index d0ba505..4572952 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -3470,20 +3470,20 @@
 	const int rw = rq_data_dir(rq);
 	const bool is_sync = rq_is_sync(rq);
 	struct cfq_queue *cfqq;
+	unsigned int changed;
 
 	might_sleep_if(gfp_mask & __GFP_WAIT);
 
 	spin_lock_irq(q->queue_lock);
 
 	/* handle changed notifications */
-	if (unlikely(cic->icq.changed)) {
-		if (test_and_clear_bit(ICQ_IOPRIO_CHANGED, &cic->icq.changed))
-			changed_ioprio(cic);
+	changed = icq_get_changed(&cic->icq);
+	if (unlikely(changed & ICQ_IOPRIO_CHANGED))
+		changed_ioprio(cic);
 #ifdef CONFIG_CFQ_GROUP_IOSCHED
-		if (test_and_clear_bit(ICQ_CGROUP_CHANGED, &cic->icq.changed))
-			changed_cgroup(cic);
+	if (unlikely(changed & ICQ_CGROUP_CHANGED))
+		changed_cgroup(cic);
 #endif
-	}
 
 new_queue:
 	cfqq = cic_to_cfqq(cic, is_sync);
diff --git a/block/genhd.c b/block/genhd.c
index 23b4f70..df9816e 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -35,6 +35,7 @@
 
 static struct device_type disk_type;
 
+static void disk_alloc_events(struct gendisk *disk);
 static void disk_add_events(struct gendisk *disk);
 static void disk_del_events(struct gendisk *disk);
 static void disk_release_events(struct gendisk *disk);
@@ -601,6 +602,8 @@
 	disk->major = MAJOR(devt);
 	disk->first_minor = MINOR(devt);
 
+	disk_alloc_events(disk);
+
 	/* Register BDI before referencing it from bdev */
 	bdi = &disk->queue->backing_dev_info;
 	bdi_register_dev(bdi, disk_devt(disk));
@@ -1475,9 +1478,9 @@
 	intv = disk_events_poll_jiffies(disk);
 	set_timer_slack(&ev->dwork.timer, intv / 4);
 	if (check_now)
-		queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
+		queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0);
 	else if (intv)
-		queue_delayed_work(system_nrt_wq, &ev->dwork, intv);
+		queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, intv);
 out_unlock:
 	spin_unlock_irqrestore(&ev->lock, flags);
 }
@@ -1521,7 +1524,7 @@
 	ev->clearing |= mask;
 	if (!ev->block) {
 		cancel_delayed_work(&ev->dwork);
-		queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
+		queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0);
 	}
 	spin_unlock_irq(&ev->lock);
 }
@@ -1558,7 +1561,7 @@
 
 	/* uncondtionally schedule event check and wait for it to finish */
 	disk_block_events(disk);
-	queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
+	queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0);
 	flush_delayed_work(&ev->dwork);
 	__disk_unblock_events(disk, false);
 
@@ -1595,7 +1598,7 @@
 
 	intv = disk_events_poll_jiffies(disk);
 	if (!ev->block && intv)
-		queue_delayed_work(system_nrt_wq, &ev->dwork, intv);
+		queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, intv);
 
 	spin_unlock_irq(&ev->lock);
 
@@ -1733,9 +1736,9 @@
 		&disk_events_dfl_poll_msecs, 0644);
 
 /*
- * disk_{add|del|release}_events - initialize and destroy disk_events.
+ * disk_{alloc|add|del|release}_events - initialize and destroy disk_events.
  */
-static void disk_add_events(struct gendisk *disk)
+static void disk_alloc_events(struct gendisk *disk)
 {
 	struct disk_events *ev;
 
@@ -1748,16 +1751,6 @@
 		return;
 	}
 
-	if (sysfs_create_files(&disk_to_dev(disk)->kobj,
-			       disk_events_attrs) < 0) {
-		pr_warn("%s: failed to create sysfs files for events\n",
-			disk->disk_name);
-		kfree(ev);
-		return;
-	}
-
-	disk->ev = ev;
-
 	INIT_LIST_HEAD(&ev->node);
 	ev->disk = disk;
 	spin_lock_init(&ev->lock);
@@ -1766,8 +1759,21 @@
 	ev->poll_msecs = -1;
 	INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn);
 
+	disk->ev = ev;
+}
+
+static void disk_add_events(struct gendisk *disk)
+{
+	if (!disk->ev)
+		return;
+
+	/* FIXME: error handling */
+	if (sysfs_create_files(&disk_to_dev(disk)->kobj, disk_events_attrs) < 0)
+		pr_warn("%s: failed to create sysfs files for events\n",
+			disk->disk_name);
+
 	mutex_lock(&disk_events_mutex);
-	list_add_tail(&ev->node, &disk_events);
+	list_add_tail(&disk->ev->node, &disk_events);
 	mutex_unlock(&disk_events_mutex);
 
 	/*
diff --git a/block/partition-generic.c b/block/partition-generic.c
index d06ec1c..6df5d69 100644
--- a/block/partition-generic.c
+++ b/block/partition-generic.c
@@ -389,17 +389,11 @@
 	}
 }
 
-int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
+static int drop_partitions(struct gendisk *disk, struct block_device *bdev)
 {
-	struct parsed_partitions *state = NULL;
 	struct disk_part_iter piter;
 	struct hd_struct *part;
-	int p, highest, res;
-rescan:
-	if (state && !IS_ERR(state)) {
-		kfree(state);
-		state = NULL;
-	}
+	int res;
 
 	if (bdev->bd_part_count)
 		return -EBUSY;
@@ -412,6 +406,24 @@
 		delete_partition(disk, part->partno);
 	disk_part_iter_exit(&piter);
 
+	return 0;
+}
+
+int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
+{
+	struct parsed_partitions *state = NULL;
+	struct hd_struct *part;
+	int p, highest, res;
+rescan:
+	if (state && !IS_ERR(state)) {
+		kfree(state);
+		state = NULL;
+	}
+
+	res = drop_partitions(disk, bdev);
+	if (res)
+		return res;
+
 	if (disk->fops->revalidate_disk)
 		disk->fops->revalidate_disk(disk);
 	check_disk_size_change(disk, bdev);
@@ -515,6 +527,26 @@
 	return 0;
 }
 
+int invalidate_partitions(struct gendisk *disk, struct block_device *bdev)
+{
+	int res;
+
+	if (!bdev->bd_invalidated)
+		return 0;
+
+	res = drop_partitions(disk, bdev);
+	if (res)
+		return res;
+
+	set_capacity(disk, 0);
+	check_disk_size_change(disk, bdev);
+	bdev->bd_invalidated = 0;
+	/* tell userspace that the media / partition table may have changed */
+	kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
+
+	return 0;
+}
+
 unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p)
 {
 	struct address_space *mapping = bdev->bd_inode->i_mapping;
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 5afe5d1..decf8e4 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -40,8 +40,6 @@
 
 source "drivers/isdn/Kconfig"
 
-source "drivers/telephony/Kconfig"
-
 # input before char - char/joystick depends on it. As does USB.
 
 source "drivers/input/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index c07be02..932e8bf 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -86,7 +86,6 @@
 obj-$(CONFIG_HWMON)		+= hwmon/
 obj-$(CONFIG_THERMAL)		+= thermal/
 obj-$(CONFIG_WATCHDOG)		+= watchdog/
-obj-$(CONFIG_PHONE)		+= telephony/
 obj-$(CONFIG_MD)		+= md/
 obj-$(CONFIG_BT)		+= bluetooth/
 obj-$(CONFIG_ACCESSIBILITY)	+= accessibility/
diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c
index c339a08..d21167b 100644
--- a/drivers/accessibility/braille/braille_console.c
+++ b/drivers/accessibility/braille/braille_console.c
@@ -244,16 +244,13 @@
 
 			switch (val) {
 			case KVAL(K_CAPS):
-				on_off = vc_kbd_led(kbd_table + fg_console,
-						VC_CAPSLOCK);
+				on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
 				break;
 			case KVAL(K_NUM):
-				on_off = vc_kbd_led(kbd_table + fg_console,
-						VC_NUMLOCK);
+				on_off = vt_get_leds(fg_console, VC_NUMLOCK);
 				break;
 			case KVAL(K_HOLD):
-				on_off = vc_kbd_led(kbd_table + fg_console,
-						VC_SCROLLOCK);
+				on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
 				break;
 			}
 			if (on_off == 1)
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 8ae05ce..2801b41 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -474,6 +474,7 @@
 
 #ifdef CONFIG_CPU_FREQ
 	acpi_processor_ppc_has_changed(pr, 0);
+	acpi_processor_load_module(pr);
 #endif
 	acpi_processor_get_throttling_info(pr);
 	acpi_processor_get_limit_info(pr);
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 85b3237..0af48a8 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -240,6 +240,28 @@
 	acpi_processor_ppc_status &= ~PPC_REGISTERED;
 }
 
+/*
+ * Do a quick check if the systems looks like it should use ACPI
+ * cpufreq. We look at a _PCT method being available, but don't
+ * do a whole lot of sanity checks.
+ */
+void acpi_processor_load_module(struct acpi_processor *pr)
+{
+	static int requested;
+	acpi_status status = 0;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+
+	if (!arch_has_acpi_pdc() || requested)
+		return;
+	status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer);
+	if (!ACPI_FAILURE(status)) {
+		printk(KERN_INFO PREFIX "Requesting acpi_cpufreq\n");
+		request_module_nowait("acpi_cpufreq");
+		requested = 1;
+	}
+	kfree(buffer.pointer);
+}
+
 static int acpi_processor_get_performance_control(struct acpi_processor *pr)
 {
 	int result = 0;
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 7be9f79..9aa618a 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -176,6 +176,9 @@
 	bool
 	default n
 
+config SOC_BUS
+	bool
+
 source "drivers/base/regmap/Kconfig"
 
 config DMA_SHARED_BUFFER
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 610f999..b6d1b9c 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -19,6 +19,7 @@
 endif
 obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
 obj-$(CONFIG_REGMAP)	+= regmap/
+obj-$(CONFIG_SOC_BUS) += soc.o
 
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
 
diff --git a/drivers/base/base.h b/drivers/base/base.h
index b858dfd..6ee17bb 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -59,6 +59,10 @@
  * @knode_parent - node in sibling list
  * @knode_driver - node in driver list
  * @knode_bus - node in bus list
+ * @deferred_probe - entry in deferred_probe_list which is used to retry the
+ *	binding of drivers which were unable to get all the resources needed by
+ *	the device; typically because it depends on another driver getting
+ *	probed first.
  * @driver_data - private pointer for driver specific info.  Will turn into a
  * list soon.
  * @device - pointer back to the struct class that this structure is
@@ -71,6 +75,7 @@
 	struct klist_node knode_parent;
 	struct klist_node knode_driver;
 	struct klist_node knode_bus;
+	struct list_head deferred_probe;
 	void *driver_data;
 	struct device *device;
 };
@@ -105,6 +110,7 @@
 
 extern void driver_detach(struct device_driver *drv);
 extern int driver_probe_device(struct device_driver *drv, struct device *dev);
+extern void driver_deferred_probe_del(struct device *dev);
 static inline int driver_match_device(struct device_driver *drv,
 				      struct device *dev)
 {
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 40fb122..26a06b8 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -1194,13 +1194,15 @@
 
 void subsys_interface_unregister(struct subsys_interface *sif)
 {
-	struct bus_type *subsys = sif->subsys;
+	struct bus_type *subsys;
 	struct subsys_dev_iter iter;
 	struct device *dev;
 
-	if (!sif)
+	if (!sif || !sif->subsys)
 		return;
 
+	subsys = sif->subsys;
+
 	mutex_lock(&subsys->p->mutex);
 	list_del_init(&sif->node);
 	if (sif->remove_dev) {
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 74dda4f..7050a75 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -921,6 +921,7 @@
 	dev->p->device = dev;
 	klist_init(&dev->p->klist_children, klist_children_get,
 		   klist_children_put);
+	INIT_LIST_HEAD(&dev->p->deferred_probe);
 	return 0;
 }
 
@@ -1188,6 +1189,7 @@
 	device_remove_file(dev, &uevent_attr);
 	device_remove_attrs(dev);
 	bus_remove_device(dev);
+	driver_deferred_probe_del(dev);
 
 	/*
 	 * Some platform devices are driven without driver attached
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 4dabf50..adf937b 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -11,6 +11,7 @@
 #include <linux/device.h>
 #include <linux/node.h>
 #include <linux/gfp.h>
+#include <linux/slab.h>
 #include <linux/percpu.h>
 
 #include "base.h"
@@ -244,6 +245,9 @@
 	cpu->dev.id = num;
 	cpu->dev.bus = &cpu_subsys;
 	cpu->dev.release = cpu_device_release;
+#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
+	cpu->dev.bus->uevent = arch_cpu_uevent;
+#endif
 	error = device_register(&cpu->dev);
 	if (!error && cpu->hotpluggable)
 		register_cpu_control(cpu);
@@ -268,6 +272,10 @@
 }
 EXPORT_SYMBOL_GPL(get_cpu_device);
 
+#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
+static DEVICE_ATTR(modalias, 0444, arch_print_cpu_modalias, NULL);
+#endif
+
 static struct attribute *cpu_root_attrs[] = {
 #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
 	&dev_attr_probe.attr,
@@ -278,6 +286,9 @@
 	&cpu_attrs[2].attr.attr,
 	&dev_attr_kernel_max.attr,
 	&dev_attr_offline.attr,
+#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
+	&dev_attr_modalias.attr,
+#endif
 	NULL
 };
 
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 142e3d600..1b1cbb5 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -28,6 +28,141 @@
 #include "base.h"
 #include "power/power.h"
 
+/*
+ * Deferred Probe infrastructure.
+ *
+ * Sometimes driver probe order matters, but the kernel doesn't always have
+ * dependency information which means some drivers will get probed before a
+ * resource it depends on is available.  For example, an SDHCI driver may
+ * first need a GPIO line from an i2c GPIO controller before it can be
+ * initialized.  If a required resource is not available yet, a driver can
+ * request probing to be deferred by returning -EPROBE_DEFER from its probe hook
+ *
+ * Deferred probe maintains two lists of devices, a pending list and an active
+ * list.  A driver returning -EPROBE_DEFER causes the device to be added to the
+ * pending list.  A successful driver probe will trigger moving all devices
+ * from the pending to the active list so that the workqueue will eventually
+ * retry them.
+ *
+ * The deferred_probe_mutex must be held any time the deferred_probe_*_list
+ * of the (struct device*)->p->deferred_probe pointers are manipulated
+ */
+static DEFINE_MUTEX(deferred_probe_mutex);
+static LIST_HEAD(deferred_probe_pending_list);
+static LIST_HEAD(deferred_probe_active_list);
+static struct workqueue_struct *deferred_wq;
+
+/**
+ * deferred_probe_work_func() - Retry probing devices in the active list.
+ */
+static void deferred_probe_work_func(struct work_struct *work)
+{
+	struct device *dev;
+	struct device_private *private;
+	/*
+	 * This block processes every device in the deferred 'active' list.
+	 * Each device is removed from the active list and passed to
+	 * bus_probe_device() to re-attempt the probe.  The loop continues
+	 * until every device in the active list is removed and retried.
+	 *
+	 * Note: Once the device is removed from the list and the mutex is
+	 * released, it is possible for the device get freed by another thread
+	 * and cause a illegal pointer dereference.  This code uses
+	 * get/put_device() to ensure the device structure cannot disappear
+	 * from under our feet.
+	 */
+	mutex_lock(&deferred_probe_mutex);
+	while (!list_empty(&deferred_probe_active_list)) {
+		private = list_first_entry(&deferred_probe_active_list,
+					typeof(*dev->p), deferred_probe);
+		dev = private->device;
+		list_del_init(&private->deferred_probe);
+
+		get_device(dev);
+
+		/*
+		 * Drop the mutex while probing each device; the probe path may
+		 * manipulate the deferred list
+		 */
+		mutex_unlock(&deferred_probe_mutex);
+		dev_dbg(dev, "Retrying from deferred list\n");
+		bus_probe_device(dev);
+		mutex_lock(&deferred_probe_mutex);
+
+		put_device(dev);
+	}
+	mutex_unlock(&deferred_probe_mutex);
+}
+static DECLARE_WORK(deferred_probe_work, deferred_probe_work_func);
+
+static void driver_deferred_probe_add(struct device *dev)
+{
+	mutex_lock(&deferred_probe_mutex);
+	if (list_empty(&dev->p->deferred_probe)) {
+		dev_dbg(dev, "Added to deferred list\n");
+		list_add(&dev->p->deferred_probe, &deferred_probe_pending_list);
+	}
+	mutex_unlock(&deferred_probe_mutex);
+}
+
+void driver_deferred_probe_del(struct device *dev)
+{
+	mutex_lock(&deferred_probe_mutex);
+	if (!list_empty(&dev->p->deferred_probe)) {
+		dev_dbg(dev, "Removed from deferred list\n");
+		list_del_init(&dev->p->deferred_probe);
+	}
+	mutex_unlock(&deferred_probe_mutex);
+}
+
+static bool driver_deferred_probe_enable = false;
+/**
+ * driver_deferred_probe_trigger() - Kick off re-probing deferred devices
+ *
+ * This functions moves all devices from the pending list to the active
+ * list and schedules the deferred probe workqueue to process them.  It
+ * should be called anytime a driver is successfully bound to a device.
+ */
+static void driver_deferred_probe_trigger(void)
+{
+	if (!driver_deferred_probe_enable)
+		return;
+
+	/*
+	 * A successful probe means that all the devices in the pending list
+	 * should be triggered to be reprobed.  Move all the deferred devices
+	 * into the active list so they can be retried by the workqueue
+	 */
+	mutex_lock(&deferred_probe_mutex);
+	list_splice_tail_init(&deferred_probe_pending_list,
+			      &deferred_probe_active_list);
+	mutex_unlock(&deferred_probe_mutex);
+
+	/*
+	 * Kick the re-probe thread.  It may already be scheduled, but it is
+	 * safe to kick it again.
+	 */
+	queue_work(deferred_wq, &deferred_probe_work);
+}
+
+/**
+ * deferred_probe_initcall() - Enable probing of deferred devices
+ *
+ * We don't want to get in the way when the bulk of drivers are getting probed.
+ * Instead, this initcall makes sure that deferred probing is delayed until
+ * late_initcall time.
+ */
+static int deferred_probe_initcall(void)
+{
+	deferred_wq = create_singlethread_workqueue("deferwq");
+	if (WARN_ON(!deferred_wq))
+		return -ENOMEM;
+
+	driver_deferred_probe_enable = true;
+	driver_deferred_probe_trigger();
+	return 0;
+}
+late_initcall(deferred_probe_initcall);
 
 static void driver_bound(struct device *dev)
 {
@@ -42,6 +177,13 @@
 
 	klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
 
+	/*
+	 * Make sure the device is no longer in one of the deferred lists and
+	 * kick off retrying all pending devices
+	 */
+	driver_deferred_probe_del(dev);
+	driver_deferred_probe_trigger();
+
 	if (dev->bus)
 		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
 					     BUS_NOTIFY_BOUND_DRIVER, dev);
@@ -142,7 +284,11 @@
 	driver_sysfs_remove(dev);
 	dev->driver = NULL;
 
-	if (ret != -ENODEV && ret != -ENXIO) {
+	if (ret == -EPROBE_DEFER) {
+		/* Driver requested deferred probing */
+		dev_info(dev, "Driver %s requests probe deferral\n", drv->name);
+		driver_deferred_probe_add(dev);
+	} else if (ret != -ENODEV && ret != -ENXIO) {
 		/* driver matched but the probe failed */
 		printk(KERN_WARNING
 		       "%s: probe of %s failed with error %d\n",
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index b631f7c..60e4f77 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -153,34 +153,6 @@
 }
 EXPORT_SYMBOL_GPL(driver_add_kobj);
 
-/**
- * get_driver - increment driver reference count.
- * @drv: driver.
- */
-struct device_driver *get_driver(struct device_driver *drv)
-{
-	if (drv) {
-		struct driver_private *priv;
-		struct kobject *kobj;
-
-		kobj = kobject_get(&drv->p->kobj);
-		priv = to_driver(kobj);
-		return priv->driver;
-	}
-	return NULL;
-}
-EXPORT_SYMBOL_GPL(get_driver);
-
-/**
- * put_driver - decrement driver's refcount.
- * @drv: driver.
- */
-void put_driver(struct device_driver *drv)
-{
-	kobject_put(&drv->p->kobj);
-}
-EXPORT_SYMBOL_GPL(put_driver);
-
 static int driver_add_groups(struct device_driver *drv,
 			     const struct attribute_group **groups)
 {
@@ -234,7 +206,6 @@
 
 	other = driver_find(drv->name, drv->bus);
 	if (other) {
-		put_driver(other);
 		printk(KERN_ERR "Error: Driver '%s' is already registered, "
 			"aborting...\n", drv->name);
 		return -EBUSY;
@@ -275,7 +246,9 @@
  * Call kset_find_obj() to iterate over list of drivers on
  * a bus to find driver by name. Return driver if found.
  *
- * Note that kset_find_obj increments driver's reference count.
+ * This routine provides no locking to prevent the driver it returns
+ * from being unregistered or unloaded while the caller is using it.
+ * The caller is responsible for preventing this.
  */
 struct device_driver *driver_find(const char *name, struct bus_type *bus)
 {
@@ -283,6 +256,8 @@
 	struct driver_private *priv;
 
 	if (k) {
+		/* Drop reference added by kset_find_obj() */
+		kobject_put(k);
 		priv = to_driver(k);
 		return priv->driver;
 	}
diff --git a/drivers/base/soc.c b/drivers/base/soc.c
new file mode 100644
index 0000000..05f1503
--- /dev/null
+++ b/drivers/base/soc.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * Author: Lee Jones <lee.jones@linaro.org> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include <linux/spinlock.h>
+#include <linux/sys_soc.h>
+#include <linux/err.h>
+
+static DEFINE_IDR(soc_ida);
+static DEFINE_SPINLOCK(soc_lock);
+
+static ssize_t soc_info_get(struct device *dev,
+			    struct device_attribute *attr,
+			    char *buf);
+
+struct soc_device {
+	struct device dev;
+	struct soc_device_attribute *attr;
+	int soc_dev_num;
+};
+
+static struct bus_type soc_bus_type = {
+	.name  = "soc",
+};
+
+static DEVICE_ATTR(machine,  S_IRUGO, soc_info_get,  NULL);
+static DEVICE_ATTR(family,   S_IRUGO, soc_info_get,  NULL);
+static DEVICE_ATTR(soc_id,   S_IRUGO, soc_info_get,  NULL);
+static DEVICE_ATTR(revision, S_IRUGO, soc_info_get,  NULL);
+
+struct device *soc_device_to_device(struct soc_device *soc_dev)
+{
+	return &soc_dev->dev;
+}
+
+static mode_t soc_attribute_mode(struct kobject *kobj,
+                                 struct attribute *attr,
+                                 int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+
+	if ((attr == &dev_attr_machine.attr)
+	    && (soc_dev->attr->machine != NULL))
+		return attr->mode;
+	if ((attr == &dev_attr_family.attr)
+	    && (soc_dev->attr->family != NULL))
+		return attr->mode;
+	if ((attr == &dev_attr_revision.attr)
+	    && (soc_dev->attr->revision != NULL))
+		return attr->mode;
+	if ((attr == &dev_attr_soc_id.attr)
+	    && (soc_dev->attr->soc_id != NULL))
+	        return attr->mode;
+
+	/* Unknown or unfilled attribute. */
+	return 0;
+}
+
+static ssize_t soc_info_get(struct device *dev,
+			    struct device_attribute *attr,
+			    char *buf)
+{
+	struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+
+	if (attr == &dev_attr_machine)
+		return sprintf(buf, "%s\n", soc_dev->attr->machine);
+	if (attr == &dev_attr_family)
+		return sprintf(buf, "%s\n", soc_dev->attr->family);
+	if (attr == &dev_attr_revision)
+		return sprintf(buf, "%s\n", soc_dev->attr->revision);
+	if (attr == &dev_attr_soc_id)
+		return sprintf(buf, "%s\n", soc_dev->attr->soc_id);
+
+	return -EINVAL;
+
+}
+
+static struct attribute *soc_attr[] = {
+	&dev_attr_machine.attr,
+	&dev_attr_family.attr,
+	&dev_attr_soc_id.attr,
+	&dev_attr_revision.attr,
+	NULL,
+};
+
+static const struct attribute_group soc_attr_group = {
+	.attrs = soc_attr,
+	.is_visible = soc_attribute_mode,
+};
+
+static const struct attribute_group *soc_attr_groups[] = {
+	&soc_attr_group,
+	NULL,
+};
+
+static void soc_release(struct device *dev)
+{
+	struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+
+	kfree(soc_dev);
+}
+
+struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr)
+{
+	struct soc_device *soc_dev;
+	int ret;
+
+	soc_dev = kzalloc(sizeof(*soc_dev), GFP_KERNEL);
+	if (!soc_dev) {
+	        ret = -ENOMEM;
+		goto out1;
+	}
+
+	/* Fetch a unique (reclaimable) SOC ID. */
+	do {
+		if (!ida_pre_get(&soc_ida, GFP_KERNEL)) {
+			ret = -ENOMEM;
+			goto out2;
+		}
+
+		spin_lock(&soc_lock);
+		ret = ida_get_new(&soc_ida, &soc_dev->soc_dev_num);
+		spin_unlock(&soc_lock);
+
+	} while (ret == -EAGAIN);
+
+	if (ret)
+	         goto out2;
+
+	soc_dev->attr = soc_dev_attr;
+	soc_dev->dev.bus = &soc_bus_type;
+	soc_dev->dev.groups = soc_attr_groups;
+	soc_dev->dev.release = soc_release;
+
+	dev_set_name(&soc_dev->dev, "soc%d", soc_dev->soc_dev_num);
+
+	ret = device_register(&soc_dev->dev);
+	if (ret)
+		goto out3;
+
+	return soc_dev;
+
+out3:
+	ida_remove(&soc_ida, soc_dev->soc_dev_num);
+out2:
+	kfree(soc_dev);
+out1:
+	return ERR_PTR(ret);
+}
+
+/* Ensure soc_dev->attr is freed prior to calling soc_device_unregister. */
+void soc_device_unregister(struct soc_device *soc_dev)
+{
+	ida_remove(&soc_ida, soc_dev->soc_dev_num);
+
+	device_unregister(&soc_dev->dev);
+}
+
+static int __init soc_bus_register(void)
+{
+	spin_lock_init(&soc_lock);
+
+	return bus_register(&soc_bus_type);
+}
+core_initcall(soc_bus_register);
+
+static void __exit soc_bus_unregister(void)
+{
+	ida_destroy(&soc_ida);
+
+	bus_unregister(&soc_bus_type);
+}
+module_exit(soc_bus_unregister);
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index e086fbb..8db9089 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -1177,7 +1177,8 @@
   int TimeoutCounter;
   int i;
 
-  
+  memset(&CommandMailbox, 0, sizeof(DAC960_V1_CommandMailbox_T));
+
   if (pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(32)))
 	return DAC960_Failure(Controller, "DMA mask out of range");
   Controller->BounceBufferLimit = DMA_BIT_MASK(32);
@@ -4627,7 +4628,8 @@
   DAC960_Controller_T *Controller = Command->Controller;
   DAC960_CommandType_T CommandType = Command->CommandType;
   DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
-  DAC960_V2_IOCTL_Opcode_T CommandOpcode = CommandMailbox->Common.IOCTL_Opcode;
+  DAC960_V2_IOCTL_Opcode_T IOCTLOpcode = CommandMailbox->Common.IOCTL_Opcode;
+  DAC960_V2_CommandOpcode_T CommandOpcode = CommandMailbox->SCSI_10.CommandOpcode;
   DAC960_V2_CommandStatus_T CommandStatus = Command->V2.CommandStatus;
 
   if (CommandType == DAC960_ReadCommand ||
@@ -4699,7 +4701,7 @@
     {
       if (Controller->ShutdownMonitoringTimer)
 	      return;
-      if (CommandOpcode == DAC960_V2_GetControllerInfo)
+      if (IOCTLOpcode == DAC960_V2_GetControllerInfo)
 	{
 	  DAC960_V2_ControllerInfo_T *NewControllerInfo =
 	    Controller->V2.NewControllerInformation;
@@ -4719,14 +4721,14 @@
 	  memcpy(ControllerInfo, NewControllerInfo,
 		 sizeof(DAC960_V2_ControllerInfo_T));
 	}
-      else if (CommandOpcode == DAC960_V2_GetEvent)
+      else if (IOCTLOpcode == DAC960_V2_GetEvent)
 	{
 	  if (CommandStatus == DAC960_V2_NormalCompletion) {
 	    DAC960_V2_ReportEvent(Controller, Controller->V2.Event);
 	  }
 	  Controller->V2.NextEventSequenceNumber++;
 	}
-      else if (CommandOpcode == DAC960_V2_GetPhysicalDeviceInfoValid &&
+      else if (IOCTLOpcode == DAC960_V2_GetPhysicalDeviceInfoValid &&
 	       CommandStatus == DAC960_V2_NormalCompletion)
 	{
 	  DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInfo =
@@ -4915,7 +4917,7 @@
 	  NewPhysicalDeviceInfo->LogicalUnit++;
 	  Controller->V2.PhysicalDeviceIndex++;
 	}
-      else if (CommandOpcode == DAC960_V2_GetPhysicalDeviceInfoValid)
+      else if (IOCTLOpcode == DAC960_V2_GetPhysicalDeviceInfoValid)
 	{
 	  unsigned int DeviceIndex;
 	  for (DeviceIndex = Controller->V2.PhysicalDeviceIndex;
@@ -4938,7 +4940,7 @@
 	    }
 	  Controller->V2.NeedPhysicalDeviceInformation = false;
 	}
-      else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid &&
+      else if (IOCTLOpcode == DAC960_V2_GetLogicalDeviceInfoValid &&
 	       CommandStatus == DAC960_V2_NormalCompletion)
 	{
 	  DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInfo =
@@ -5065,7 +5067,7 @@
 			 [LogicalDeviceNumber] = true;
 	  NewLogicalDeviceInfo->LogicalDeviceNumber++;
 	}
-      else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid)
+      else if (IOCTLOpcode == DAC960_V2_GetLogicalDeviceInfoValid)
 	{
 	  int LogicalDriveNumber;
 	  for (LogicalDriveNumber = 0;
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 4e4c8a4..a796407 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -354,7 +354,7 @@
 	  Use devices /dev/sx8/$N and /dev/sx8/$Np$M.
 
 config BLK_DEV_UB
-	tristate "Low Performance USB Block driver"
+	tristate "Low Performance USB Block driver (deprecated)"
 	depends on USB
 	help
 	  This driver supports certain USB attached storage devices
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index e7472f5..3fb6ab4 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -1120,7 +1120,7 @@
 			break;
 		case MISC_GET_FW_VER: {
 			struct carm_fw_ver *ver = (struct carm_fw_ver *)
-				mem + sizeof(struct carm_msg_get_fw_ver);
+				(mem + sizeof(struct carm_msg_get_fw_ver));
 			if (!error) {
 				host->fw_ver = le32_to_cpu(ver->version);
 				host->flags |= (ver->features & FL_FW_VER_MASK);
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index 7333b9e..fcec022 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -119,43 +119,6 @@
 
 /*
  */
-
-/* command block wrapper */
-struct bulk_cb_wrap {
-	__le32	Signature;		/* contains 'USBC' */
-	u32	Tag;			/* unique per command id */
-	__le32	DataTransferLength;	/* size of data */
-	u8	Flags;			/* direction in bit 0 */
-	u8	Lun;			/* LUN */
-	u8	Length;			/* of of the CDB */
-	u8	CDB[UB_MAX_CDB_SIZE];	/* max command */
-};
-
-#define US_BULK_CB_WRAP_LEN	31
-#define US_BULK_CB_SIGN		0x43425355	/*spells out USBC */
-#define US_BULK_FLAG_IN		1
-#define US_BULK_FLAG_OUT	0
-
-/* command status wrapper */
-struct bulk_cs_wrap {
-	__le32	Signature;		/* should = 'USBS' */
-	u32	Tag;			/* same as original command */
-	__le32	Residue;		/* amount not transferred */
-	u8	Status;			/* see below */
-};
-
-#define US_BULK_CS_WRAP_LEN	13
-#define US_BULK_CS_SIGN		0x53425355	/* spells out 'USBS' */
-#define US_BULK_STAT_OK		0
-#define US_BULK_STAT_FAIL	1
-#define US_BULK_STAT_PHASE	2
-
-/* bulk-only class specific requests */
-#define US_BULK_RESET_REQUEST	0xff
-#define US_BULK_GET_MAX_LUN	0xfe
-
-/*
- */
 struct ub_dev;
 
 #define UB_MAX_REQ_SG	9	/* cdrecord requires 32KB and maybe a header */
@@ -2477,6 +2440,8 @@
 	int rc;
 	int i;
 
+	pr_info("'Low Performance USB Block' driver is deprecated. "
+			"Please switch to usb-storage\n");
 	for (i = 0; i < UB_QLOCK_NUM; i++)
 		spin_lock_init(&ub_qlockv[i]);
 
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 4364303..ee94686 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -66,21 +66,6 @@
 
 	  If unsure, say N.
 
-config BRIQ_PANEL
-	tristate 'Total Impact briQ front panel driver'
-	depends on PPC_CHRP
-	---help---
-	  The briQ is a small footprint CHRP computer with a frontpanel VFD, a
-	  tristate led and two switches. It is the size of a CDROM drive.
-
-	  If you have such one and want anything showing on the VFD then you
-	  must answer Y here.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called briq_panel.
-
-	  It's safe to say N here.
-
 config BFIN_OTP
 	tristate "Blackfin On-Chip OTP Memory Support"
 	depends on BLACKFIN && (BF51x || BF52x || BF54x)
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 32762ba..0dc5d7c 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -16,7 +16,6 @@
 obj-$(CONFIG_VIOTAPE)		+= viotape.o
 obj-$(CONFIG_IBM_BSR)		+= bsr.o
 obj-$(CONFIG_SGI_MBCS)		+= mbcs.o
-obj-$(CONFIG_BRIQ_PANEL)	+= briq_panel.o
 obj-$(CONFIG_BFIN_OTP)		+= bfin-otp.o
 
 obj-$(CONFIG_PRINTER)		+= lp.o
diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c
deleted file mode 100644
index 095ab90..0000000
--- a/drivers/char/briq_panel.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Drivers for the Total Impact PPC based computer "BRIQ"
- * by Dr. Karsten Jeppesen
- *
- */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/timer.h>
-#include <linux/kernel.h>
-#include <linux/wait.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/miscdevice.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-
-#define		BRIQ_PANEL_MINOR	156
-#define		BRIQ_PANEL_VFD_IOPORT	0x0390
-#define		BRIQ_PANEL_LED_IOPORT	0x0398
-#define		BRIQ_PANEL_VER		"1.1 (04/20/2002)"
-#define		BRIQ_PANEL_MSG0		"Loading Linux"
-
-static int		vfd_is_open;
-static unsigned char	vfd[40];
-static int		vfd_cursor;
-static unsigned char	ledpb, led;
-
-static void update_vfd(void)
-{
-	int	i;
-
-	/* cursor home */
-	outb(0x02, BRIQ_PANEL_VFD_IOPORT);
-	for (i=0; i<20; i++)
-		outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
-
-	/* cursor to next line */
-	outb(0xc0, BRIQ_PANEL_VFD_IOPORT);
-	for (i=20; i<40; i++)
-		outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
-
-}
-
-static void set_led(char state)
-{
-	if (state == 'R')
-		led = 0x01;
-	else if (state == 'G')
-		led = 0x02;
-	else if (state == 'Y')
-		led = 0x03;
-	else if (state == 'X')
-		led = 0x00;
-	outb(led, BRIQ_PANEL_LED_IOPORT);
-}
-
-static int briq_panel_open(struct inode *ino, struct file *filep)
-{
-	tty_lock();
-	/* enforce single access, vfd_is_open is protected by BKL */
-	if (vfd_is_open) {
-		tty_unlock();
-		return -EBUSY;
-	}
-	vfd_is_open = 1;
-
-	tty_unlock();
-	return 0;
-}
-
-static int briq_panel_release(struct inode *ino, struct file *filep)
-{
-	if (!vfd_is_open)
-		return -ENODEV;
-
-	vfd_is_open = 0;
-
-	return 0;
-}
-
-static ssize_t briq_panel_read(struct file *file, char __user *buf, size_t count,
-			 loff_t *ppos)
-{
-	unsigned short c;
-	unsigned char cp;
-
-	if (!vfd_is_open)
-		return -ENODEV;
-
-	c = (inb(BRIQ_PANEL_LED_IOPORT) & 0x000c) | (ledpb & 0x0003);
-	set_led(' ');
-	/* upper button released */
-	if ((!(ledpb & 0x0004)) && (c & 0x0004)) {
-		cp = ' ';
-		ledpb = c;
-		if (copy_to_user(buf, &cp, 1))
-			return -EFAULT;
-		return 1;
-	}
-	/* lower button released */
-	else if ((!(ledpb & 0x0008)) && (c & 0x0008)) {
-		cp = '\r';
-		ledpb = c;
-		if (copy_to_user(buf, &cp, 1))
-			return -EFAULT;
-		return 1;
-	} else {
-		ledpb = c;
-		return 0;
-	}
-}
-
-static void scroll_vfd( void )
-{
-	int	i;
-
-	for (i=0; i<20; i++) {
-		vfd[i] = vfd[i+20];
-		vfd[i+20] = ' ';
-	}
-	vfd_cursor = 20;
-}
-
-static ssize_t briq_panel_write(struct file *file, const char __user *buf, size_t len,
-			  loff_t *ppos)
-{
-	size_t indx = len;
-	int i, esc = 0;
-
-	if (!vfd_is_open)
-		return -EBUSY;
-
-	for (;;) {
-		char c;
-		if (!indx)
-			break;
-		if (get_user(c, buf))
-			return -EFAULT;
-		if (esc) {
-			set_led(c);
-			esc = 0;
-		} else if (c == 27) {
-			esc = 1;
-		} else if (c == 12) {
-			/* do a form feed */
-			for (i=0; i<40; i++)
-				vfd[i] = ' ';
-			vfd_cursor = 0;
-		} else if (c == 10) {
-			if (vfd_cursor < 20)
-				vfd_cursor = 20;
-			else if (vfd_cursor < 40)
-				vfd_cursor = 40;
-			else if (vfd_cursor < 60)
-				vfd_cursor = 60;
-			if (vfd_cursor > 59)
-				scroll_vfd();
-		} else {
-			/* just a character */
-			if (vfd_cursor > 39)
-				scroll_vfd();
-			vfd[vfd_cursor++] = c;
-		}
-		indx--;
-		buf++;
-	}
-	update_vfd();
-
-	return len;
-}
-
-static const struct file_operations briq_panel_fops = {
-	.owner		= THIS_MODULE,
-	.read		= briq_panel_read,
-	.write		= briq_panel_write,
-	.open		= briq_panel_open,
-	.release	= briq_panel_release,
-	.llseek		= noop_llseek,
-};
-
-static struct miscdevice briq_panel_miscdev = {
-	BRIQ_PANEL_MINOR,
-	"briq_panel",
-	&briq_panel_fops
-};
-
-static int __init briq_panel_init(void)
-{
-	struct device_node *root = of_find_node_by_path("/");
-	const char *machine;
-	int i;
-
-	machine = of_get_property(root, "model", NULL);
-	if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) {
-		of_node_put(root);
-		return -ENODEV;
-	}
-	of_node_put(root);
-
-	printk(KERN_INFO
-		"briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)\n",
-		BRIQ_PANEL_VER);
-
-	if (!request_region(BRIQ_PANEL_VFD_IOPORT, 4, "BRIQ Front Panel"))
-		return -EBUSY;
-
-	if (!request_region(BRIQ_PANEL_LED_IOPORT, 2, "BRIQ Front Panel")) {
-		release_region(BRIQ_PANEL_VFD_IOPORT, 4);
-		return -EBUSY;
-	}
-	ledpb = inb(BRIQ_PANEL_LED_IOPORT) & 0x000c;
-
-	if (misc_register(&briq_panel_miscdev) < 0) {
-		release_region(BRIQ_PANEL_VFD_IOPORT, 4);
-		release_region(BRIQ_PANEL_LED_IOPORT, 2);
-		return -EBUSY;
-	}
-
-	outb(0x38, BRIQ_PANEL_VFD_IOPORT);	/* Function set */
-	outb(0x01, BRIQ_PANEL_VFD_IOPORT);	/* Clear display */
-	outb(0x0c, BRIQ_PANEL_VFD_IOPORT);	/* Display on */
-	outb(0x06, BRIQ_PANEL_VFD_IOPORT);	/* Entry normal */
-	for (i=0; i<40; i++)
-		vfd[i]=' ';
-#ifndef MODULE
-	vfd[0] = 'L';
-	vfd[1] = 'o';
-	vfd[2] = 'a';
-	vfd[3] = 'd';
-	vfd[4] = 'i';
-	vfd[5] = 'n';
-	vfd[6] = 'g';
-	vfd[7] = ' ';
-	vfd[8] = '.';
-	vfd[9] = '.';
-	vfd[10] = '.';
-#endif /* !MODULE */
-
-	update_vfd();
-
-	return 0;
-}
-
-static void __exit briq_panel_exit(void)
-{
-	misc_deregister(&briq_panel_miscdev);
-	release_region(BRIQ_PANEL_VFD_IOPORT, 4);
-	release_region(BRIQ_PANEL_LED_IOPORT, 2);
-}
-
-module_init(briq_panel_init);
-module_exit(briq_panel_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Karsten Jeppesen <karsten@jeppesens.com>");
-MODULE_DESCRIPTION("Driver for the Total Impact briQ front panel");
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 07f6a5a..f6453df 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -2484,7 +2484,7 @@
 
 	/* verify range of specified line number */
 	line = tty->index;
-	if ((line < 0) || (line >= mgslpc_device_count)) {
+	if (line >= mgslpc_device_count) {
 		printk("%s(%d):mgslpc_open with invalid line #%d.\n",
 			__FILE__,__LINE__,line);
 		return -ENODEV;
@@ -2836,7 +2836,6 @@
 
     /* Initialize the tty_driver structure */
 
-    serial_driver->owner = THIS_MODULE;
     serial_driver->driver_name = "synclink_cs";
     serial_driver->name = "ttySLP";
     serial_driver->major = ttymajor;
diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c
index 9fec323..2a5e45d2 100644
--- a/drivers/char/ramoops.c
+++ b/drivers/char/ramoops.c
@@ -26,7 +26,6 @@
 #include <linux/module.h>
 #include <linux/kmsg_dump.h>
 #include <linux/time.h>
-#include <linux/err.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c
index 0c964cd..ce29e7c 100644
--- a/drivers/char/tlclk.c
+++ b/drivers/char/tlclk.c
@@ -797,7 +797,7 @@
 	telclk_interrupt = (inb(TLCLK_REG7) & 0x0f);
 
 	if (0x0F == telclk_interrupt ) { /* not MCPBL0010 ? */
-		printk(KERN_ERR "telclk_interrup = 0x%x non-mcpbl0010 hw.\n",
+		printk(KERN_ERR "telclk_interrupt = 0x%x non-mcpbl0010 hw.\n",
 			telclk_interrupt);
 		ret = -ENXIO;
 		goto out3;
diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
index eedd547..46b77ed 100644
--- a/drivers/char/ttyprintk.c
+++ b/drivers/char/ttyprintk.c
@@ -184,12 +184,10 @@
 	if (!ttyprintk_driver)
 		return ret;
 
-	ttyprintk_driver->owner = THIS_MODULE;
 	ttyprintk_driver->driver_name = "ttyprintk";
 	ttyprintk_driver->name = "ttyprintk";
 	ttyprintk_driver->major = TTYAUX_MAJOR;
 	ttyprintk_driver->minor_start = 3;
-	ttyprintk_driver->num = 1;
 	ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
 	ttyprintk_driver->init_termios = tty_std_termios;
 	ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index ad6e64a..8b34c65 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -976,7 +976,7 @@
 
 	tape_class = class_create(THIS_MODULE, "tape");
 	if (IS_ERR(tape_class)) {
-		printk(VIOTAPE_KERN_WARN "Unable to allocat class\n");
+		printk(VIOTAPE_KERN_WARN "Unable to allocate class\n");
 		ret = PTR_ERR(tape_class);
 		goto unreg_chrdev;
 	}
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 6b5cf02..82e8820 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/async.h>
 #include <asm/io.h>
 
 /*
@@ -179,17 +180,15 @@
 /* Number of reads we try to get two different values */
 #define ACPI_PM_READ_CHECKS 10000
 
-static int __init init_acpi_pm_clocksource(void)
+static void __init acpi_pm_clocksource_async(void *unused, async_cookie_t cookie)
 {
 	cycle_t value1, value2;
 	unsigned int i, j = 0;
 
-	if (!pmtmr_ioport)
-		return -ENODEV;
 
 	/* "verify" this timing source: */
 	for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) {
-		udelay(100 * j);
+		usleep_range(100 * j, 100 * j + 100);
 		value1 = clocksource_acpi_pm.read(&clocksource_acpi_pm);
 		for (i = 0; i < ACPI_PM_READ_CHECKS; i++) {
 			value2 = clocksource_acpi_pm.read(&clocksource_acpi_pm);
@@ -203,25 +202,34 @@
 			       " 0x%#llx, 0x%#llx - aborting.\n",
 			       value1, value2);
 			pmtmr_ioport = 0;
-			return -EINVAL;
+			return;
 		}
 		if (i == ACPI_PM_READ_CHECKS) {
 			printk(KERN_INFO "PM-Timer failed consistency check "
 			       " (0x%#llx) - aborting.\n", value1);
 			pmtmr_ioport = 0;
-			return -ENODEV;
+			return;
 		}
 	}
 
 	if (verify_pmtmr_rate() != 0){
 		pmtmr_ioport = 0;
-		return -ENODEV;
+		return;
 	}
 
-	return clocksource_register_hz(&clocksource_acpi_pm,
+	clocksource_register_hz(&clocksource_acpi_pm,
 						PMTMR_TICKS_PER_SEC);
 }
 
+static int __init init_acpi_pm_clocksource(void)
+{
+	if (!pmtmr_ioport)
+		return -ENODEV;
+
+	async_schedule(acpi_pm_clocksource_async, NULL);
+	return 0;
+}
+
 /* We use fs_initcall because we want the PCI fixups to have run
  * but we still need to load before device_initcall
  */
diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c b/drivers/clocksource/clksrc-dbx500-prcmu.c
index fb6b6d2..c26c369 100644
--- a/drivers/clocksource/clksrc-dbx500-prcmu.c
+++ b/drivers/clocksource/clksrc-dbx500-prcmu.c
@@ -52,7 +52,6 @@
 	.name		= "dbx500-prcmu-timer",
 	.rating		= 300,
 	.read		= clksrc_dbx500_prcmu_read,
-	.shift		= 10,
 	.mask		= CLOCKSOURCE_MASK(32),
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 };
@@ -90,7 +89,5 @@
 	setup_sched_clock(dbx500_prcmu_sched_clock_read,
 			 32, RATE_32K);
 #endif
-	clocksource_calc_mult_shift(&clocksource_dbx500_prcmu,
-				    RATE_32K, SCHED_CLOCK_MIN_WRAP);
-	clocksource_register(&clocksource_dbx500_prcmu);
+	clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K);
 }
diff --git a/drivers/clocksource/cs5535-clockevt.c b/drivers/clocksource/cs5535-clockevt.c
index b7dab32..540795c 100644
--- a/drivers/clocksource/cs5535-clockevt.c
+++ b/drivers/clocksource/cs5535-clockevt.c
@@ -100,7 +100,6 @@
 	.set_mode = mfgpt_set_mode,
 	.set_next_event = mfgpt_next_event,
 	.rating = 250,
-	.cpumask = cpu_all_mask,
 	.shift = 32
 };
 
@@ -133,7 +132,7 @@
 
 static struct irqaction mfgptirq  = {
 	.handler = mfgpt_tick,
-	.flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
+	.flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER | IRQF_SHARED,
 	.name = DRV_NAME,
 };
 
diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c
index 72f811f..9e0998f 100644
--- a/drivers/clocksource/cyclone.c
+++ b/drivers/clocksource/cyclone.c
@@ -55,11 +55,11 @@
 	}
 	/* even on 64bit systems, this is only 32bits: */
 	base = readl(reg);
+	iounmap(reg);
 	if (!base) {
 		printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
 		return -ENODEV;
 	}
-	iounmap(reg);
 
 	/* setup PMCC: */
 	offset = base + CYCLONE_PMCC_OFFSET;
diff --git a/drivers/clocksource/scx200_hrt.c b/drivers/clocksource/scx200_hrt.c
index 27f4d96..64f9e82 100644
--- a/drivers/clocksource/scx200_hrt.c
+++ b/drivers/clocksource/scx200_hrt.c
@@ -49,9 +49,6 @@
 	return (cycle_t) inl(scx200_cb_base + SCx200_TIMER_OFFSET);
 }
 
-#define HRT_SHIFT_1	22
-#define HRT_SHIFT_27	26
-
 static struct clocksource cs_hrt = {
 	.name		= "scx200_hrt",
 	.rating		= 250,
@@ -63,6 +60,7 @@
 
 static int __init init_hrt_clocksource(void)
 {
+	u32 freq;
 	/* Make sure scx200 has initialized the configuration block */
 	if (!scx200_cb_present())
 		return -ENODEV;
@@ -71,7 +69,7 @@
 	if (!request_region(scx200_cb_base + SCx200_TIMER_OFFSET,
 			    SCx200_TIMER_SIZE,
 			    "NatSemi SCx200 High-Resolution Timer")) {
-		printk(KERN_WARNING NAME ": unable to lock timer region\n");
+		pr_warn("unable to lock timer region\n");
 		return -ENODEV;
 	}
 
@@ -79,19 +77,13 @@
 	outb(HR_TMEN | (mhz27 ? HR_TMCLKSEL : 0),
 	     scx200_cb_base + SCx200_TMCNFG_OFFSET);
 
-	if (mhz27) {
-		cs_hrt.shift = HRT_SHIFT_27;
-		cs_hrt.mult = clocksource_hz2mult((HRT_FREQ + ppm) * 27,
-						  cs_hrt.shift);
-	} else {
-		cs_hrt.shift = HRT_SHIFT_1;
-		cs_hrt.mult = clocksource_hz2mult(HRT_FREQ + ppm,
-						  cs_hrt.shift);
-	}
-	printk(KERN_INFO "enabling scx200 high-res timer (%s MHz +%d ppm)\n",
-		mhz27 ? "27":"1", ppm);
+	freq = (HRT_FREQ + ppm);
+	if (mhz27)
+		freq *= 27;
 
-	return clocksource_register(&cs_hrt);
+	pr_info("enabling scx200 high-res timer (%s MHz +%d ppm)\n", mhz27 ? "27":"1", ppm);
+
+	return clocksource_register_hz(&cs_hrt, freq);
 }
 
 module_init(init_hrt_clocksource);
diff --git a/drivers/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c
index 7bac808..13d311e 100644
--- a/drivers/cpufreq/cpufreq-nforce2.c
+++ b/drivers/cpufreq/cpufreq-nforce2.c
@@ -385,6 +385,14 @@
 	.owner = THIS_MODULE,
 };
 
+#ifdef MODULE
+static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = {
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2 },
+	{}
+};
+MODULE_DEVICE_TABLE(pci, nforce2_ids);
+#endif
+
 /**
  * nforce2_detect_chipset - detect the Southbridge which contains FSB PLL logic
  *
diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c
index 4bd6815..3fffbe6 100644
--- a/drivers/cpufreq/e_powersaver.c
+++ b/drivers/cpufreq/e_powersaver.c
@@ -16,6 +16,7 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 
+#include <asm/cpu_device_id.h>
 #include <asm/msr.h>
 #include <asm/tsc.h>
 
@@ -437,18 +438,19 @@
 	.attr		= eps_attr,
 };
 
+
+/* This driver will work only on Centaur C7 processors with
+ * Enhanced SpeedStep/PowerSaver registers */
+static const struct x86_cpu_id eps_cpu_id[] = {
+	{ X86_VENDOR_CENTAUR, 6, X86_MODEL_ANY, X86_FEATURE_EST },
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, eps_cpu_id);
+
 static int __init eps_init(void)
 {
-	struct cpuinfo_x86 *c = &cpu_data(0);
-
-	/* This driver will work only on Centaur C7 processors with
-	 * Enhanced SpeedStep/PowerSaver registers */
-	if (c->x86_vendor != X86_VENDOR_CENTAUR
-	    || c->x86 != 6 || c->x86_model < 10)
+	if (!x86_match_cpu(eps_cpu_id) || boot_cpu_data.x86_model < 10)
 		return -ENODEV;
-	if (!cpu_has(c, X86_FEATURE_EST))
-		return -ENODEV;
-
 	if (cpufreq_register_driver(&eps_driver))
 		return -EINVAL;
 	return 0;
diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c
index c587db4..960671f 100644
--- a/drivers/cpufreq/elanfreq.c
+++ b/drivers/cpufreq/elanfreq.c
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/cpufreq.h>
 
+#include <asm/cpu_device_id.h>
 #include <asm/msr.h>
 #include <linux/timex.h>
 #include <linux/io.h>
@@ -277,17 +278,16 @@
 	.attr		= elanfreq_attr,
 };
 
+static const struct x86_cpu_id elan_id[] = {
+	{ X86_VENDOR_AMD, 4, 10, },
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, elan_id);
 
 static int __init elanfreq_init(void)
 {
-	struct cpuinfo_x86 *c = &cpu_data(0);
-
-	/* Test if we have the right hardware */
-	if ((c->x86_vendor != X86_VENDOR_AMD) ||
-		(c->x86 != 4) || (c->x86_model != 10)) {
-		printk(KERN_INFO "elanfreq: error: no Elan processor found!\n");
+	if (!x86_match_cpu(elan_id))
 		return -ENODEV;
-	}
 	return cpufreq_register_driver(&elanfreq_driver);
 }
 
diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c
index ffe1f2c..456bee0 100644
--- a/drivers/cpufreq/gx-suspmod.c
+++ b/drivers/cpufreq/gx-suspmod.c
@@ -82,6 +82,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 
+#include <asm/cpu_device_id.h>
 #include <asm/processor-cyrix.h>
 
 /* PCI config registers, all at F0 */
@@ -171,6 +172,7 @@
 	{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, gx_chipset_tbl);
 
 static void gx_write_byte(int reg, int value)
 {
@@ -185,13 +187,6 @@
 {
 	struct pci_dev *gx_pci = NULL;
 
-	/* check if CPU is a MediaGX or a Geode. */
-	if ((boot_cpu_data.x86_vendor != X86_VENDOR_NSC) &&
-	    (boot_cpu_data.x86_vendor != X86_VENDOR_CYRIX)) {
-		pr_debug("error: no MediaGX/Geode processor found!\n");
-		return NULL;
-	}
-
 	/* detect which companion chip is used */
 	for_each_pci_dev(gx_pci) {
 		if ((pci_match_id(gx_chipset_tbl, gx_pci)) != NULL)
diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c
index f47d26e..53ddbc7 100644
--- a/drivers/cpufreq/longhaul.c
+++ b/drivers/cpufreq/longhaul.c
@@ -35,6 +35,7 @@
 #include <linux/acpi.h>
 
 #include <asm/msr.h>
+#include <asm/cpu_device_id.h>
 #include <acpi/processor.h>
 
 #include "longhaul.h"
@@ -951,12 +952,17 @@
 	.attr	= longhaul_attr,
 };
 
+static const struct x86_cpu_id longhaul_id[] = {
+	{ X86_VENDOR_CENTAUR, 6 },
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, longhaul_id);
 
 static int __init longhaul_init(void)
 {
 	struct cpuinfo_x86 *c = &cpu_data(0);
 
-	if (c->x86_vendor != X86_VENDOR_CENTAUR || c->x86 != 6)
+	if (!x86_match_cpu(longhaul_id))
 		return -ENODEV;
 
 #ifdef CONFIG_SMP
diff --git a/drivers/cpufreq/longrun.c b/drivers/cpufreq/longrun.c
index 34ea359..8bc9f5f 100644
--- a/drivers/cpufreq/longrun.c
+++ b/drivers/cpufreq/longrun.c
@@ -14,6 +14,7 @@
 
 #include <asm/msr.h>
 #include <asm/processor.h>
+#include <asm/cpu_device_id.h>
 
 static struct cpufreq_driver	longrun_driver;
 
@@ -288,6 +289,12 @@
 	.owner		= THIS_MODULE,
 };
 
+static const struct x86_cpu_id longrun_ids[] = {
+	{ X86_VENDOR_TRANSMETA, X86_FAMILY_ANY, X86_MODEL_ANY,
+	  X86_FEATURE_LONGRUN },
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, longrun_ids);
 
 /**
  * longrun_init - initializes the Transmeta Crusoe LongRun CPUFreq driver
@@ -296,12 +303,8 @@
  */
 static int __init longrun_init(void)
 {
-	struct cpuinfo_x86 *c = &cpu_data(0);
-
-	if (c->x86_vendor != X86_VENDOR_TRANSMETA ||
-	    !cpu_has(c, X86_FEATURE_LONGRUN))
+	if (!x86_match_cpu(longrun_ids))
 		return -ENODEV;
-
 	return cpufreq_register_driver(&longrun_driver);
 }
 
diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c
index 6be3e07..827629c9 100644
--- a/drivers/cpufreq/p4-clockmod.c
+++ b/drivers/cpufreq/p4-clockmod.c
@@ -31,6 +31,7 @@
 #include <asm/processor.h>
 #include <asm/msr.h>
 #include <asm/timer.h>
+#include <asm/cpu_device_id.h>
 
 #include "speedstep-lib.h"
 
@@ -289,21 +290,25 @@
 	.attr		= p4clockmod_attr,
 };
 
+static const struct x86_cpu_id cpufreq_p4_id[] = {
+	{ X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_ACC },
+	{}
+};
+
+/*
+ * Intentionally no MODULE_DEVICE_TABLE here: this driver should not
+ * be auto loaded.  Please don't add one.
+ */
 
 static int __init cpufreq_p4_init(void)
 {
-	struct cpuinfo_x86 *c = &cpu_data(0);
 	int ret;
 
 	/*
 	 * THERM_CONTROL is architectural for IA32 now, so
 	 * we can rely on the capability checks
 	 */
-	if (c->x86_vendor != X86_VENDOR_INTEL)
-		return -ENODEV;
-
-	if (!test_cpu_cap(c, X86_FEATURE_ACPI) ||
-				!test_cpu_cap(c, X86_FEATURE_ACC))
+	if (!x86_match_cpu(cpufreq_p4_id) || !boot_cpu_has(X86_FEATURE_ACPI))
 		return -ENODEV;
 
 	ret = cpufreq_register_driver(&p4clockmod_driver);
diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c
index b3379d6..af23e0b 100644
--- a/drivers/cpufreq/powernow-k6.c
+++ b/drivers/cpufreq/powernow-k6.c
@@ -16,6 +16,7 @@
 #include <linux/timex.h>
 #include <linux/io.h>
 
+#include <asm/cpu_device_id.h>
 #include <asm/msr.h>
 
 #define POWERNOW_IOPORT 0xfff0          /* it doesn't matter where, as long
@@ -210,6 +211,12 @@
 	.attr		= powernow_k6_attr,
 };
 
+static const struct x86_cpu_id powernow_k6_ids[] = {
+	{ X86_VENDOR_AMD, 5, 12 },
+	{ X86_VENDOR_AMD, 5, 13 },
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, powernow_k6_ids);
 
 /**
  * powernow_k6_init - initializes the k6 PowerNow! CPUFreq driver
@@ -220,10 +227,7 @@
  */
 static int __init powernow_k6_init(void)
 {
-	struct cpuinfo_x86 *c = &cpu_data(0);
-
-	if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) ||
-		((c->x86_model != 12) && (c->x86_model != 13)))
+	if (!x86_match_cpu(powernow_k6_ids))
 		return -ENODEV;
 
 	if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) {
diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c
index d71d9f3..cf7e1ee 100644
--- a/drivers/cpufreq/powernow-k7.c
+++ b/drivers/cpufreq/powernow-k7.c
@@ -28,6 +28,7 @@
 #include <asm/timer.h>		/* Needed for recalibrate_cpu_khz() */
 #include <asm/msr.h>
 #include <asm/system.h>
+#include <asm/cpu_device_id.h>
 
 #ifdef CONFIG_X86_POWERNOW_K7_ACPI
 #include <linux/acpi.h>
@@ -110,18 +111,19 @@
 	return delta < 5;
 }
 
+static const struct x86_cpu_id powernow_k7_cpuids[] = {
+	{ X86_VENDOR_AMD, 6, },
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, powernow_k7_cpuids);
+
 static int check_powernow(void)
 {
 	struct cpuinfo_x86 *c = &cpu_data(0);
 	unsigned int maxei, eax, ebx, ecx, edx;
 
-	if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 6)) {
-#ifdef MODULE
-		printk(KERN_INFO PFX "This module only works with "
-				"AMD K7 CPUs\n");
-#endif
+	if (!x86_match_cpu(powernow_k7_cpuids))
 		return 0;
-	}
 
 	/* Get maximum capabilities */
 	maxei = cpuid_eax(0x80000000);
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index 8f9b2ce..c0e8164 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -40,6 +40,7 @@
 #include <linux/delay.h>
 
 #include <asm/msr.h>
+#include <asm/cpu_device_id.h>
 
 #include <linux/acpi.h>
 #include <linux/mutex.h>
@@ -520,6 +521,15 @@
 	return 0;
 }
 
+static const struct x86_cpu_id powernow_k8_ids[] = {
+	/* IO based frequency switching */
+	{ X86_VENDOR_AMD, 0xf },
+	/* MSR based frequency switching supported */
+	X86_FEATURE_MATCH(X86_FEATURE_HW_PSTATE),
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, powernow_k8_ids);
+
 static void check_supported_cpu(void *_rc)
 {
 	u32 eax, ebx, ecx, edx;
@@ -527,13 +537,7 @@
 
 	*rc = -ENODEV;
 
-	if (__this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_AMD)
-		return;
-
 	eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
-	if (((eax & CPUID_XFAM) != CPUID_XFAM_K8) &&
-	    ((eax & CPUID_XFAM) < CPUID_XFAM_10H))
-		return;
 
 	if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) {
 		if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
@@ -1553,6 +1557,9 @@
 	unsigned int i, supported_cpus = 0, cpu;
 	int rv;
 
+	if (!x86_match_cpu(powernow_k8_ids))
+		return -ENODEV;
+
 	for_each_online_cpu(i) {
 		int rc;
 		smp_call_function_single(i, check_supported_cpu, &rc, 1);
diff --git a/drivers/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c
index 1e205e6..e42e073 100644
--- a/drivers/cpufreq/sc520_freq.c
+++ b/drivers/cpufreq/sc520_freq.c
@@ -22,6 +22,7 @@
 #include <linux/timex.h>
 #include <linux/io.h>
 
+#include <asm/cpu_device_id.h>
 #include <asm/msr.h>
 
 #define MMCR_BASE	0xfffef000	/* The default base address */
@@ -150,18 +151,19 @@
 	.attr	= sc520_freq_attr,
 };
 
+static const struct x86_cpu_id sc520_ids[] = {
+	{ X86_VENDOR_AMD, 4, 9 },
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, sc520_ids);
 
 static int __init sc520_freq_init(void)
 {
-	struct cpuinfo_x86 *c = &cpu_data(0);
 	int err;
 
-	/* Test if we have the right hardware */
-	if (c->x86_vendor != X86_VENDOR_AMD ||
-	    c->x86 != 4 || c->x86_model != 9) {
-		pr_debug("no Elan SC520 processor found!\n");
+	if (!x86_match_cpu(sc520_ids))
 		return -ENODEV;
-	}
+
 	cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
 	if (!cpuctl) {
 		printk(KERN_ERR "sc520_freq: error: failed to remap memory\n");
diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c
index 6ea3455..3a953d5 100644
--- a/drivers/cpufreq/speedstep-centrino.c
+++ b/drivers/cpufreq/speedstep-centrino.c
@@ -25,6 +25,7 @@
 #include <asm/msr.h>
 #include <asm/processor.h>
 #include <asm/cpufeature.h>
+#include <asm/cpu_device_id.h>
 
 #define PFX		"speedstep-centrino: "
 #define MAINTAINER	"cpufreq@vger.kernel.org"
@@ -595,6 +596,24 @@
 	.owner		= THIS_MODULE,
 };
 
+/*
+ * This doesn't replace the detailed checks above because
+ * the generic CPU IDs don't have a way to match for steppings
+ * or ASCII model IDs.
+ */
+static const struct x86_cpu_id centrino_ids[] = {
+	{ X86_VENDOR_INTEL, 6, 9, X86_FEATURE_EST },
+	{ X86_VENDOR_INTEL, 6, 13, X86_FEATURE_EST },
+	{ X86_VENDOR_INTEL, 6, 13, X86_FEATURE_EST },
+	{ X86_VENDOR_INTEL, 6, 13, X86_FEATURE_EST },
+	{ X86_VENDOR_INTEL, 15, 3, X86_FEATURE_EST },
+	{ X86_VENDOR_INTEL, 15, 4, X86_FEATURE_EST },
+	{}
+};
+#if 0
+/* Autoload or not? Do not for now. */
+MODULE_DEVICE_TABLE(x86cpu, centrino_ids);
+#endif
 
 /**
  * centrino_init - initializes the Enhanced SpeedStep CPUFreq driver
@@ -612,11 +631,8 @@
  */
 static int __init centrino_init(void)
 {
-	struct cpuinfo_x86 *cpu = &cpu_data(0);
-
-	if (!cpu_has(cpu, X86_FEATURE_EST))
+	if (!x86_match_cpu(centrino_ids))
 		return -ENODEV;
-
 	return cpufreq_register_driver(&centrino_driver);
 }
 
diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c
index a748ce7..7432b3a 100644
--- a/drivers/cpufreq/speedstep-ich.c
+++ b/drivers/cpufreq/speedstep-ich.c
@@ -25,6 +25,8 @@
 #include <linux/pci.h>
 #include <linux/sched.h>
 
+#include <asm/cpu_device_id.h>
+
 #include "speedstep-lib.h"
 
 
@@ -388,6 +390,16 @@
 	.attr	= speedstep_attr,
 };
 
+static const struct x86_cpu_id ss_smi_ids[] = {
+	{ X86_VENDOR_INTEL, 6, 0xb, },
+	{ X86_VENDOR_INTEL, 6, 0x8, },
+	{ X86_VENDOR_INTEL, 15, 2 },
+	{}
+};
+#if 0
+/* Autoload or not? Do not for now. */
+MODULE_DEVICE_TABLE(x86cpu, ss_smi_ids);
+#endif
 
 /**
  * speedstep_init - initializes the SpeedStep CPUFreq driver
@@ -398,6 +410,9 @@
  */
 static int __init speedstep_init(void)
 {
+	if (!x86_match_cpu(ss_smi_ids))
+		return -ENODEV;
+
 	/* detect processor */
 	speedstep_processor = speedstep_detect_processor();
 	if (!speedstep_processor) {
diff --git a/drivers/cpufreq/speedstep-lib.c b/drivers/cpufreq/speedstep-lib.c
index 8af2d2f..7047821 100644
--- a/drivers/cpufreq/speedstep-lib.c
+++ b/drivers/cpufreq/speedstep-lib.c
@@ -249,6 +249,7 @@
  *                 DETECT SPEEDSTEP-CAPABLE PROCESSOR                *
  *********************************************************************/
 
+/* Keep in sync with the x86_cpu_id tables in the different modules */
 unsigned int speedstep_detect_processor(void)
 {
 	struct cpuinfo_x86 *c = &cpu_data(0);
diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c
index c76ead3..6a457fc 100644
--- a/drivers/cpufreq/speedstep-smi.c
+++ b/drivers/cpufreq/speedstep-smi.c
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <asm/ist.h>
+#include <asm/cpu_device_id.h>
 
 #include "speedstep-lib.h"
 
@@ -379,6 +380,17 @@
 	.attr		= speedstep_attr,
 };
 
+static const struct x86_cpu_id ss_smi_ids[] = {
+	{ X86_VENDOR_INTEL, 6, 0xb, },
+	{ X86_VENDOR_INTEL, 6, 0x8, },
+	{ X86_VENDOR_INTEL, 15, 2 },
+	{}
+};
+#if 0
+/* Not auto loaded currently */
+MODULE_DEVICE_TABLE(x86cpu, ss_smi_ids);
+#endif
+
 /**
  * speedstep_init - initializes the SpeedStep CPUFreq driver
  *
@@ -388,6 +400,9 @@
  */
 static int __init speedstep_init(void)
 {
+	if (!x86_match_cpu(ss_smi_ids))
+		return -ENODEV;
+
 	speedstep_processor = speedstep_detect_processor();
 
 	switch (speedstep_processor) {
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 59f4261..6588f43 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -94,13 +94,13 @@
 
 	target_state = &drv->states[next_state];
 
-	trace_power_start(POWER_CSTATE, next_state, dev->cpu);
-	trace_cpu_idle(next_state, dev->cpu);
+	trace_power_start_rcuidle(POWER_CSTATE, next_state, dev->cpu);
+	trace_cpu_idle_rcuidle(next_state, dev->cpu);
 
 	entered_state = target_state->enter(dev, drv, next_state);
 
-	trace_power_end(dev->cpu);
-	trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
+	trace_power_end_rcuidle(dev->cpu);
+	trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
 
 	if (entered_state >= 0) {
 		/* Update cpuidle counters */
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index 29b9469..37b2e94 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -19,6 +19,7 @@
 #include <linux/percpu.h>
 #include <linux/smp.h>
 #include <linux/slab.h>
+#include <asm/cpu_device_id.h>
 #include <asm/byteorder.h>
 #include <asm/processor.h>
 #include <asm/i387.h>
@@ -503,12 +504,18 @@
 	}
 };
 
+static struct x86_cpu_id padlock_cpu_id[] = {
+	X86_FEATURE_MATCH(X86_FEATURE_XCRYPT),
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, padlock_cpu_id);
+
 static int __init padlock_init(void)
 {
 	int ret;
 	struct cpuinfo_x86 *c = &cpu_data(0);
 
-	if (!cpu_has_xcrypt)
+	if (!x86_match_cpu(padlock_cpu_id))
 		return -ENODEV;
 
 	if (!cpu_has_xcrypt_enabled) {
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
index 06bdb4b..9266c0e 100644
--- a/drivers/crypto/padlock-sha.c
+++ b/drivers/crypto/padlock-sha.c
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/scatterlist.h>
+#include <asm/cpu_device_id.h>
 #include <asm/i387.h>
 
 struct padlock_sha_desc {
@@ -526,6 +527,12 @@
 	}
 };
 
+static struct x86_cpu_id padlock_sha_ids[] = {
+	X86_FEATURE_MATCH(X86_FEATURE_PHE),
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, padlock_sha_ids);
+
 static int __init padlock_init(void)
 {
 	int rc = -ENODEV;
@@ -533,15 +540,8 @@
 	struct shash_alg *sha1;
 	struct shash_alg *sha256;
 
-	if (!cpu_has_phe) {
-		printk(KERN_NOTICE PFX "VIA PadLock Hash Engine not detected.\n");
+	if (!x86_match_cpu(padlock_sha_ids) || !cpu_has_phe_enabled)
 		return -ENODEV;
-	}
-
-	if (!cpu_has_phe_enabled) {
-		printk(KERN_NOTICE PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
-		return -ENODEV;
-	}
 
 	/* Register the newly added algorithm module if on *
 	* VIA Nano processor, or else just do as before */
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index 618bd4d..99d5527 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -54,14 +54,14 @@
 	mode->vrefresh = timing->refresh;
 
 	mode->hdisplay = timing->xres;
-	mode->hsync_start = mode->hdisplay + timing->left_margin;
+	mode->hsync_start = mode->hdisplay + timing->right_margin;
 	mode->hsync_end = mode->hsync_start + timing->hsync_len;
-	mode->htotal = mode->hsync_end + timing->right_margin;
+	mode->htotal = mode->hsync_end + timing->left_margin;
 
 	mode->vdisplay = timing->yres;
-	mode->vsync_start = mode->vdisplay + timing->upper_margin;
+	mode->vsync_start = mode->vdisplay + timing->lower_margin;
 	mode->vsync_end = mode->vsync_start + timing->vsync_len;
-	mode->vtotal = mode->vsync_end + timing->lower_margin;
+	mode->vtotal = mode->vsync_end + timing->upper_margin;
 	mode->width_mm = panel->width_mm;
 	mode->height_mm = panel->height_mm;
 
@@ -85,14 +85,14 @@
 	timing->refresh = drm_mode_vrefresh(mode);
 
 	timing->xres = mode->hdisplay;
-	timing->left_margin = mode->hsync_start - mode->hdisplay;
+	timing->right_margin = mode->hsync_start - mode->hdisplay;
 	timing->hsync_len = mode->hsync_end - mode->hsync_start;
-	timing->right_margin = mode->htotal - mode->hsync_end;
+	timing->left_margin = mode->htotal - mode->hsync_end;
 
 	timing->yres = mode->vdisplay;
-	timing->upper_margin = mode->vsync_start - mode->vdisplay;
+	timing->lower_margin = mode->vsync_start - mode->vdisplay;
 	timing->vsync_len = mode->vsync_end - mode->vsync_start;
-	timing->lower_margin = mode->vtotal - mode->vsync_end;
+	timing->upper_margin = mode->vtotal - mode->vsync_end;
 
 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
 		timing->vmode = FB_VMODE_INTERLACED;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 58820eb..09cc13f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -246,7 +246,7 @@
 	.remove		= __devexit_p(exynos_drm_platform_remove),
 	.driver		= {
 		.owner	= THIS_MODULE,
-		.name	= DRIVER_NAME,
+		.name	= "exynos-drm",
 	},
 };
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 3508700..54f8f07 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -46,39 +46,13 @@
 	struct exynos_drm_gem_obj	*exynos_gem_obj;
 };
 
-static int exynos_drm_fbdev_set_par(struct fb_info *info)
-{
-	struct fb_var_screeninfo *var = &info->var;
-
-	switch (var->bits_per_pixel) {
-	case 32:
-	case 24:
-	case 18:
-	case 16:
-	case 12:
-		info->fix.visual = FB_VISUAL_TRUECOLOR;
-		break;
-	case 1:
-		info->fix.visual = FB_VISUAL_MONO01;
-		break;
-	default:
-		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
-		break;
-	}
-
-	info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
-
-	return drm_fb_helper_set_par(info);
-}
-
-
 static struct fb_ops exynos_drm_fb_ops = {
 	.owner		= THIS_MODULE,
 	.fb_fillrect	= cfb_fillrect,
 	.fb_copyarea	= cfb_copyarea,
 	.fb_imageblit	= cfb_imageblit,
 	.fb_check_var	= drm_fb_helper_check_var,
-	.fb_set_par	= exynos_drm_fbdev_set_par,
+	.fb_set_par	= drm_fb_helper_set_par,
 	.fb_blank	= drm_fb_helper_blank,
 	.fb_pan_display	= drm_fb_helper_pan_display,
 	.fb_setcmap	= drm_fb_helper_setcmap,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 360adf2..56458ee 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -817,8 +817,6 @@
 		goto err_clk_get;
 	}
 
-	clk_enable(ctx->bus_clk);
-
 	ctx->lcd_clk = clk_get(dev, "sclk_fimd");
 	if (IS_ERR(ctx->lcd_clk)) {
 		dev_err(dev, "failed to get lcd clock\n");
@@ -826,8 +824,6 @@
 		goto err_bus_clk;
 	}
 
-	clk_enable(ctx->lcd_clk);
-
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(dev, "failed to find registers\n");
@@ -864,17 +860,11 @@
 		goto err_req_irq;
 	}
 
-	ctx->clkdiv = fimd_calc_clkdiv(ctx, &panel->timing);
 	ctx->vidcon0 = pdata->vidcon0;
 	ctx->vidcon1 = pdata->vidcon1;
 	ctx->default_win = pdata->default_win;
 	ctx->panel = panel;
 
-	panel->timing.pixclock = clk_get_rate(ctx->lcd_clk) / ctx->clkdiv;
-
-	DRM_DEBUG_KMS("pixel clock = %d, clkdiv = %d\n",
-			panel->timing.pixclock, ctx->clkdiv);
-
 	subdrv = &ctx->subdrv;
 
 	subdrv->probe = fimd_subdrv_probe;
@@ -889,10 +879,15 @@
 
 	platform_set_drvdata(pdev, ctx);
 
-	pm_runtime_set_active(dev);
 	pm_runtime_enable(dev);
 	pm_runtime_get_sync(dev);
 
+	ctx->clkdiv = fimd_calc_clkdiv(ctx, &panel->timing);
+	panel->timing.pixclock = clk_get_rate(ctx->lcd_clk) / ctx->clkdiv;
+
+	DRM_DEBUG_KMS("pixel clock = %d, clkdiv = %d\n",
+			panel->timing.pixclock, ctx->clkdiv);
+
 	for (win = 0; win < WINDOWS_NR; win++)
 		fimd_clear_win(ctx, win);
 
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 03c53fc..558ac71 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -2689,7 +2689,7 @@
 #define   DVS_FORMAT_RGBX888	(2<<25)
 #define   DVS_FORMAT_RGBX161616	(3<<25)
 #define   DVS_SOURCE_KEY	(1<<22)
-#define   DVS_RGB_ORDER_RGBX	(1<<20)
+#define   DVS_RGB_ORDER_XBGR	(1<<20)
 #define   DVS_YUV_BYTE_ORDER_MASK (3<<16)
 #define   DVS_YUV_ORDER_YUYV	(0<<16)
 #define   DVS_YUV_ORDER_UYVY	(1<<16)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f851db7..397087c 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7828,6 +7828,7 @@
 	case DRM_FORMAT_RGB332:
 	case DRM_FORMAT_RGB565:
 	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_XBGR8888:
 	case DRM_FORMAT_ARGB8888:
 	case DRM_FORMAT_XRGB2101010:
 	case DRM_FORMAT_ARGB2101010:
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 2288abf..a083504 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -225,16 +225,16 @@
 
 	/* Mask out pixel format bits in case we change it */
 	dvscntr &= ~DVS_PIXFORMAT_MASK;
-	dvscntr &= ~DVS_RGB_ORDER_RGBX;
+	dvscntr &= ~DVS_RGB_ORDER_XBGR;
 	dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK;
 
 	switch (fb->pixel_format) {
 	case DRM_FORMAT_XBGR8888:
-		dvscntr |= DVS_FORMAT_RGBX888;
+		dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
 		pixel_size = 4;
 		break;
 	case DRM_FORMAT_XRGB8888:
-		dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_RGBX;
+		dvscntr |= DVS_FORMAT_RGBX888;
 		pixel_size = 4;
 		break;
 	case DRM_FORMAT_YUYV:
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index af08ce7..bce53fa 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1619,11 +1619,7 @@
 	list_add_tail(&dynid->list, &hdrv->dyn_list);
 	spin_unlock(&hdrv->dyn_lock);
 
-	ret = 0;
-	if (get_driver(&hdrv->driver)) {
-		ret = driver_attach(&hdrv->driver);
-		put_driver(&hdrv->driver);
-	}
+	ret = driver_attach(&hdrv->driver);
 
 	return ret ? : count;
 }
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 36484db..9ffbfc5 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -37,81 +37,6 @@
 	void (*message_handler)(struct vmbus_channel_message_header *msg);
 };
 
-#define MAX_MSG_TYPES                    4
-#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 8
-
-static const uuid_le
-	supported_device_classes[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
-	/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
-	/* Storage - SCSI */
-	{
-		.b  = {
-			0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
-			0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
-		}
-	},
-
-	/* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
-	/* Network */
-	{
-		.b = {
-			0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
-			0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
-		}
-	},
-
-	/* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
-	/* Input */
-	{
-		.b = {
-			0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
-			0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A
-		}
-	},
-
-	/* {32412632-86cb-44a2-9b5c-50d1417354f5} */
-	/* IDE */
-	{
-		.b = {
-			0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
-			0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
-		}
-	},
-	/* 0E0B6031-5213-4934-818B-38D90CED39DB */
-	/* Shutdown */
-	{
-		.b = {
-			0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
-			0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
-		}
-	},
-	/* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
-	/* TimeSync */
-	{
-		.b = {
-			0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
-			0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
-		}
-	},
-	/* {57164f39-9115-4e78-ab55-382f3bd5422d} */
-	/* Heartbeat */
-	{
-		.b = {
-			0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
-			0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d
-		}
-	},
-	/* {A9A0F4E7-5A45-4d96-B827-8A841E8C03E6} */
-	/* KVP */
-	{
-		.b = {
-			0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
-			0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3,  0xe6
-	}
-	},
-
-};
-
 
 /**
  * vmbus_prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
@@ -321,20 +246,8 @@
 	struct vmbus_channel *newchannel;
 	uuid_le *guidtype;
 	uuid_le *guidinstance;
-	int i;
-	int fsupported = 0;
 
 	offer = (struct vmbus_channel_offer_channel *)hdr;
-	for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
-		if (!uuid_le_cmp(offer->offer.if_type,
-				supported_device_classes[i])) {
-			fsupported = 1;
-			break;
-		}
-	}
-
-	if (!fsupported)
-		return;
 
 	guidtype = &offer->offer.if_type;
 	guidinstance = &offer->offer.if_instance;
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 12aa97f..15956bd 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -155,9 +155,9 @@
 	union hv_x64_msr_hypercall_contents hypercall_msr;
 	void *virtaddr = NULL;
 
-	memset(hv_context.synic_event_page, 0, sizeof(void *) * MAX_NUM_CPUS);
+	memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
 	memset(hv_context.synic_message_page, 0,
-	       sizeof(void *) * MAX_NUM_CPUS);
+	       sizeof(void *) * NR_CPUS);
 
 	if (!query_hypervisor_presence())
 		goto cleanup;
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 0e8343f..6186025 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -28,8 +28,6 @@
 #include <linux/workqueue.h>
 #include <linux/hyperv.h>
 
-#include "hv_kvp.h"
-
 
 
 /*
@@ -44,9 +42,10 @@
 static struct {
 	bool active; /* transaction status - active or not */
 	int recv_len; /* number of bytes received. */
-	int index; /* current index */
+	struct hv_kvp_msg  *kvp_msg; /* current message */
 	struct vmbus_channel *recv_channel; /* chn we got the request */
 	u64 recv_req_id; /* request ID. */
+	void *kvp_context; /* for the channel callback */
 } kvp_transaction;
 
 static void kvp_send_key(struct work_struct *dummy);
@@ -73,15 +72,20 @@
 {
 
 	struct cn_msg *msg;
+	struct hv_kvp_msg *kvp_msg;
+	char *version;
 
-	msg = kzalloc(sizeof(*msg) + strlen(HV_DRV_VERSION) + 1 , GFP_ATOMIC);
+	msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg), GFP_ATOMIC);
 
 	if (msg) {
+		kvp_msg = (struct hv_kvp_msg *)msg->data;
+		version = kvp_msg->body.kvp_register.version;
 		msg->id.idx =  CN_KVP_IDX;
 		msg->id.val = CN_KVP_VAL;
-		msg->seq = KVP_REGISTER;
-		strcpy(msg->data, HV_DRV_VERSION);
-		msg->len = strlen(HV_DRV_VERSION) + 1;
+
+		kvp_msg->kvp_hdr.operation = KVP_OP_REGISTER;
+		strcpy(version, HV_DRV_VERSION);
+		msg->len = sizeof(struct hv_kvp_msg);
 		cn_netlink_send(msg, 0, GFP_ATOMIC);
 		kfree(msg);
 	}
@@ -103,23 +107,28 @@
 static void
 kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
 {
-	struct hv_ku_msg *message;
+	struct hv_kvp_msg *message;
+	struct hv_kvp_msg_enumerate *data;
 
-	message = (struct hv_ku_msg *)msg->data;
-	if (msg->seq == KVP_REGISTER) {
+	message = (struct hv_kvp_msg *)msg->data;
+	switch (message->kvp_hdr.operation) {
+	case KVP_OP_REGISTER:
 		pr_info("KVP: user-mode registering done.\n");
 		kvp_register();
-	}
+		kvp_transaction.active = false;
+		hv_kvp_onchannelcallback(kvp_transaction.kvp_context);
+		break;
 
-	if (msg->seq == KVP_USER_SET) {
+	default:
+		data = &message->body.kvp_enum_data;
 		/*
 		 * Complete the transaction by forwarding the key value
 		 * to the host. But first, cancel the timeout.
 		 */
 		if (cancel_delayed_work_sync(&kvp_work))
-			kvp_respond_to_host(message->kvp_key,
-						message->kvp_value,
-						!strlen(message->kvp_key));
+			kvp_respond_to_host(data->data.key,
+					 data->data.value,
+					!strlen(data->data.key));
 	}
 }
 
@@ -127,19 +136,105 @@
 kvp_send_key(struct work_struct *dummy)
 {
 	struct cn_msg *msg;
-	int index = kvp_transaction.index;
+	struct hv_kvp_msg *message;
+	struct hv_kvp_msg *in_msg;
+	__u8 operation = kvp_transaction.kvp_msg->kvp_hdr.operation;
+	__u8 pool = kvp_transaction.kvp_msg->kvp_hdr.pool;
+	__u32 val32;
+	__u64 val64;
 
 	msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC);
+	if (!msg)
+		return;
 
-	if (msg) {
-		msg->id.idx =  CN_KVP_IDX;
-		msg->id.val = CN_KVP_VAL;
-		msg->seq = KVP_KERNEL_GET;
-		((struct hv_ku_msg *)msg->data)->kvp_index = index;
-		msg->len = sizeof(struct hv_ku_msg);
-		cn_netlink_send(msg, 0, GFP_ATOMIC);
-		kfree(msg);
+	msg->id.idx =  CN_KVP_IDX;
+	msg->id.val = CN_KVP_VAL;
+
+	message = (struct hv_kvp_msg *)msg->data;
+	message->kvp_hdr.operation = operation;
+	message->kvp_hdr.pool = pool;
+	in_msg = kvp_transaction.kvp_msg;
+
+	/*
+	 * The key/value strings sent from the host are encoded in
+	 * in utf16; convert it to utf8 strings.
+	 * The host assures us that the utf16 strings will not exceed
+	 * the max lengths specified. We will however, reserve room
+	 * for the string terminating character - in the utf16s_utf8s()
+	 * function we limit the size of the buffer where the converted
+	 * string is placed to HV_KVP_EXCHANGE_MAX_*_SIZE -1 to gaurantee
+	 * that the strings can be properly terminated!
+	 */
+
+	switch (message->kvp_hdr.operation) {
+	case KVP_OP_SET:
+		switch (in_msg->body.kvp_set.data.value_type) {
+		case REG_SZ:
+			/*
+			 * The value is a string - utf16 encoding.
+			 */
+			message->body.kvp_set.data.value_size =
+				utf16s_to_utf8s(
+				(wchar_t *)in_msg->body.kvp_set.data.value,
+				in_msg->body.kvp_set.data.value_size,
+				UTF16_LITTLE_ENDIAN,
+				message->body.kvp_set.data.value,
+				HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1) + 1;
+				break;
+
+		case REG_U32:
+			/*
+			 * The value is a 32 bit scalar.
+			 * We save this as a utf8 string.
+			 */
+			val32 = in_msg->body.kvp_set.data.value_u32;
+			message->body.kvp_set.data.value_size =
+				sprintf(message->body.kvp_set.data.value,
+					"%d", val32) + 1;
+			break;
+
+		case REG_U64:
+			/*
+			 * The value is a 64 bit scalar.
+			 * We save this as a utf8 string.
+			 */
+			val64 = in_msg->body.kvp_set.data.value_u64;
+			message->body.kvp_set.data.value_size =
+				sprintf(message->body.kvp_set.data.value,
+					"%llu", val64) + 1;
+			break;
+
+		}
+	case KVP_OP_GET:
+		message->body.kvp_set.data.key_size =
+			utf16s_to_utf8s(
+			(wchar_t *)in_msg->body.kvp_set.data.key,
+			in_msg->body.kvp_set.data.key_size,
+			UTF16_LITTLE_ENDIAN,
+			message->body.kvp_set.data.key,
+			HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
+			break;
+
+	case KVP_OP_DELETE:
+		message->body.kvp_delete.key_size =
+			utf16s_to_utf8s(
+			(wchar_t *)in_msg->body.kvp_delete.key,
+			in_msg->body.kvp_delete.key_size,
+			UTF16_LITTLE_ENDIAN,
+			message->body.kvp_delete.key,
+			HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
+			break;
+
+	case KVP_OP_ENUMERATE:
+		message->body.kvp_enum_data.index =
+			in_msg->body.kvp_enum_data.index;
+			break;
 	}
+
+	msg->len = sizeof(struct hv_kvp_msg);
+	cn_netlink_send(msg, 0, GFP_ATOMIC);
+	kfree(msg);
+
 	return;
 }
 
@@ -151,10 +246,11 @@
 kvp_respond_to_host(char *key, char *value, int error)
 {
 	struct hv_kvp_msg  *kvp_msg;
-	struct hv_kvp_msg_enumerate  *kvp_data;
+	struct hv_kvp_exchg_msg_value  *kvp_data;
 	char	*key_name;
 	struct icmsg_hdr *icmsghdrp;
-	int	keylen, valuelen;
+	int	keylen = 0;
+	int	valuelen = 0;
 	u32	buf_len;
 	struct vmbus_channel *channel;
 	u64	req_id;
@@ -181,6 +277,9 @@
 
 	kvp_transaction.active = false;
 
+	icmsghdrp = (struct icmsg_hdr *)
+			&recv_buffer[sizeof(struct vmbuspipe_hdr)];
+
 	if (channel->onchannel_callback == NULL)
 		/*
 		 * We have raced with util driver being unloaded;
@@ -188,41 +287,67 @@
 		 */
 		return;
 
-	icmsghdrp = (struct icmsg_hdr *)
-			&recv_buffer[sizeof(struct vmbuspipe_hdr)];
-	kvp_msg = (struct hv_kvp_msg *)
-			&recv_buffer[sizeof(struct vmbuspipe_hdr) +
-			sizeof(struct icmsg_hdr)];
-	kvp_data = &kvp_msg->kvp_data;
-	key_name = key;
 
 	/*
-	 * If the error parameter is set, terminate the host's enumeration.
+	 * If the error parameter is set, terminate the host's enumeration
+	 * on this pool.
 	 */
 	if (error) {
 		/*
-		 * We don't support this index or the we have timedout;
-		 * terminate the host-side iteration by returning an error.
+		 * Something failed or the we have timedout;
+		 * terminate the current  host-side iteration.
 		 */
-		icmsghdrp->status = HV_E_FAIL;
+		icmsghdrp->status = HV_S_CONT;
 		goto response_done;
 	}
 
+	icmsghdrp->status = HV_S_OK;
+
+	kvp_msg = (struct hv_kvp_msg *)
+			&recv_buffer[sizeof(struct vmbuspipe_hdr) +
+			sizeof(struct icmsg_hdr)];
+
+	switch (kvp_transaction.kvp_msg->kvp_hdr.operation) {
+	case KVP_OP_GET:
+		kvp_data = &kvp_msg->body.kvp_get.data;
+		goto copy_value;
+
+	case KVP_OP_SET:
+	case KVP_OP_DELETE:
+		goto response_done;
+
+	default:
+		break;
+	}
+
+	kvp_data = &kvp_msg->body.kvp_enum_data.data;
+	key_name = key;
+
 	/*
 	 * The windows host expects the key/value pair to be encoded
-	 * in utf16.
+	 * in utf16. Ensure that the key/value size reported to the host
+	 * will be less than or equal to the MAX size (including the
+	 * terminating character).
 	 */
 	keylen = utf8s_to_utf16s(key_name, strlen(key_name), UTF16_HOST_ENDIAN,
-				(wchar_t *) kvp_data->data.key,
-				HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2);
-	kvp_data->data.key_size = 2*(keylen + 1); /* utf16 encoding */
-	valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN,
-				(wchar_t *) kvp_data->data.value,
-				HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2);
-	kvp_data->data.value_size = 2*(valuelen + 1); /* utf16 encoding */
+				(wchar_t *) kvp_data->key,
+				(HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2) - 2);
+	kvp_data->key_size = 2*(keylen + 1); /* utf16 encoding */
 
-	kvp_data->data.value_type = REG_SZ; /* all our values are strings */
-	icmsghdrp->status = HV_S_OK;
+copy_value:
+	valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN,
+				(wchar_t *) kvp_data->value,
+				(HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2);
+	kvp_data->value_size = 2*(valuelen + 1); /* utf16 encoding */
+
+	/*
+	 * If the utf8s to utf16s conversion failed; notify host
+	 * of the error.
+	 */
+	if ((keylen < 0) || (valuelen < 0))
+		icmsghdrp->status = HV_E_FAIL;
+
+	kvp_data->value_type = REG_SZ; /* all our values are strings */
 
 response_done:
 	icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
@@ -249,11 +374,18 @@
 	u64 requestid;
 
 	struct hv_kvp_msg *kvp_msg;
-	struct hv_kvp_msg_enumerate *kvp_data;
 
 	struct icmsg_hdr *icmsghdrp;
 	struct icmsg_negotiate *negop = NULL;
 
+	if (kvp_transaction.active) {
+		/*
+		 * We will defer processing this callback once
+		 * the current transaction is complete.
+		 */
+		kvp_transaction.kvp_context = context;
+		return;
+	}
 
 	vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid);
 
@@ -268,29 +400,16 @@
 				sizeof(struct vmbuspipe_hdr) +
 				sizeof(struct icmsg_hdr)];
 
-			kvp_data = &kvp_msg->kvp_data;
-
-			/*
-			 * We only support the "get" operation on
-			 * "KVP_POOL_AUTO" pool.
-			 */
-
-			if ((kvp_msg->kvp_hdr.pool != KVP_POOL_AUTO) ||
-				(kvp_msg->kvp_hdr.operation !=
-				KVP_OP_ENUMERATE)) {
-				icmsghdrp->status = HV_E_FAIL;
-				goto callback_done;
-			}
-
 			/*
 			 * Stash away this global state for completing the
 			 * transaction; note transactions are serialized.
 			 */
+
 			kvp_transaction.recv_len = recvlen;
 			kvp_transaction.recv_channel = channel;
 			kvp_transaction.recv_req_id = requestid;
 			kvp_transaction.active = true;
-			kvp_transaction.index = kvp_data->index;
+			kvp_transaction.kvp_msg = kvp_msg;
 
 			/*
 			 * Get the information from the
@@ -308,8 +427,6 @@
 
 		}
 
-callback_done:
-
 		icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
 			| ICMSGHDRFLAG_RESPONSE;
 
@@ -330,6 +447,14 @@
 		return err;
 	recv_buffer = srv->recv_buffer;
 
+	/*
+	 * When this driver loads, the user level daemon that
+	 * processes the host requests may not yet be running.
+	 * Defer processing channel callbacks until the daemon
+	 * has registered.
+	 */
+	kvp_transaction.active = true;
+
 	return 0;
 }
 
diff --git a/drivers/hv/hv_kvp.h b/drivers/hv/hv_kvp.h
deleted file mode 100644
index 9b765d7..0000000
--- a/drivers/hv/hv_kvp.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * An implementation of HyperV key value pair (KVP) functionality for Linux.
- *
- *
- * Copyright (C) 2010, Novell, Inc.
- * Author : K. Y. Srinivasan <ksrinivasan@novell.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.
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT.  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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-#ifndef	_KVP_H
-#define	_KVP_H_
-
-/*
- * Maximum value size - used for both key names and value data, and includes
- * any applicable NULL terminators.
- *
- * Note:  This limit is somewhat arbitrary, but falls easily within what is
- * supported for all native guests (back to Win 2000) and what is reasonable
- * for the IC KVP exchange functionality.  Note that Windows Me/98/95 are
- * limited to 255 character key names.
- *
- * MSDN recommends not storing data values larger than 2048 bytes in the
- * registry.
- *
- * Note:  This value is used in defining the KVP exchange message - this value
- * cannot be modified without affecting the message size and compatibility.
- */
-
-/*
- * bytes, including any null terminators
- */
-#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE          (2048)
-
-
-/*
- * Maximum key size - the registry limit for the length of an entry name
- * is 256 characters, including the null terminator
- */
-
-#define HV_KVP_EXCHANGE_MAX_KEY_SIZE            (512)
-
-/*
- * In Linux, we implement the KVP functionality in two components:
- * 1) The kernel component which is packaged as part of the hv_utils driver
- * is responsible for communicating with the host and responsible for
- * implementing the host/guest protocol. 2) A user level daemon that is
- * responsible for data gathering.
- *
- * Host/Guest Protocol: The host iterates over an index and expects the guest
- * to assign a key name to the index and also return the value corresponding to
- * the key. The host will have atmost one KVP transaction outstanding at any
- * given point in time. The host side iteration stops when the guest returns
- * an error. Microsoft has specified the following mapping of key names to
- * host specified index:
- *
- *	Index		Key Name
- *	0		FullyQualifiedDomainName
- *	1		IntegrationServicesVersion
- *	2		NetworkAddressIPv4
- *	3		NetworkAddressIPv6
- *	4		OSBuildNumber
- *	5		OSName
- *	6		OSMajorVersion
- *	7		OSMinorVersion
- *	8		OSVersion
- *	9		ProcessorArchitecture
- *
- * The Windows host expects the Key Name and Key Value to be encoded in utf16.
- *
- * Guest Kernel/KVP Daemon Protocol: As noted earlier, we implement all of the
- * data gathering functionality in a user mode daemon. The user level daemon
- * is also responsible for binding the key name to the index as well. The
- * kernel and user-level daemon communicate using a connector channel.
- *
- * The user mode component first registers with the
- * the kernel component. Subsequently, the kernel component requests, data
- * for the specified keys. In response to this message the user mode component
- * fills in the value corresponding to the specified key. We overload the
- * sequence field in the cn_msg header to define our KVP message types.
- *
- *
- * The kernel component simply acts as a conduit for communication between the
- * Windows host and the user-level daemon. The kernel component passes up the
- * index received from the Host to the user-level daemon. If the index is
- * valid (supported), the corresponding key as well as its
- * value (both are strings) is returned. If the index is invalid
- * (not supported), a NULL key string is returned.
- */
-
-/*
- *
- * The following definitions are shared with the user-mode component; do not
- * change any of this without making the corresponding changes in
- * the KVP user-mode component.
- */
-
-#define CN_KVP_VAL             0x1 /* This supports queries from the kernel */
-#define CN_KVP_USER_VAL       0x2 /* This supports queries from the user */
-
-enum hv_ku_op {
-	KVP_REGISTER = 0, /* Register the user mode component */
-	KVP_KERNEL_GET, /* Kernel is requesting the value */
-	KVP_KERNEL_SET, /* Kernel is providing the value */
-	KVP_USER_GET,  /* User is requesting the value */
-	KVP_USER_SET  /* User is providing the value */
-};
-
-struct hv_ku_msg {
-	__u32 kvp_index; /* Key index */
-	__u8  kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */
-	__u8  kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key  value */
-};
-
-
-
-
-#ifdef __KERNEL__
-
-/*
- * Registry value types.
- */
-
-#define REG_SZ 1
-
-enum hv_kvp_exchg_op {
-	KVP_OP_GET = 0,
-	KVP_OP_SET,
-	KVP_OP_DELETE,
-	KVP_OP_ENUMERATE,
-	KVP_OP_COUNT /* Number of operations, must be last. */
-};
-
-enum hv_kvp_exchg_pool {
-	KVP_POOL_EXTERNAL = 0,
-	KVP_POOL_GUEST,
-	KVP_POOL_AUTO,
-	KVP_POOL_AUTO_EXTERNAL,
-	KVP_POOL_AUTO_INTERNAL,
-	KVP_POOL_COUNT /* Number of pools, must be last. */
-};
-
-struct hv_kvp_hdr {
-	u8 operation;
-	u8 pool;
-};
-
-struct hv_kvp_exchg_msg_value {
-	u32 value_type;
-	u32 key_size;
-	u32 value_size;
-	u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
-	u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
-};
-
-struct hv_kvp_msg_enumerate {
-	u32 index;
-	struct hv_kvp_exchg_msg_value data;
-};
-
-struct hv_kvp_msg {
-	struct hv_kvp_hdr	kvp_hdr;
-	struct hv_kvp_msg_enumerate	kvp_data;
-};
-
-int hv_kvp_init(struct hv_util_service *);
-void hv_kvp_deinit(void);
-void hv_kvp_onchannelcallback(void *);
-
-#endif /* __KERNEL__ */
-#endif	/* _KVP_H */
-
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index 55d58f2..dbb8b8e 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -28,9 +28,6 @@
 #include <linux/reboot.h>
 #include <linux/hyperv.h>
 
-#include "hv_kvp.h"
-
-
 static void shutdown_onchannelcallback(void *context);
 static struct hv_util_service util_shutdown = {
 	.util_cb = shutdown_onchannelcallback,
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 6d7d286..699f0d8 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -457,7 +457,6 @@
 	},
 };
 
-#define MAX_NUM_CPUS	32
 
 
 struct hv_input_signal_event_buffer {
@@ -483,8 +482,8 @@
 	/* 8-bytes aligned of the buffer above */
 	struct hv_input_signal_event *signal_event_param;
 
-	void *synic_message_page[MAX_NUM_CPUS];
-	void *synic_event_page[MAX_NUM_CPUS];
+	void *synic_message_page[NR_CPUS];
+	void *synic_event_page[NR_CPUS];
 };
 
 extern struct hv_context hv_context;
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index a6c6ec3..249ac46 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -39,6 +39,7 @@
 #include <linux/moduleparam.h>
 #include <asm/msr.h>
 #include <asm/processor.h>
+#include <asm/cpu_device_id.h>
 
 #define DRVNAME	"coretemp"
 
@@ -759,13 +760,23 @@
 	.notifier_call = coretemp_cpu_callback,
 };
 
+static const struct x86_cpu_id coretemp_ids[] = {
+	{ X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTS },
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, coretemp_ids);
+
 static int __init coretemp_init(void)
 {
 	int i, err = -ENODEV;
 
-	/* quick check if we run Intel */
-	if (cpu_data(0).x86_vendor != X86_VENDOR_INTEL)
-		goto exit;
+	/*
+	 * CPUID.06H.EAX[0] indicates whether the CPU has thermal
+	 * sensors. We check this bit only, all the early CPUs
+	 * without thermal sensors will be filtered out.
+	 */
+	if (!x86_match_cpu(coretemp_ids))
+		return -ENODEV;
 
 	err = platform_driver_register(&coretemp_driver);
 	if (err)
diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c
index 880b90c..e3e8420 100644
--- a/drivers/hwmon/pmbus/zl6100.c
+++ b/drivers/hwmon/pmbus/zl6100.c
@@ -200,17 +200,11 @@
 	data->id = mid->driver_data;
 
 	/*
-	 * ZL2005, ZL2008, ZL2105, and ZL6100 are known to require a wait time
-	 * between I2C accesses. ZL2004 and ZL6105 are known to be safe.
-	 * Other chips have not yet been tested.
-	 *
-	 * Only clear the wait time for chips known to be safe. The wait time
-	 * can be cleared later for additional chips if tests show that it
-	 * is not needed (in other words, better be safe than sorry).
+	 * According to information from the chip vendor, all currently
+	 * supported chips are known to require a wait time between I2C
+	 * accesses.
 	 */
 	data->delay = delay;
-	if (data->id == zl2004 || data->id == zl6105)
-		data->delay = 0;
 
 	/*
 	 * Since there was a direct I2C device access above, wait before
diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c
index 8eac67d..8689664 100644
--- a/drivers/hwmon/via-cputemp.c
+++ b/drivers/hwmon/via-cputemp.c
@@ -37,6 +37,7 @@
 #include <linux/cpu.h>
 #include <asm/msr.h>
 #include <asm/processor.h>
+#include <asm/cpu_device_id.h>
 
 #define DRVNAME	"via_cputemp"
 
@@ -308,15 +309,20 @@
 	.notifier_call = via_cputemp_cpu_callback,
 };
 
+static const struct x86_cpu_id cputemp_ids[] = {
+	{ X86_VENDOR_CENTAUR, 6, 0xa, }, /* C7 A */
+	{ X86_VENDOR_CENTAUR, 6, 0xd, }, /* C7 D */
+	{ X86_VENDOR_CENTAUR, 6, 0xf, }, /* Nano */
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, cputemp_ids);
+
 static int __init via_cputemp_init(void)
 {
 	int i, err;
 
-	if (cpu_data(0).x86_vendor != X86_VENDOR_CENTAUR) {
-		printk(KERN_DEBUG DRVNAME ": Not a VIA CPU\n");
-		err = -ENODEV;
-		goto exit;
-	}
+	if (!x86_match_cpu(cputemp_ids))
+		return -ENODEV;
 
 	err = platform_driver_register(&via_cputemp_driver);
 	if (err)
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 5276d19..a658d62 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -39,7 +39,7 @@
 					       0x8860 0xa1
     w83627dhg    9      5       4       3      0xa020 0xc1    0x5ca3
     w83627dhg-p  9      5       4       3      0xb070 0xc1    0x5ca3
-    w83627uhg    8      2       2       2      0xa230 0xc1    0x5ca3
+    w83627uhg    8      2       2       3      0xa230 0xc1    0x5ca3
     w83667hg     9      5       3       3      0xa510 0xc1    0x5ca3
     w83667hg-b   9      5       3       4      0xb350 0xc1    0x5ca3
     nct6775f     9      4       3       9      0xb470 0xc1    0x5ca3
@@ -1607,7 +1607,7 @@
 	val = step_time_to_reg(val, data->pwm_mode[nr]); \
 	mutex_lock(&data->update_lock); \
 	data->reg[nr] = val; \
-	w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
+	w83627ehf_write_value(data, data->REG_##REG[nr], val); \
 	mutex_unlock(&data->update_lock); \
 	return count; \
 } \
@@ -2004,7 +2004,8 @@
 		goto exit;
 	}
 
-	data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(struct w83627ehf_data),
+			    GFP_KERNEL);
 	if (!data) {
 		err = -ENOMEM;
 		goto exit_release;
@@ -2157,16 +2158,16 @@
 		w83627ehf_set_temp_reg_ehf(data, 3);
 
 		/*
-		 * Temperature sources for temp1 and temp2 are selected with
+		 * Temperature sources for temp2 and temp3 are selected with
 		 * bank 0, registers 0x49 and 0x4a.
 		 */
 		data->temp_src[0] = 0;	/* SYSTIN */
 		reg = w83627ehf_read_value(data, 0x49) & 0x07;
 		/* Adjust to have the same mapping as other source registers */
 		if (reg == 0)
-			data->temp_src[1]++;
+			data->temp_src[1] = 1;
 		else if (reg >= 2 && reg <= 5)
-			data->temp_src[1] += 2;
+			data->temp_src[1] = reg + 2;
 		else	/* should never happen */
 			data->have_temp &= ~(1 << 1);
 		reg = w83627ehf_read_value(data, 0x4a);
@@ -2493,9 +2494,8 @@
 
 exit_remove:
 	w83627ehf_device_remove_files(dev);
-	kfree(data);
-	platform_set_drvdata(pdev, NULL);
 exit_release:
+	platform_set_drvdata(pdev, NULL);
 	release_region(res->start, IOREGION_LENGTH);
 exit:
 	return err;
@@ -2509,7 +2509,6 @@
 	w83627ehf_device_remove_files(&pdev->dev);
 	release_region(data->addr, IOREGION_LENGTH);
 	platform_set_drvdata(pdev, NULL);
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index 525c734..24f94f4 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -103,8 +103,14 @@
 		 * chips may hold it low ("clock stretching") while they
 		 * are processing data internally.
 		 */
-		if (time_after(jiffies, start + adap->timeout))
+		if (time_after(jiffies, start + adap->timeout)) {
+			/* Test one last time, as we may have been preempted
+			 * between last check and timeout test.
+			 */
+			if (getscl(adap))
+				break;
 			return -ETIMEDOUT;
+		}
 		cond_resched();
 	}
 #ifdef DEBUG
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 1e56061..e9c1893 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -1386,8 +1386,10 @@
 
 	ret = i2c_transfer(adap, &msg, 1);
 
-	/* If everything went ok (i.e. 1 msg transmitted), return #bytes
-	   transmitted, else error code. */
+	/*
+	 * If everything went ok (i.e. 1 msg transmitted), return #bytes
+	 * transmitted, else error code.
+	 */
 	return (ret == 1) ? count : ret;
 }
 EXPORT_SYMBOL(i2c_master_send);
@@ -1414,8 +1416,10 @@
 
 	ret = i2c_transfer(adap, &msg, 1);
 
-	/* If everything went ok (i.e. 1 msg transmitted), return #bytes
-	   transmitted, else error code. */
+	/*
+	 * If everything went ok (i.e. 1 msg received), return #bytes received,
+	 * else error code.
+	 */
 	return (ret == 1) ? count : ret;
 }
 EXPORT_SYMBOL(i2c_master_recv);
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 54ab97b..1c15e9b 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -62,6 +62,7 @@
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/module.h>
+#include <asm/cpu_device_id.h>
 #include <asm/mwait.h>
 #include <asm/msr.h>
 
@@ -81,6 +82,17 @@
 /* Reliable LAPIC Timer States, bit 1 for C1 etc.  */
 static unsigned int lapic_timer_reliable_states = (1 << 1);	 /* Default to only C1 */
 
+struct idle_cpu {
+	struct cpuidle_state *state_table;
+
+	/*
+	 * Hardware C-state auto-demotion may not always be optimal.
+	 * Indicate which enable bits to clear here.
+	 */
+	unsigned long auto_demotion_disable_flags;
+};
+
+static const struct idle_cpu *icpu;
 static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
 static int intel_idle(struct cpuidle_device *dev,
 			struct cpuidle_driver *drv, int index);
@@ -88,12 +100,6 @@
 static struct cpuidle_state *cpuidle_state_table;
 
 /*
- * Hardware C-state auto-demotion may not always be optimal.
- * Indicate which enable bits to clear here.
- */
-static unsigned long long auto_demotion_disable_flags;
-
-/*
  * Set this flag for states where the HW flushes the TLB for us
  * and so we don't need cross-calls to keep it consistent.
  * If this flag is set, SW flushes the TLB, so even if the
@@ -319,27 +325,68 @@
 	unsigned long long msr_bits;
 
 	rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
-	msr_bits &= ~auto_demotion_disable_flags;
+	msr_bits &= ~(icpu->auto_demotion_disable_flags);
 	wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
 }
 
+static const struct idle_cpu idle_cpu_nehalem = {
+	.state_table = nehalem_cstates,
+	.auto_demotion_disable_flags = NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE,
+};
+
+static const struct idle_cpu idle_cpu_atom = {
+	.state_table = atom_cstates,
+};
+
+static const struct idle_cpu idle_cpu_lincroft = {
+	.state_table = atom_cstates,
+	.auto_demotion_disable_flags = ATM_LNC_C6_AUTO_DEMOTE,
+};
+
+static const struct idle_cpu idle_cpu_snb = {
+	.state_table = snb_cstates,
+};
+
+#define ICPU(model, cpu) \
+	{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&cpu }
+
+static const struct x86_cpu_id intel_idle_ids[] = {
+	ICPU(0x1a, idle_cpu_nehalem),
+	ICPU(0x1e, idle_cpu_nehalem),
+	ICPU(0x1f, idle_cpu_nehalem),
+	ICPU(0x25, idle_cpu_nehalem),
+	ICPU(0x2c, idle_cpu_nehalem),
+	ICPU(0x2e, idle_cpu_nehalem),
+	ICPU(0x1c, idle_cpu_atom),
+	ICPU(0x26, idle_cpu_lincroft),
+	ICPU(0x2f, idle_cpu_nehalem),
+	ICPU(0x2a, idle_cpu_snb),
+	ICPU(0x2d, idle_cpu_snb),
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
+
 /*
  * intel_idle_probe()
  */
 static int intel_idle_probe(void)
 {
 	unsigned int eax, ebx, ecx;
+	const struct x86_cpu_id *id;
 
 	if (max_cstate == 0) {
 		pr_debug(PREFIX "disabled\n");
 		return -EPERM;
 	}
 
-	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+	id = x86_match_cpu(intel_idle_ids);
+	if (!id) {
+		if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+		    boot_cpu_data.x86 == 6)
+			pr_debug(PREFIX "does not run on family %d model %d\n",
+				boot_cpu_data.x86, boot_cpu_data.x86_model);
 		return -ENODEV;
-
-	if (!boot_cpu_has(X86_FEATURE_MWAIT))
-		return -ENODEV;
+	}
 
 	if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
 		return -ENODEV;
@@ -353,43 +400,8 @@
 
 	pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates);
 
-
-	if (boot_cpu_data.x86 != 6)	/* family 6 */
-		return -ENODEV;
-
-	switch (boot_cpu_data.x86_model) {
-
-	case 0x1A:	/* Core i7, Xeon 5500 series */
-	case 0x1E:	/* Core i7 and i5 Processor - Lynnfield Jasper Forest */
-	case 0x1F:	/* Core i7 and i5 Processor - Nehalem */
-	case 0x2E:	/* Nehalem-EX Xeon */
-	case 0x2F:	/* Westmere-EX Xeon */
-	case 0x25:	/* Westmere */
-	case 0x2C:	/* Westmere */
-		cpuidle_state_table = nehalem_cstates;
-		auto_demotion_disable_flags =
-			(NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE);
-		break;
-
-	case 0x1C:	/* 28 - Atom Processor */
-		cpuidle_state_table = atom_cstates;
-		break;
-
-	case 0x26:	/* 38 - Lincroft Atom Processor */
-		cpuidle_state_table = atom_cstates;
-		auto_demotion_disable_flags = ATM_LNC_C6_AUTO_DEMOTE;
-		break;
-
-	case 0x2A:	/* SNB */
-	case 0x2D:	/* SNB Xeon */
-		cpuidle_state_table = snb_cstates;
-		break;
-
-	default:
-		pr_debug(PREFIX "does not run on family %d model %d\n",
-			boot_cpu_data.x86, boot_cpu_data.x86_model);
-		return -ENODEV;
-	}
+	icpu = (const struct idle_cpu *)id->driver_data;
+	cpuidle_state_table = icpu->state_table;
 
 	if (boot_cpu_has(X86_FEATURE_ARAT))	/* Always Reliable APIC Timer */
 		lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE;
@@ -470,7 +482,7 @@
 		drv->state_count += 1;
 	}
 
-	if (auto_demotion_disable_flags)
+	if (icpu->auto_demotion_disable_flags)
 		on_each_cpu(auto_demotion_disable, NULL, 1);
 
 	return 0;
@@ -522,7 +534,7 @@
 		return -EIO;
 	}
 
-	if (auto_demotion_disable_flags)
+	if (icpu->auto_demotion_disable_flags)
 		smp_call_function_single(cpu, auto_demotion_disable, NULL, 1);
 
 	return 0;
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index c351aa4..da739d9 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -449,7 +449,6 @@
 	} else if ((drv = driver_find(buf, &gameport_bus)) != NULL) {
 		gameport_disconnect_port(gameport);
 		error = gameport_bind_driver(gameport, to_gameport_driver(drv));
-		put_driver(drv);
 	} else {
 		error = -EINVAL;
 	}
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index ba70058..d0f7533 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -441,7 +441,6 @@
 	} else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
 		serio_disconnect_port(serio);
 		error = serio_bind_driver(serio, to_serio_driver(drv));
-		put_driver(drv);
 		serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT);
 	} else {
 		error = -EINVAL;
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c9c6053..a08a534 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -48,8 +48,6 @@
 #define ROOT_SIZE		VTD_PAGE_SIZE
 #define CONTEXT_SIZE		VTD_PAGE_SIZE
 
-#define IS_BRIDGE_HOST_DEVICE(pdev) \
-			    ((pdev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
 #define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
 #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
 #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
@@ -356,10 +354,18 @@
 /* si_domain contains mulitple devices */
 #define DOMAIN_FLAG_STATIC_IDENTITY	(1 << 2)
 
+/* define the limit of IOMMUs supported in each domain */
+#ifdef	CONFIG_X86
+# define	IOMMU_UNITS_SUPPORTED	MAX_IO_APICS
+#else
+# define	IOMMU_UNITS_SUPPORTED	64
+#endif
+
 struct dmar_domain {
 	int	id;			/* domain id */
 	int	nid;			/* node id */
-	unsigned long iommu_bmp;	/* bitmap of iommus this domain uses*/
+	DECLARE_BITMAP(iommu_bmp, IOMMU_UNITS_SUPPORTED);
+					/* bitmap of iommus this domain uses*/
 
 	struct list_head devices; 	/* all devices' list */
 	struct iova_domain iovad;	/* iova's that belong to this domain */
@@ -571,7 +577,7 @@
 	BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
 	BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY);
 
-	iommu_id = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
+	iommu_id = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
 	if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
 		return NULL;
 
@@ -584,7 +590,7 @@
 
 	domain->iommu_coherency = 1;
 
-	for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
+	for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
 		if (!ecap_coherent(g_iommus[i]->ecap)) {
 			domain->iommu_coherency = 0;
 			break;
@@ -598,7 +604,7 @@
 
 	domain->iommu_snooping = 1;
 
-	for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
+	for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
 		if (!ecap_sc_support(g_iommus[i]->ecap)) {
 			domain->iommu_snooping = 0;
 			break;
@@ -1334,7 +1340,7 @@
 		return NULL;
 
 	domain->nid = -1;
-	memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
+	memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
 	domain->flags = 0;
 
 	return domain;
@@ -1360,7 +1366,7 @@
 
 	domain->id = num;
 	set_bit(num, iommu->domain_ids);
-	set_bit(iommu->seq_id, &domain->iommu_bmp);
+	set_bit(iommu->seq_id, domain->iommu_bmp);
 	iommu->domains[num] = domain;
 	spin_unlock_irqrestore(&iommu->lock, flags);
 
@@ -1385,7 +1391,7 @@
 
 	if (found) {
 		clear_bit(num, iommu->domain_ids);
-		clear_bit(iommu->seq_id, &domain->iommu_bmp);
+		clear_bit(iommu->seq_id, domain->iommu_bmp);
 		iommu->domains[num] = NULL;
 	}
 	spin_unlock_irqrestore(&iommu->lock, flags);
@@ -1527,7 +1533,7 @@
 	dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
 
 	for_each_active_iommu(iommu, drhd)
-		if (test_bit(iommu->seq_id, &domain->iommu_bmp))
+		if (test_bit(iommu->seq_id, domain->iommu_bmp))
 			iommu_detach_domain(domain, iommu);
 
 	free_domain_mem(domain);
@@ -1653,7 +1659,7 @@
 	spin_unlock_irqrestore(&iommu->lock, flags);
 
 	spin_lock_irqsave(&domain->iommu_lock, flags);
-	if (!test_and_set_bit(iommu->seq_id, &domain->iommu_bmp)) {
+	if (!test_and_set_bit(iommu->seq_id, domain->iommu_bmp)) {
 		domain->iommu_count++;
 		if (domain->iommu_count == 1)
 			domain->nid = iommu->node;
@@ -2369,18 +2375,18 @@
 		return -EFAULT;
 
 	for_each_pci_dev(pdev) {
-		/* Skip Host/PCI Bridge devices */
-		if (IS_BRIDGE_HOST_DEVICE(pdev))
-			continue;
 		if (iommu_should_identity_map(pdev, 1)) {
-			printk(KERN_INFO "IOMMU: %s identity mapping for device %s\n",
-			       hw ? "hardware" : "software", pci_name(pdev));
-
 			ret = domain_add_dev_info(si_domain, pdev,
-						     hw ? CONTEXT_TT_PASS_THROUGH :
-						     CONTEXT_TT_MULTI_LEVEL);
-			if (ret)
+					     hw ? CONTEXT_TT_PASS_THROUGH :
+						  CONTEXT_TT_MULTI_LEVEL);
+			if (ret) {
+				/* device not associated with an iommu */
+				if (ret == -ENODEV)
+					continue;
 				return ret;
+			}
+			pr_info("IOMMU: %s identity mapping for device %s\n",
+				hw ? "hardware" : "software", pci_name(pdev));
 		}
 	}
 
@@ -2402,12 +2408,17 @@
 	 * endfor
 	 */
 	for_each_drhd_unit(drhd) {
-		g_num_of_iommus++;
 		/*
 		 * lock not needed as this is only incremented in the single
 		 * threaded kernel __init code path all other access are read
 		 * only
 		 */
+		if (g_num_of_iommus < IOMMU_UNITS_SUPPORTED) {
+			g_num_of_iommus++;
+			continue;
+		}
+		printk_once(KERN_ERR "intel-iommu: exceeded %d IOMMUs\n",
+			  IOMMU_UNITS_SUPPORTED);
 	}
 
 	g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
@@ -3748,7 +3759,7 @@
 	if (found == 0) {
 		unsigned long tmp_flags;
 		spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
-		clear_bit(iommu->seq_id, &domain->iommu_bmp);
+		clear_bit(iommu->seq_id, domain->iommu_bmp);
 		domain->iommu_count--;
 		domain_update_iommu_cap(domain);
 		spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
@@ -3790,7 +3801,7 @@
 		 */
 		spin_lock_irqsave(&domain->iommu_lock, flags2);
 		if (test_and_clear_bit(iommu->seq_id,
-				       &domain->iommu_bmp)) {
+				       domain->iommu_bmp)) {
 			domain->iommu_count--;
 			domain_update_iommu_cap(domain);
 		}
@@ -3815,7 +3826,7 @@
 
 	domain->id = vm_domid++;
 	domain->nid = -1;
-	memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
+	memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
 	domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
 
 	return domain;
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index e44933d..3a7905b 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -1013,16 +1013,12 @@
 static int
 capinc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
 {
-	int idx = tty->index;
-	struct capiminor *mp = capiminor_get(idx);
-	int ret = tty_init_termios(tty);
+	struct capiminor *mp = capiminor_get(tty->index);
+	int ret = tty_standard_install(driver, tty);
 
-	if (ret == 0) {
-		tty_driver_kref_get(driver);
-		tty->count++;
+	if (ret == 0)
 		tty->driver_data = mp;
-		driver->ttys[idx] = tty;
-	} else
+	else
 		capiminor_put(mp);
 	return ret;
 }
@@ -1290,7 +1286,6 @@
 		kfree(capiminors);
 		return -ENOMEM;
 	}
-	drv->owner = THIS_MODULE;
 	drv->driver_name = "capi_nc";
 	drv->name = "capi";
 	drv->major = 0;
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index db621db..880f6ef 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -720,12 +720,11 @@
 
 	tasklet_init(&cs->event_tasklet, gigaset_handle_event,
 		     (unsigned long) cs);
+	tty_port_init(&cs->port);
 	cs->commands_pending = 0;
 	cs->cur_at_seq = 0;
 	cs->gotfwver = -1;
-	cs->open_count = 0;
 	cs->dev = NULL;
-	cs->tty = NULL;
 	cs->tty_dev = NULL;
 	cs->cidmode = cidmode != 0;
 	cs->tabnocid = gigaset_tab_nocid;
@@ -1051,8 +1050,6 @@
 
 struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty)
 {
-	if (tty->index < 0 || tty->index >= tty->driver->num)
-		return NULL;
 	return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start);
 }
 
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index 212efaf..f877726 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -433,8 +433,7 @@
 	spinlock_t cmdlock;
 	unsigned curlen, cmdbytes;
 
-	unsigned open_count;
-	struct tty_struct *tty;
+	struct tty_port port;
 	struct tasklet_struct if_wake_tasklet;
 	unsigned control_state;
 
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index ee0a549..8f8814a 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -146,13 +146,10 @@
 static int if_open(struct tty_struct *tty, struct file *filp)
 {
 	struct cardstate *cs;
-	unsigned long flags;
 
 	gig_dbg(DEBUG_IF, "%d+%d: %s()",
 		tty->driver->minor_start, tty->index, __func__);
 
-	tty->driver_data = NULL;
-
 	cs = gigaset_get_cs_by_tty(tty);
 	if (!cs || !try_module_get(cs->driver->owner))
 		return -ENODEV;
@@ -163,12 +160,10 @@
 	}
 	tty->driver_data = cs;
 
-	++cs->open_count;
+	++cs->port.count;
 
-	if (cs->open_count == 1) {
-		spin_lock_irqsave(&cs->lock, flags);
-		cs->tty = tty;
-		spin_unlock_irqrestore(&cs->lock, flags);
+	if (cs->port.count == 1) {
+		tty_port_tty_set(&cs->port, tty);
 		tty->low_latency = 1;
 	}
 
@@ -178,12 +173,10 @@
 
 static void if_close(struct tty_struct *tty, struct file *filp)
 {
-	struct cardstate *cs;
-	unsigned long flags;
+	struct cardstate *cs = tty->driver_data;
 
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
+	if (!cs) { /* happens if we didn't find cs in open */
+		printk(KERN_DEBUG "%s: no cardstate\n", __func__);
 		return;
 	}
 
@@ -193,15 +186,10 @@
 
 	if (!cs->connected)
 		gig_dbg(DEBUG_IF, "not connected");	/* nothing to do */
-	else if (!cs->open_count)
+	else if (!cs->port.count)
 		dev_warn(cs->dev, "%s: device not opened\n", __func__);
-	else {
-		if (!--cs->open_count) {
-			spin_lock_irqsave(&cs->lock, flags);
-			cs->tty = NULL;
-			spin_unlock_irqrestore(&cs->lock, flags);
-		}
-	}
+	else if (!--cs->port.count)
+		tty_port_tty_set(&cs->port, NULL);
 
 	mutex_unlock(&cs->mutex);
 
@@ -211,18 +199,12 @@
 static int if_ioctl(struct tty_struct *tty,
 		    unsigned int cmd, unsigned long arg)
 {
-	struct cardstate *cs;
+	struct cardstate *cs = tty->driver_data;
 	int retval = -ENODEV;
 	int int_arg;
 	unsigned char buf[6];
 	unsigned version[4];
 
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return -ENODEV;
-	}
-
 	gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd);
 
 	if (mutex_lock_interruptible(&cs->mutex))
@@ -231,9 +213,7 @@
 	if (!cs->connected) {
 		gig_dbg(DEBUG_IF, "not connected");
 		retval = -ENODEV;
-	} else if (!cs->open_count)
-		dev_warn(cs->dev, "%s: device not opened\n", __func__);
-	else {
+	} else {
 		retval = 0;
 		switch (cmd) {
 		case GIGASET_REDIR:
@@ -285,15 +265,9 @@
 
 static int if_tiocmget(struct tty_struct *tty)
 {
-	struct cardstate *cs;
+	struct cardstate *cs = tty->driver_data;
 	int retval;
 
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return -ENODEV;
-	}
-
 	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
 
 	if (mutex_lock_interruptible(&cs->mutex))
@@ -309,16 +283,10 @@
 static int if_tiocmset(struct tty_struct *tty,
 		       unsigned int set, unsigned int clear)
 {
-	struct cardstate *cs;
+	struct cardstate *cs = tty->driver_data;
 	int retval;
 	unsigned mc;
 
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return -ENODEV;
-	}
-
 	gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)",
 		cs->minor_index, __func__, set, clear);
 
@@ -341,16 +309,10 @@
 
 static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
-	struct cardstate *cs;
+	struct cardstate *cs = tty->driver_data;
 	struct cmdbuf_t *cb;
 	int retval;
 
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return -ENODEV;
-	}
-
 	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
 
 	if (mutex_lock_interruptible(&cs->mutex))
@@ -361,11 +323,6 @@
 		retval = -ENODEV;
 		goto done;
 	}
-	if (!cs->open_count) {
-		dev_warn(cs->dev, "%s: device not opened\n", __func__);
-		retval = -ENODEV;
-		goto done;
-	}
 	if (cs->mstate != MS_LOCKED) {
 		dev_warn(cs->dev, "can't write to unlocked device\n");
 		retval = -EBUSY;
@@ -397,15 +354,9 @@
 
 static int if_write_room(struct tty_struct *tty)
 {
-	struct cardstate *cs;
+	struct cardstate *cs = tty->driver_data;
 	int retval = -ENODEV;
 
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return -ENODEV;
-	}
-
 	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
 
 	if (mutex_lock_interruptible(&cs->mutex))
@@ -414,9 +365,7 @@
 	if (!cs->connected) {
 		gig_dbg(DEBUG_IF, "not connected");
 		retval = -ENODEV;
-	} else if (!cs->open_count)
-		dev_warn(cs->dev, "%s: device not opened\n", __func__);
-	else if (cs->mstate != MS_LOCKED) {
+	} else if (cs->mstate != MS_LOCKED) {
 		dev_warn(cs->dev, "can't write to unlocked device\n");
 		retval = -EBUSY;
 	} else
@@ -429,23 +378,15 @@
 
 static int if_chars_in_buffer(struct tty_struct *tty)
 {
-	struct cardstate *cs;
+	struct cardstate *cs = tty->driver_data;
 	int retval = 0;
 
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return 0;
-	}
-
 	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
 
 	mutex_lock(&cs->mutex);
 
 	if (!cs->connected)
 		gig_dbg(DEBUG_IF, "not connected");
-	else if (!cs->open_count)
-		dev_warn(cs->dev, "%s: device not opened\n", __func__);
 	else if (cs->mstate != MS_LOCKED)
 		dev_warn(cs->dev, "can't write to unlocked device\n");
 	else
@@ -458,13 +399,7 @@
 
 static void if_throttle(struct tty_struct *tty)
 {
-	struct cardstate *cs;
-
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return;
-	}
+	struct cardstate *cs = tty->driver_data;
 
 	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
 
@@ -472,8 +407,6 @@
 
 	if (!cs->connected)
 		gig_dbg(DEBUG_IF, "not connected");	/* nothing to do */
-	else if (!cs->open_count)
-		dev_warn(cs->dev, "%s: device not opened\n", __func__);
 	else
 		gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
 
@@ -482,13 +415,7 @@
 
 static void if_unthrottle(struct tty_struct *tty)
 {
-	struct cardstate *cs;
-
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return;
-	}
+	struct cardstate *cs = tty->driver_data;
 
 	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
 
@@ -496,8 +423,6 @@
 
 	if (!cs->connected)
 		gig_dbg(DEBUG_IF, "not connected");	/* nothing to do */
-	else if (!cs->open_count)
-		dev_warn(cs->dev, "%s: device not opened\n", __func__);
 	else
 		gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
 
@@ -506,18 +431,12 @@
 
 static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
 {
-	struct cardstate *cs;
+	struct cardstate *cs = tty->driver_data;
 	unsigned int iflag;
 	unsigned int cflag;
 	unsigned int old_cflag;
 	unsigned int control_state, new_state;
 
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return;
-	}
-
 	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
 
 	mutex_lock(&cs->mutex);
@@ -527,11 +446,6 @@
 		goto out;
 	}
 
-	if (!cs->open_count) {
-		dev_warn(cs->dev, "%s: device not opened\n", __func__);
-		goto out;
-	}
-
 	iflag = tty->termios->c_iflag;
 	cflag = tty->termios->c_cflag;
 	old_cflag = old ? old->c_cflag : cflag;
@@ -588,10 +502,13 @@
 /* wakeup tasklet for the write operation */
 static void if_wake(unsigned long data)
 {
-	struct cardstate *cs = (struct cardstate *) data;
+	struct cardstate *cs = (struct cardstate *)data;
+	struct tty_struct *tty = tty_port_tty_get(&cs->port);
 
-	if (cs->tty)
-		tty_wakeup(cs->tty);
+	if (tty) {
+		tty_wakeup(tty);
+		tty_kref_put(tty);
+	}
 }
 
 /*** interface to common ***/
@@ -644,18 +561,16 @@
 void gigaset_if_receive(struct cardstate *cs,
 			unsigned char *buffer, size_t len)
 {
-	unsigned long flags;
-	struct tty_struct *tty;
+	struct tty_struct *tty = tty_port_tty_get(&cs->port);
 
-	spin_lock_irqsave(&cs->lock, flags);
-	tty = cs->tty;
-	if (tty == NULL)
+	if (tty == NULL) {
 		gig_dbg(DEBUG_IF, "receive on closed device");
-	else {
-		tty_insert_flip_string(tty, buffer, len);
-		tty_flip_buffer_push(tty);
+		return;
 	}
-	spin_unlock_irqrestore(&cs->lock, flags);
+
+	tty_insert_flip_string(tty, buffer, len);
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
 }
 EXPORT_SYMBOL_GPL(gigaset_if_receive);
 
@@ -669,17 +584,15 @@
 void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
 			   const char *devname)
 {
-	unsigned minors = drv->minors;
 	int ret;
 	struct tty_driver *tty;
 
 	drv->have_tty = 0;
 
-	drv->tty = tty = alloc_tty_driver(minors);
+	drv->tty = tty = alloc_tty_driver(drv->minors);
 	if (tty == NULL)
 		goto enomem;
 
-	tty->magic =		TTY_DRIVER_MAGIC,
 	tty->type =		TTY_DRIVER_TYPE_SERIAL,
 	tty->subtype =		SERIAL_TYPE_NORMAL,
 	tty->flags =		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
@@ -687,9 +600,6 @@
 	tty->driver_name =	procname;
 	tty->name =		devname;
 	tty->minor_start =	drv->minor;
-	tty->num =		drv->minors;
-
-	tty->owner =		THIS_MODULE;
 
 	tty->init_termios          = tty_std_termios;
 	tty->init_termios.c_cflag  = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 2c26b64..ac48401 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1590,12 +1590,9 @@
 isdn_tty_open(struct tty_struct *tty, struct file *filp)
 {
 	modem_info *info;
-	int retval, line;
+	int retval;
 
-	line = tty->index;
-	if (line < 0 || line >= ISDN_MAX_CHANNELS)
-		return -ENODEV;
-	info = &dev->mdm.info[line];
+	info = &dev->mdm.info[tty->index];
 	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
 		return -ENODEV;
 	if (!try_module_get(info->owner)) {
diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c
index 654685c..aa77e54 100644
--- a/drivers/media/dvb/siano/smsdvb.c
+++ b/drivers/media/dvb/siano/smsdvb.c
@@ -49,9 +49,6 @@
 
 	struct completion       tune_done;
 
-	/* todo: save freq/band instead whole struct */
-	struct dtv_frontend_properties fe_params;
-
 	struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
 	int event_fe_state;
 	int event_unc_state;
@@ -744,12 +741,124 @@
 	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
 	struct smsdvb_client_t *client =
 		container_of(fe, struct smsdvb_client_t, frontend);
+	struct smscore_device_t *coredev = client->coredev;
+	struct TRANSMISSION_STATISTICS_S *td =
+		&client->sms_stat_dvb.TransmissionData;
 
-	sms_debug("");
+	switch (smscore_get_device_mode(coredev)) {
+	case DEVICE_MODE_DVBT:
+	case DEVICE_MODE_DVBT_BDA:
+		fep->frequency = td->Frequency;
 
-	/* todo: */
-	memcpy(fep, &client->fe_params,
-	       sizeof(struct dtv_frontend_properties));
+		switch (td->Bandwidth) {
+		case 6:
+			fep->bandwidth_hz = 6000000;
+			break;
+		case 7:
+			fep->bandwidth_hz = 7000000;
+			break;
+		case 8:
+			fep->bandwidth_hz = 8000000;
+			break;
+		}
+
+		switch (td->TransmissionMode) {
+		case 2:
+			fep->transmission_mode = TRANSMISSION_MODE_2K;
+			break;
+		case 8:
+			fep->transmission_mode = TRANSMISSION_MODE_8K;
+		}
+
+		switch (td->GuardInterval) {
+		case 0:
+			fep->guard_interval = GUARD_INTERVAL_1_32;
+			break;
+		case 1:
+			fep->guard_interval = GUARD_INTERVAL_1_16;
+			break;
+		case 2:
+			fep->guard_interval = GUARD_INTERVAL_1_8;
+			break;
+		case 3:
+			fep->guard_interval = GUARD_INTERVAL_1_4;
+			break;
+		}
+
+		switch (td->CodeRate) {
+		case 0:
+			fep->code_rate_HP = FEC_1_2;
+			break;
+		case 1:
+			fep->code_rate_HP = FEC_2_3;
+			break;
+		case 2:
+			fep->code_rate_HP = FEC_3_4;
+			break;
+		case 3:
+			fep->code_rate_HP = FEC_5_6;
+			break;
+		case 4:
+			fep->code_rate_HP = FEC_7_8;
+			break;
+		}
+
+		switch (td->LPCodeRate) {
+		case 0:
+			fep->code_rate_LP = FEC_1_2;
+			break;
+		case 1:
+			fep->code_rate_LP = FEC_2_3;
+			break;
+		case 2:
+			fep->code_rate_LP = FEC_3_4;
+			break;
+		case 3:
+			fep->code_rate_LP = FEC_5_6;
+			break;
+		case 4:
+			fep->code_rate_LP = FEC_7_8;
+			break;
+		}
+
+		switch (td->Constellation) {
+		case 0:
+			fep->modulation = QPSK;
+			break;
+		case 1:
+			fep->modulation = QAM_16;
+			break;
+		case 2:
+			fep->modulation = QAM_64;
+			break;
+		}
+
+		switch (td->Hierarchy) {
+		case 0:
+			fep->hierarchy = HIERARCHY_NONE;
+			break;
+		case 1:
+			fep->hierarchy = HIERARCHY_1;
+			break;
+		case 2:
+			fep->hierarchy = HIERARCHY_2;
+			break;
+		case 3:
+			fep->hierarchy = HIERARCHY_4;
+			break;
+		}
+
+		fep->inversion = INVERSION_AUTO;
+		break;
+	case DEVICE_MODE_ISDBT:
+	case DEVICE_MODE_ISDBT_BDA:
+		fep->frequency = td->Frequency;
+		fep->bandwidth_hz = 6000000;
+		/* todo: retrive the other parameters */
+		break;
+	default:
+		return -EINVAL;
+	}
 
 	return 0;
 }
@@ -872,11 +981,11 @@
 	switch (smscore_get_device_mode(coredev)) {
 	case DEVICE_MODE_DVBT:
 	case DEVICE_MODE_DVBT_BDA:
-		smsdvb_fe_ops.delsys[0] = SYS_DVBT;
+		client->frontend.ops.delsys[0] = SYS_DVBT;
 		break;
 	case DEVICE_MODE_ISDBT:
 	case DEVICE_MODE_ISDBT_BDA:
-		smsdvb_fe_ops.delsys[0] = SYS_ISDBT;
+		client->frontend.ops.delsys[0] = SYS_ISDBT;
 		break;
 	}
 
diff --git a/drivers/media/video/cx18/cx18-alsa-main.c b/drivers/media/video/cx18/cx18-alsa-main.c
index a1e6c2a..e118361 100644
--- a/drivers/media/video/cx18/cx18-alsa-main.c
+++ b/drivers/media/video/cx18/cx18-alsa-main.c
@@ -285,7 +285,6 @@
 
 	drv = driver_find("cx18", &pci_bus_type);
 	ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback);
-	put_driver(drv);
 
 	cx18_ext_init = NULL;
 	printk(KERN_INFO "cx18-alsa: module unload complete\n");
diff --git a/drivers/media/video/davinci/isif.c b/drivers/media/video/davinci/isif.c
index 1e63852..5278fe7 100644
--- a/drivers/media/video/davinci/isif.c
+++ b/drivers/media/video/davinci/isif.c
@@ -34,6 +34,7 @@
 #include <linux/videodev2.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/module.h>
 
 #include <mach/mux.h>
 
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index d0fbfcf..e5e7fa9 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -1293,7 +1293,6 @@
 
 	drv = driver_find("ivtv", &pci_bus_type);
 	err = driver_for_each_device(drv, NULL, &registered, ivtvfb_callback_init);
-	put_driver(drv);
 	if (!registered) {
 		printk(KERN_ERR "ivtvfb:  no cards found\n");
 		return -ENODEV;
@@ -1310,7 +1309,6 @@
 
 	drv = driver_find("ivtv", &pci_bus_type);
 	err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
-	put_driver(drv);
 }
 
 module_init(ivtvfb_init);
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c
index 8ea4ee1..63eccb5 100644
--- a/drivers/media/video/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c
@@ -344,16 +344,13 @@
 		return -ENODEV;
 	ret = driver_for_each_device(driver, NULL, fmd,
 				     fimc_register_callback);
-	put_driver(driver);
 	if (ret)
 		return ret;
 
 	driver = driver_find(CSIS_DRIVER_NAME, &platform_bus_type);
-	if (driver) {
+	if (driver)
 		ret = driver_for_each_device(driver, NULL, fmd,
 					     csis_register_callback);
-		put_driver(driver);
-	}
 	return ret;
 }
 
diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c
index 7884bae..f7ca5cc 100644
--- a/drivers/media/video/s5p-tv/mixer_video.c
+++ b/drivers/media/video/s5p-tv/mixer_video.c
@@ -58,7 +58,6 @@
 	}
 
 done:
-	put_driver(drv);
 	return sd;
 }
 
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index c7e69b8..4a44f9a 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -611,9 +611,11 @@
 	delta_stc = buf->pts - (1UL << 31);
 	x1 = first->dev_stc - delta_stc;
 	x2 = last->dev_stc - delta_stc;
+	if (x1 == x2)
+		goto done;
+
 	y1 = (first->dev_sof + 2048) << 16;
 	y2 = (last->dev_sof + 2048) << 16;
-
 	if (y2 < y1)
 		y2 += 2048 << 16;
 
@@ -631,14 +633,16 @@
 		  x1, x2, y1, y2, clock->sof_offset);
 
 	/* Second step, SOF to host clock conversion. */
-	ts = timespec_sub(last->host_ts, first->host_ts);
 	x1 = (uvc_video_clock_host_sof(first) + 2048) << 16;
 	x2 = (uvc_video_clock_host_sof(last) + 2048) << 16;
-	y1 = NSEC_PER_SEC;
-	y2 = (ts.tv_sec + 1) * NSEC_PER_SEC + ts.tv_nsec;
-
 	if (x2 < x1)
 		x2 += 2048 << 16;
+	if (x1 == x2)
+		goto done;
+
+	ts = timespec_sub(last->host_ts, first->host_ts);
+	y1 = NSEC_PER_SEC;
+	y2 = (ts.tv_sec + 1) * NSEC_PER_SEC + ts.tv_nsec;
 
 	/* Interpolated and host SOF timestamps can wrap around at slightly
 	 * different times. Handle this by adding or removing 2048 to or from
diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c
index 83adab6..8208262 100644
--- a/drivers/misc/ad525x_dpot-i2c.c
+++ b/drivers/misc/ad525x_dpot-i2c.c
@@ -113,17 +113,7 @@
 	.id_table	= ad_dpot_id,
 };
 
-static int __init ad_dpot_i2c_init(void)
-{
-	return i2c_add_driver(&ad_dpot_i2c_driver);
-}
-module_init(ad_dpot_i2c_init);
-
-static void __exit ad_dpot_i2c_exit(void)
-{
-	i2c_del_driver(&ad_dpot_i2c_driver);
-}
-module_exit(ad_dpot_i2c_exit);
+module_i2c_driver(ad_dpot_i2c_driver);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("digital potentiometer I2C bus driver");
diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c
index 822749e..f623175 100644
--- a/drivers/misc/ad525x_dpot-spi.c
+++ b/drivers/misc/ad525x_dpot-spi.c
@@ -135,17 +135,7 @@
 	.id_table	= ad_dpot_spi_id,
 };
 
-static int __init ad_dpot_spi_init(void)
-{
-	return spi_register_driver(&ad_dpot_spi_driver);
-}
-module_init(ad_dpot_spi_init);
-
-static void __exit ad_dpot_spi_exit(void)
-{
-	spi_unregister_driver(&ad_dpot_spi_driver);
-}
-module_exit(ad_dpot_spi_exit);
+module_spi_driver(ad_dpot_spi_driver);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("digital potentiometer SPI bus driver");
diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c
index 81db781..0314773 100644
--- a/drivers/misc/apds9802als.c
+++ b/drivers/misc/apds9802als.c
@@ -332,17 +332,7 @@
 	.id_table = apds9802als_id,
 };
 
-static int __init sensor_apds9802als_init(void)
-{
-	return i2c_add_driver(&apds9802als_driver);
-}
-
-static void  __exit sensor_apds9802als_exit(void)
-{
-	i2c_del_driver(&apds9802als_driver);
-}
-module_init(sensor_apds9802als_init);
-module_exit(sensor_apds9802als_exit);
+module_i2c_driver(apds9802als_driver);
 
 MODULE_AUTHOR("Anantha Narayanan <Anantha.Narayanan@intel.com");
 MODULE_DESCRIPTION("Avago apds9802als ALS Driver");
diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c
index e2a52e5..ee74244 100644
--- a/drivers/misc/apds990x.c
+++ b/drivers/misc/apds990x.c
@@ -1279,19 +1279,8 @@
 	.id_table = apds990x_id,
 };
 
-static int __init apds990x_init(void)
-{
-	return i2c_add_driver(&apds990x_driver);
-}
-
-static void __exit apds990x_exit(void)
-{
-	i2c_del_driver(&apds990x_driver);
-}
+module_i2c_driver(apds990x_driver);
 
 MODULE_DESCRIPTION("APDS990X combined ALS and proximity sensor");
 MODULE_AUTHOR("Samu Onkalo, Nokia Corporation");
 MODULE_LICENSE("GPL v2");
-
-module_init(apds990x_init);
-module_exit(apds990x_exit);
diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c
index d79a972..3d56ae7 100644
--- a/drivers/misc/bh1770glc.c
+++ b/drivers/misc/bh1770glc.c
@@ -1399,19 +1399,8 @@
 	.id_table = bh1770_id,
 };
 
-static int __init bh1770_init(void)
-{
-	return i2c_add_driver(&bh1770_driver);
-}
-
-static void __exit bh1770_exit(void)
-{
-	i2c_del_driver(&bh1770_driver);
-}
+module_i2c_driver(bh1770_driver);
 
 MODULE_DESCRIPTION("BH1770GLC / SFH7770 combined ALS and proximity sensor");
 MODULE_AUTHOR("Samu Onkalo, Nokia Corporation");
 MODULE_LICENSE("GPL v2");
-
-module_init(bh1770_init);
-module_exit(bh1770_exit);
diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c
index bfeea9b..54f6f39 100644
--- a/drivers/misc/bh1780gli.c
+++ b/drivers/misc/bh1780gli.c
@@ -253,21 +253,10 @@
 	.driver = {
 		.name = "bh1780",
 		.pm	= BH1780_PMOPS,
-},
+	},
 };
 
-static int __init bh1780_init(void)
-{
-	return i2c_add_driver(&bh1780_driver);
-}
-
-static void __exit bh1780_exit(void)
-{
-	i2c_del_driver(&bh1780_driver);
-}
-
-module_init(bh1780_init)
-module_exit(bh1780_exit)
+module_i2c_driver(bh1780_driver);
 
 MODULE_DESCRIPTION("BH1780GLI Ambient Light Sensor Driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c
index b29a2be..76c3064 100644
--- a/drivers/misc/bmp085.c
+++ b/drivers/misc/bmp085.c
@@ -87,7 +87,7 @@
 	u32 raw_temperature;
 	u32 raw_pressure;
 	unsigned char oversampling_setting;
-	u32 last_temp_measurement;
+	unsigned long last_temp_measurement;
 	s32 b6; /* calculated temperature correction coefficient */
 };
 
@@ -234,7 +234,8 @@
 	int status;
 
 	/* alt least every second force an update of the ambient temperature */
-	if (data->last_temp_measurement + 1*HZ < jiffies) {
+	if (data->last_temp_measurement == 0 ||
+			time_is_before_jiffies(data->last_temp_measurement + 1*HZ)) {
 		status = bmp085_get_temperature(data, NULL);
 		if (status != 0)
 			goto exit;
@@ -464,20 +465,8 @@
 	.address_list	= normal_i2c
 };
 
-static int __init bmp085_init(void)
-{
-	return i2c_add_driver(&bmp085_driver);
-}
-
-static void __exit bmp085_exit(void)
-{
-	i2c_del_driver(&bmp085_driver);
-}
-
+module_i2c_driver(bmp085_driver);
 
 MODULE_AUTHOR("Christoph Mair <christoph.mair@gmail.com");
 MODULE_DESCRIPTION("BMP085 driver");
 MODULE_LICENSE("GPL");
-
-module_init(bmp085_init);
-module_exit(bmp085_exit);
diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c
index 14e974b2..366bc15 100644
--- a/drivers/misc/carma/carma-fpga.c
+++ b/drivers/misc/carma/carma-fpga.c
@@ -1410,23 +1410,8 @@
 	},
 };
 
-/*
- * Module Init / Exit
- */
-
-static int __init data_init(void)
-{
-	return platform_driver_register(&data_of_driver);
-}
-
-static void __exit data_exit(void)
-{
-	platform_driver_unregister(&data_of_driver);
-}
+module_platform_driver(data_of_driver);
 
 MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
 MODULE_DESCRIPTION("CARMA DATA-FPGA Access Driver");
 MODULE_LICENSE("GPL");
-
-module_init(data_init);
-module_exit(data_exit);
diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c
index 87a390d..f505a40 100644
--- a/drivers/misc/cs5535-mfgpt.c
+++ b/drivers/misc/cs5535-mfgpt.c
@@ -246,7 +246,7 @@
  * Jordan tells me that he and Mitch once played w/ it, but it's unclear
  * what the results of that were (and they experienced some instability).
  */
-static void __init reset_all_timers(void)
+static void __devinit reset_all_timers(void)
 {
 	uint32_t val, dummy;
 
diff --git a/drivers/misc/ds1682.c b/drivers/misc/ds1682.c
index a513f0a..154b02e 100644
--- a/drivers/misc/ds1682.c
+++ b/drivers/misc/ds1682.c
@@ -250,19 +250,8 @@
 	.id_table = ds1682_id,
 };
 
-static int __init ds1682_init(void)
-{
-	return i2c_add_driver(&ds1682_driver);
-}
-
-static void __exit ds1682_exit(void)
-{
-	i2c_del_driver(&ds1682_driver);
-}
+module_i2c_driver(ds1682_driver);
 
 MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
 MODULE_DESCRIPTION("DS1682 Elapsed Time Indicator driver");
 MODULE_LICENSE("GPL");
-
-module_init(ds1682_init);
-module_exit(ds1682_exit);
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index c627e41..01ab3c9 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -405,17 +405,7 @@
 	.remove		= __devexit_p(at25_remove),
 };
 
-static int __init at25_init(void)
-{
-	return spi_register_driver(&at25_driver);
-}
-module_init(at25_init);
-
-static void __exit at25_exit(void)
-{
-	spi_unregister_driver(&at25_driver);
-}
-module_exit(at25_exit);
+module_spi_driver(at25_driver);
 
 MODULE_DESCRIPTION("Driver for most SPI EEPROMs");
 MODULE_AUTHOR("David Brownell");
diff --git a/drivers/misc/eeprom/eeprom.c b/drivers/misc/eeprom/eeprom.c
index 45060dd..c169e07 100644
--- a/drivers/misc/eeprom/eeprom.c
+++ b/drivers/misc/eeprom/eeprom.c
@@ -229,22 +229,10 @@
 	.address_list	= normal_i2c,
 };
 
-static int __init eeprom_init(void)
-{
-	return i2c_add_driver(&eeprom_driver);
-}
-
-static void __exit eeprom_exit(void)
-{
-	i2c_del_driver(&eeprom_driver);
-}
-
+module_i2c_driver(eeprom_driver);
 
 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
 		"Philip Edelbrock <phil@netroedge.com> and "
 		"Greg Kroah-Hartman <greg@kroah.com>");
 MODULE_DESCRIPTION("I2C EEPROM driver");
 MODULE_LICENSE("GPL");
-
-module_init(eeprom_init);
-module_exit(eeprom_exit);
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
index 0c7ebb1..ce3fe36 100644
--- a/drivers/misc/eeprom/eeprom_93xx46.c
+++ b/drivers/misc/eeprom/eeprom_93xx46.c
@@ -392,17 +392,7 @@
 	.remove		= __devexit_p(eeprom_93xx46_remove),
 };
 
-static int __init eeprom_93xx46_init(void)
-{
-	return spi_register_driver(&eeprom_93xx46_driver);
-}
-module_init(eeprom_93xx46_init);
-
-static void __exit eeprom_93xx46_exit(void)
-{
-	spi_unregister_driver(&eeprom_93xx46_driver);
-}
-module_exit(eeprom_93xx46_exit);
+module_spi_driver(eeprom_93xx46_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Driver for 93xx46 EEPROMs");
diff --git a/drivers/misc/eeprom/max6875.c b/drivers/misc/eeprom/max6875.c
index 5653a3c..e36157d 100644
--- a/drivers/misc/eeprom/max6875.c
+++ b/drivers/misc/eeprom/max6875.c
@@ -208,20 +208,8 @@
 	.id_table	= max6875_id,
 };
 
-static int __init max6875_init(void)
-{
-	return i2c_add_driver(&max6875_driver);
-}
-
-static void __exit max6875_exit(void)
-{
-	i2c_del_driver(&max6875_driver);
-}
-
+module_i2c_driver(max6875_driver);
 
 MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
 MODULE_DESCRIPTION("MAX6875 driver");
 MODULE_LICENSE("GPL");
-
-module_init(max6875_init);
-module_exit(max6875_exit);
diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c
index f6586d5..ac96c3a 100644
--- a/drivers/misc/fsa9480.c
+++ b/drivers/misc/fsa9480.c
@@ -458,7 +458,6 @@
 	if (client->irq)
 		free_irq(client->irq, usbsw);
 fail1:
-	i2c_set_clientdata(client, NULL);
 	kfree(usbsw);
 	return ret;
 }
@@ -468,7 +467,6 @@
 	struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
 	if (client->irq)
 		free_irq(client->irq, usbsw);
-	i2c_set_clientdata(client, NULL);
 
 	sysfs_remove_group(&client->dev.kobj, &fsa9480_group);
 	device_init_wakeup(&client->dev, 0);
@@ -541,17 +539,7 @@
 	.id_table = fsa9480_id,
 };
 
-static int __init fsa9480_init(void)
-{
-	return i2c_add_driver(&fsa9480_i2c_driver);
-}
-module_init(fsa9480_init);
-
-static void __exit fsa9480_exit(void)
-{
-	i2c_del_driver(&fsa9480_i2c_driver);
-}
-module_exit(fsa9480_exit);
+module_i2c_driver(fsa9480_i2c_driver);
 
 MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>");
 MODULE_DESCRIPTION("FSA9480 USB Switch driver");
diff --git a/drivers/misc/hmc6352.c b/drivers/misc/hmc6352.c
index ca938fc..423cd40 100644
--- a/drivers/misc/hmc6352.c
+++ b/drivers/misc/hmc6352.c
@@ -148,18 +148,7 @@
 	.id_table = hmc6352_id,
 };
 
-static int __init sensor_hmc6352_init(void)
-{
-	return i2c_add_driver(&hmc6352_driver);
-}
-
-static void  __exit sensor_hmc6352_exit(void)
-{
-	i2c_del_driver(&hmc6352_driver);
-}
-
-module_init(sensor_hmc6352_init);
-module_exit(sensor_hmc6352_exit);
+module_i2c_driver(hmc6352_driver);
 
 MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com");
 MODULE_DESCRIPTION("hmc6352 Compass Driver");
diff --git a/drivers/misc/ics932s401.c b/drivers/misc/ics932s401.c
index 152e9d9..0029536 100644
--- a/drivers/misc/ics932s401.c
+++ b/drivers/misc/ics932s401.c
@@ -480,23 +480,12 @@
 	return 0;
 }
 
-static int __init ics932s401_init(void)
-{
-	return i2c_add_driver(&ics932s401_driver);
-}
-
-static void __exit ics932s401_exit(void)
-{
-	i2c_del_driver(&ics932s401_driver);
-}
+module_i2c_driver(ics932s401_driver);
 
 MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
 MODULE_DESCRIPTION("ICS932S401 driver");
 MODULE_LICENSE("GPL");
 
-module_init(ics932s401_init);
-module_exit(ics932s401_exit);
-
 /* IBM IntelliStation Z30 */
 MODULE_ALIAS("dmi:bvnIBM:*:rn9228:*");
 MODULE_ALIAS("dmi:bvnIBM:*:rn9232:*");
diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c
index a71e245..eb5de2e 100644
--- a/drivers/misc/isl29003.c
+++ b/drivers/misc/isl29003.c
@@ -455,21 +455,9 @@
 	.id_table = isl29003_id,
 };
 
-static int __init isl29003_init(void)
-{
-	return i2c_add_driver(&isl29003_driver);
-}
-
-static void __exit isl29003_exit(void)
-{
-	i2c_del_driver(&isl29003_driver);
-}
+module_i2c_driver(isl29003_driver);
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
 MODULE_DESCRIPTION("ISL29003 ambient light sensor driver");
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION(DRIVER_VERSION);
-
-module_init(isl29003_init);
-module_exit(isl29003_exit);
-
diff --git a/drivers/misc/isl29020.c b/drivers/misc/isl29020.c
index 3d6cce6..0aa08c7 100644
--- a/drivers/misc/isl29020.c
+++ b/drivers/misc/isl29020.c
@@ -230,18 +230,7 @@
 	.id_table = isl29020_id,
 };
 
-static int __init sensor_isl29020_init(void)
-{
-	return i2c_add_driver(&isl29020_driver);
-}
-
-static void  __exit sensor_isl29020_exit(void)
-{
-	i2c_del_driver(&isl29020_driver);
-}
-
-module_init(sensor_isl29020_init);
-module_exit(sensor_isl29020_exit);
+module_i2c_driver(isl29020_driver);
 
 MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com>");
 MODULE_DESCRIPTION("Intersil isl29020 ALS Driver");
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
index c02fea0..e8c0019 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
@@ -256,19 +256,8 @@
 	.id_table = lis3lv02d_id,
 };
 
-static int __init lis3lv02d_init(void)
-{
-	return i2c_add_driver(&lis3lv02d_i2c_driver);
-}
-
-static void __exit lis3lv02d_exit(void)
-{
-	i2c_del_driver(&lis3lv02d_i2c_driver);
-}
+module_i2c_driver(lis3lv02d_i2c_driver);
 
 MODULE_AUTHOR("Nokia Corporation");
 MODULE_DESCRIPTION("lis3lv02d I2C interface");
 MODULE_LICENSE("GPL");
-
-module_init(lis3lv02d_init);
-module_exit(lis3lv02d_exit);
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c
index b2c1be1..80880e9 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_spi.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_spi.c
@@ -126,18 +126,7 @@
 	.remove	= __devexit_p(lis302dl_spi_remove),
 };
 
-static int __init lis302dl_init(void)
-{
-	return spi_register_driver(&lis302dl_spi_driver);
-}
-
-static void __exit lis302dl_exit(void)
-{
-	spi_unregister_driver(&lis302dl_spi_driver);
-}
-
-module_init(lis302dl_init);
-module_exit(lis302dl_exit);
+module_spi_driver(lis302dl_spi_driver);
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
 MODULE_DESCRIPTION("lis3lv02d SPI glue layer");
diff --git a/drivers/misc/max8997-muic.c b/drivers/misc/max8997-muic.c
index d74ef41..19591ea 100644
--- a/drivers/misc/max8997-muic.c
+++ b/drivers/misc/max8997-muic.c
@@ -488,17 +488,7 @@
 	.remove		= __devexit_p(max8997_muic_remove),
 };
 
-static int __init max8997_muic_init(void)
-{
-	return platform_driver_register(&max8997_muic_driver);
-}
-module_init(max8997_muic_init);
-
-static void __exit max8997_muic_exit(void)
-{
-	platform_driver_unregister(&max8997_muic_driver);
-}
-module_exit(max8997_muic_exit);
+module_platform_driver(max8997_muic_driver);
 
 MODULE_DESCRIPTION("Maxim MAX8997 MUIC driver");
 MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index 0b56e3f..383133b 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -481,13 +481,9 @@
 {
 	int idx = tty->index;
 	struct pti_tty *pti_tty_data;
-	int ret = tty_init_termios(tty);
+	int ret = tty_standard_install(driver, tty);
 
 	if (ret == 0) {
-		tty_driver_kref_get(driver);
-		tty->count++;
-		driver->ttys[idx] = tty;
-
 		pti_tty_data = kmalloc(sizeof(struct pti_tty), GFP_KERNEL);
 		if (pti_tty_data == NULL)
 			return -ENOMEM;
@@ -911,21 +907,17 @@
 
 	/* First register module as tty device */
 
-	pti_tty_driver = alloc_tty_driver(1);
+	pti_tty_driver = alloc_tty_driver(PTITTY_MINOR_NUM);
 	if (pti_tty_driver == NULL) {
 		pr_err("%s(%d): Memory allocation failed for ptiTTY driver\n",
 			__func__, __LINE__);
 		return -ENOMEM;
 	}
 
-	pti_tty_driver->owner			= THIS_MODULE;
-	pti_tty_driver->magic			= TTY_DRIVER_MAGIC;
 	pti_tty_driver->driver_name		= DRIVERNAME;
 	pti_tty_driver->name			= TTYNAME;
 	pti_tty_driver->major			= 0;
 	pti_tty_driver->minor_start		= PTITTY_MINOR_START;
-	pti_tty_driver->minor_num		= PTITTY_MINOR_NUM;
-	pti_tty_driver->num			= PTITTY_MINOR_NUM;
 	pti_tty_driver->type			= TTY_DRIVER_TYPE_SYSTEM;
 	pti_tty_driver->subtype			= SYSTEM_TYPE_SYSCONS;
 	pti_tty_driver->flags			= TTY_DRIVER_REAL_RAW |
diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c
index 43d073b..123ed98 100644
--- a/drivers/misc/spear13xx_pcie_gadget.c
+++ b/drivers/misc/spear13xx_pcie_gadget.c
@@ -891,17 +891,7 @@
 	},
 };
 
-static int __init spear_pcie_gadget_init(void)
-{
-	return platform_driver_register(&spear_pcie_gadget_driver);
-}
-module_init(spear_pcie_gadget_init);
-
-static void __exit spear_pcie_gadget_exit(void)
-{
-	platform_driver_unregister(&spear_pcie_gadget_driver);
-}
-module_exit(spear_pcie_gadget_exit);
+module_platform_driver(spear_pcie_gadget_driver);
 
 MODULE_ALIAS("platform:pcie-gadget-spear");
 MODULE_AUTHOR("Pratyush Anand");
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c
index a7a861c..7c14f8f 100644
--- a/drivers/misc/ti-st/st_kim.c
+++ b/drivers/misc/ti-st/st_kim.c
@@ -837,19 +837,8 @@
 	},
 };
 
-static int __init st_kim_init(void)
-{
-	return platform_driver_register(&kim_platform_driver);
-}
+module_platform_driver(kim_platform_driver);
 
-static void __exit st_kim_deinit(void)
-{
-	platform_driver_unregister(&kim_platform_driver);
-}
-
-
-module_init(st_kim_init);
-module_exit(st_kim_deinit);
 MODULE_AUTHOR("Pavan Savoy <pavan_savoy@ti.com>");
 MODULE_DESCRIPTION("Shared Transport Driver for TI BT/FM/GPS combo chips ");
 MODULE_LICENSE("GPL");
diff --git a/drivers/misc/ti_dac7512.c b/drivers/misc/ti_dac7512.c
index d3f229a..5acbba1 100644
--- a/drivers/misc/ti_dac7512.c
+++ b/drivers/misc/ti_dac7512.c
@@ -82,20 +82,9 @@
 	.remove	= __devexit_p(dac7512_remove),
 };
 
-static int __init dac7512_init(void)
-{
-	return spi_register_driver(&dac7512_driver);
-}
-
-static void __exit dac7512_exit(void)
-{
-	spi_unregister_driver(&dac7512_driver);
-}
+module_spi_driver(dac7512_driver);
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
 MODULE_DESCRIPTION("DAC7512 16-bit DAC");
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION(DRIVER_VERSION);
-
-module_init(dac7512_init);
-module_exit(dac7512_exit);
diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c
index 483ae5f..0beb298 100644
--- a/drivers/misc/tsl2550.c
+++ b/drivers/misc/tsl2550.c
@@ -454,20 +454,9 @@
 	.id_table = tsl2550_id,
 };
 
-static int __init tsl2550_init(void)
-{
-	return i2c_add_driver(&tsl2550_driver);
-}
-
-static void __exit tsl2550_exit(void)
-{
-	i2c_del_driver(&tsl2550_driver);
-}
+module_i2c_driver(tsl2550_driver);
 
 MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
 MODULE_DESCRIPTION("TSL2550 ambient light sensor driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRIVER_VERSION);
-
-module_init(tsl2550_init);
-module_exit(tsl2550_exit);
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 2c151e1..5a2cbfa 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -750,15 +750,12 @@
 {
 	int idx = tty->index;
 	struct sdio_uart_port *port = sdio_uart_port_get(idx);
-	int ret = tty_init_termios(tty);
+	int ret = tty_standard_install(driver, tty);
 
-	if (ret == 0) {
-		tty_driver_kref_get(driver);
-		tty->count++;
+	if (ret == 0)
 		/* This is the ref sdio_uart_port get provided */
 		tty->driver_data = port;
-		driver->ttys[idx] = tty;
-	} else
+	else
 		sdio_uart_port_put(port);
 	return ret;
 }
@@ -1178,7 +1175,6 @@
 	if (!tty_drv)
 		return -ENOMEM;
 
-	tty_drv->owner = THIS_MODULE;
 	tty_drv->driver_name = "sdio_uart";
 	tty_drv->name =   "ttySDIO";
 	tty_drv->major = 0;  /* dynamically allocated */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 7aee469..99389c8 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -1934,7 +1934,7 @@
 	}
 
 	if (bp->port.pmf)
-		bnx2x_update_drv_flags(bp, DRV_FLAGS_DCB_CONFIGURED, 0);
+		bnx2x_update_drv_flags(bp, 1 << DRV_FLAGS_DCB_CONFIGURED, 0);
 	else
 		bnx2x__link_status_update(bp);
 
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index bf27c54..4f40f7d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -1179,10 +1179,16 @@
  */
 static inline u8 bnx2x_stats_id(struct bnx2x_fastpath *fp)
 {
-	if (!CHIP_IS_E1x(fp->bp))
+	struct bnx2x *bp = fp->bp;
+	if (!CHIP_IS_E1x(bp)) {
+#ifdef BCM_CNIC
+		/* there are special statistics counters for FCoE 136..140 */
+		if (IS_FCOE_FP(fp))
+			return bp->cnic_base_cl_id + (bp->pf_num >> 1);
+#endif
 		return fp->cl_id;
-	else
-		return fp->cl_id + BP_PORT(fp->bp) * FP_SB_MAX_E1x;
+	}
+	return fp->cl_id + BP_PORT(bp) * FP_SB_MAX_E1x;
 }
 
 static inline void bnx2x_init_vlan_mac_fp_objs(struct bnx2x_fastpath *fp,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
index 5051cf3..6d82ade 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
@@ -735,7 +735,9 @@
 						 bp->dcbx_error);
 
 			/* mark DCBX result for PMF migration */
-			bnx2x_update_drv_flags(bp, DRV_FLAGS_DCB_CONFIGURED, 1);
+			bnx2x_update_drv_flags(bp,
+					       1 << DRV_FLAGS_DCB_CONFIGURED,
+					       1);
 #ifdef BCM_DCBNL
 			/*
 			 * Add new app tlvs to dcbnl
@@ -1020,7 +1022,7 @@
 		DP(NETIF_MSG_LINK, "dcbx_lldp_params_offset 0x%x\n",
 		   dcbx_lldp_params_offset);
 
-		bnx2x_update_drv_flags(bp, DRV_FLAGS_DCB_CONFIGURED, 0);
+		bnx2x_update_drv_flags(bp, 1 << DRV_FLAGS_DCB_CONFIGURED, 0);
 
 		if (SHMEM_LLDP_DCBX_PARAMS_NONE != dcbx_lldp_params_offset) {
 			bnx2x_dcbx_admin_mib_updated_params(bp,
@@ -1857,7 +1859,7 @@
 	 * read it from shmem and update bp and netdev accordingly
 	 */
 	if (SHMEM2_HAS(bp, drv_flags) &&
-	   GET_FLAGS(SHMEM2_RD(bp, drv_flags), DRV_FLAGS_DCB_CONFIGURED)) {
+	   GET_FLAGS(SHMEM2_RD(bp, drv_flags), 1 << DRV_FLAGS_DCB_CONFIGURED)) {
 		/* Read neg results if dcbx is in the FW */
 		if (bnx2x_dcbx_read_shmem_neg_results(bp))
 			return;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 2545213..b69f876 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -10824,38 +10824,36 @@
 
 int bnx2x_init_firmware(struct bnx2x *bp)
 {
+	const char *fw_file_name;
 	struct bnx2x_fw_file_hdr *fw_hdr;
 	int rc;
 
+	if (bp->firmware)
+		return 0;
 
-	if (!bp->firmware) {
-		const char *fw_file_name;
+	if (CHIP_IS_E1(bp))
+		fw_file_name = FW_FILE_NAME_E1;
+	else if (CHIP_IS_E1H(bp))
+		fw_file_name = FW_FILE_NAME_E1H;
+	else if (!CHIP_IS_E1x(bp))
+		fw_file_name = FW_FILE_NAME_E2;
+	else {
+		BNX2X_ERR("Unsupported chip revision\n");
+		return -EINVAL;
+	}
+	BNX2X_DEV_INFO("Loading %s\n", fw_file_name);
 
-		if (CHIP_IS_E1(bp))
-			fw_file_name = FW_FILE_NAME_E1;
-		else if (CHIP_IS_E1H(bp))
-			fw_file_name = FW_FILE_NAME_E1H;
-		else if (!CHIP_IS_E1x(bp))
-			fw_file_name = FW_FILE_NAME_E2;
-		else {
-			BNX2X_ERR("Unsupported chip revision\n");
-			return -EINVAL;
-		}
-		BNX2X_DEV_INFO("Loading %s\n", fw_file_name);
+	rc = request_firmware(&bp->firmware, fw_file_name, &bp->pdev->dev);
+	if (rc) {
+		BNX2X_ERR("Can't load firmware file %s\n",
+			  fw_file_name);
+		goto request_firmware_exit;
+	}
 
-		rc = request_firmware(&bp->firmware, fw_file_name,
-				      &bp->pdev->dev);
-		if (rc) {
-			BNX2X_ERR("Can't load firmware file %s\n",
-				  fw_file_name);
-			goto request_firmware_exit;
-		}
-
-		rc = bnx2x_check_firmware(bp);
-		if (rc) {
-			BNX2X_ERR("Corrupt firmware file %s\n", fw_file_name);
-			goto request_firmware_exit;
-		}
+	rc = bnx2x_check_firmware(bp);
+	if (rc) {
+		BNX2X_ERR("Corrupt firmware file %s\n", fw_file_name);
+		goto request_firmware_exit;
 	}
 
 	fw_hdr = (struct bnx2x_fw_file_hdr *)bp->firmware->data;
@@ -10901,6 +10899,7 @@
 	kfree(bp->init_data);
 request_firmware_exit:
 	release_firmware(bp->firmware);
+	bp->firmware = NULL;
 
 	return rc;
 }
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index cb6339c..94110e9 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -5601,7 +5601,7 @@
 
 	/* Fill the ramrod data with provided parameters */
 	rdata->function_mode = cpu_to_le16(start_params->mf_mode);
-	rdata->sd_vlan_tag   = start_params->sd_vlan_tag;
+	rdata->sd_vlan_tag   = cpu_to_le16(start_params->sd_vlan_tag);
 	rdata->path_id       = BP_PATH(bp);
 	rdata->network_cos_mode = start_params->network_cos_mode;
 
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
index 1adef26..a766b25 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
@@ -554,23 +554,11 @@
 		UPDATE_STAT64(tx_stat_gtufl, tx_stat_mac_ufl);
 
 		/* collect PFC stats */
-		DIFF_64(diff.hi, new->tx_stat_gtpp_hi,
-			pstats->pfc_frames_tx_hi,
-			diff.lo, new->tx_stat_gtpp_lo,
-			pstats->pfc_frames_tx_lo);
 		pstats->pfc_frames_tx_hi = new->tx_stat_gtpp_hi;
 		pstats->pfc_frames_tx_lo = new->tx_stat_gtpp_lo;
-		ADD_64(pstats->pfc_frames_tx_hi, diff.hi,
-			pstats->pfc_frames_tx_lo, diff.lo);
 
-		DIFF_64(diff.hi, new->rx_stat_grpp_hi,
-			pstats->pfc_frames_rx_hi,
-			diff.lo, new->rx_stat_grpp_lo,
-			pstats->pfc_frames_rx_lo);
 		pstats->pfc_frames_rx_hi = new->rx_stat_grpp_hi;
 		pstats->pfc_frames_rx_lo = new->rx_stat_grpp_lo;
-		ADD_64(pstats->pfc_frames_rx_hi, diff.hi,
-			pstats->pfc_frames_rx_lo, diff.lo);
 	}
 
 	estats->pause_frames_received_hi =
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index bf01841..610860f 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -166,7 +166,7 @@
 
 		dev_kfree_skb(skb);
 		net->stats.tx_dropped++;
-		return NETDEV_TX_BUSY;
+		return NETDEV_TX_OK;
 	}
 
 	packet->extension = (void *)(unsigned long)packet +
@@ -226,7 +226,7 @@
 		dev_kfree_skb_any(skb);
 	}
 
-	return ret ? NETDEV_TX_BUSY : NETDEV_TX_OK;
+	return NETDEV_TX_OK;
 }
 
 /*
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index f320f46..e8c42d6 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -915,9 +915,7 @@
 
 	phydev = to_phy_device(dev);
 
-	/* Make sure the driver is held.
-	 * XXX -- Is this correct? */
-	drv = get_driver(phydev->dev.driver);
+	drv = phydev->dev.driver;
 	phydrv = to_phy_driver(drv);
 	phydev->drv = phydrv;
 
@@ -957,8 +955,6 @@
 
 	if (phydev->drv->remove)
 		phydev->drv->remove(phydev);
-
-	put_driver(dev->driver);
 	phydev->drv = NULL;
 
 	return 0;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 93c5d72..2d7601d 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -359,7 +359,7 @@
 {
 	struct tun_struct *tun = netdev_priv(dev);
 
-	sock_put(tun->socket.sk);
+	sk_release_kernel(tun->socket.sk);
 }
 
 /* Net device open. */
@@ -980,10 +980,18 @@
 	return ret;
 }
 
+static int tun_release(struct socket *sock)
+{
+	if (sock->sk)
+		sock_put(sock->sk);
+	return 0;
+}
+
 /* Ops structure to mimic raw sockets with tun */
 static const struct proto_ops tun_socket_ops = {
 	.sendmsg = tun_sendmsg,
 	.recvmsg = tun_recvmsg,
+	.release = tun_release,
 };
 
 static struct proto tun_proto = {
@@ -1110,10 +1118,11 @@
 		tun->vnet_hdr_sz = sizeof(struct virtio_net_hdr);
 
 		err = -ENOMEM;
-		sk = sk_alloc(net, AF_UNSPEC, GFP_KERNEL, &tun_proto);
+		sk = sk_alloc(&init_net, AF_UNSPEC, GFP_KERNEL, &tun_proto);
 		if (!sk)
 			goto err_free_dev;
 
+		sk_change_net(sk, net);
 		tun->socket.wq = &tun->wq;
 		init_waitqueue_head(&tun->wq.wait);
 		tun->socket.ops = &tun_socket_ops;
@@ -1174,7 +1183,7 @@
 	return 0;
 
  err_free_sk:
-	sock_put(sk);
+	tun_free_netdev(dev);
  err_free_dev:
 	free_netdev(dev);
  failed:
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 2335761..4bad899 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -398,6 +398,27 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called kalmia.
 
+config USB_NET_QMI_WWAN
+	tristate "QMI WWAN driver for Qualcomm MSM based 3G and LTE modems"
+	depends on USB_USBNET
+	help
+	  Support WWAN LTE/3G devices based on Qualcomm Mobile Data Modem
+	  (MDM) chipsets.  Examples of such devices are
+	    * Huawei E392/E398
+
+	  This driver will only drive the ethernet part of the chips.
+	  The devices require additional configuration to be usable.
+	  Multiple management interfaces with linux drivers are
+	  available:
+
+	    * option: AT commands on /dev/ttyUSBx
+	    * cdc-wdm: Qualcomm MSM Interface (QMI) protocol on /dev/cdc-wdmx
+
+	  A modem manager with support for QMI is recommended.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called qmi_wwan.
+
 config USB_HSO
 	tristate "Option USB High Speed Mobile Devices"
 	depends on USB && RFKILL
@@ -461,4 +482,5 @@
 
 	  http://ubuntuforums.org/showpost.php?p=10589647&postcount=17
 
+
 endmenu
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index c203fa2..a2e2d72 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -29,4 +29,5 @@
 obj-$(CONFIG_USB_NET_CX82310_ETH)	+= cx82310_eth.o
 obj-$(CONFIG_USB_NET_CDC_NCM)	+= cdc_ncm.o
 obj-$(CONFIG_USB_VL600)		+= lg-vl600.o
+obj-$(CONFIG_USB_NET_QMI_WWAN)	+= qmi_wwan.o
 
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 8e84f5b..d6da5ee 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -1599,6 +1599,10 @@
 	USB_DEVICE (0x6189, 0x182d),
 	.driver_info =  (unsigned long) &ax8817x_info,
 }, {
+	// Sitecom LN-031 "USB 2.0 10/100/1000 Ethernet adapter"
+	USB_DEVICE (0x0df6, 0x0056),
+	.driver_info =  (unsigned long) &ax88178_info,
+}, {
 	// corega FEther USB2-TX
 	USB_DEVICE (0x07aa, 0x0017),
 	.driver_info =  (unsigned long) &ax8817x_info,
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index e1324b4..2d2a688 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -3313,7 +3313,6 @@
 
 	/* fill in all needed values */
 	tty_drv->magic = TTY_DRIVER_MAGIC;
-	tty_drv->owner = THIS_MODULE;
 	tty_drv->driver_name = driver_name;
 	tty_drv->name = tty_filename;
 
@@ -3322,7 +3321,6 @@
 		tty_drv->major = tty_major;
 
 	tty_drv->minor_start = 0;
-	tty_drv->num = HSO_SERIAL_TTY_MINORS;
 	tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
 	tty_drv->subtype = SERIAL_TYPE_NORMAL;
 	tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
new file mode 100644
index 0000000..aac68f5
--- /dev/null
+++ b/drivers/net/usb/qmi_wwan.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2012  Bjørn Mork <bjorn@mork.no>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/usbnet.h>
+#include <linux/usb/cdc-wdm.h>
+
+/* The name of the CDC Device Management driver */
+#define DM_DRIVER "cdc_wdm"
+
+/*
+ * This driver supports wwan (3G/LTE/?) devices using a vendor
+ * specific management protocol called Qualcomm MSM Interface (QMI) -
+ * in addition to the more common AT commands over serial interface
+ * management
+ *
+ * QMI is wrapped in CDC, using CDC encapsulated commands on the
+ * control ("master") interface of a two-interface CDC Union
+ * resembling standard CDC ECM.  The devices do not use the control
+ * interface for any other CDC messages.  Most likely because the
+ * management protocol is used in place of the standard CDC
+ * notifications NOTIFY_NETWORK_CONNECTION and NOTIFY_SPEED_CHANGE
+ *
+ * Handling a protocol like QMI is out of the scope for any driver.
+ * It can be exported as a character device using the cdc-wdm driver,
+ * which will enable userspace applications ("modem managers") to
+ * handle it.  This may be required to use the network interface
+ * provided by the driver.
+ *
+ * These devices may alternatively/additionally be configured using AT
+ * commands on any of the serial interfaces driven by the option driver
+ *
+ * This driver binds only to the data ("slave") interface to enable
+ * the cdc-wdm driver to bind to the control interface.  It still
+ * parses the CDC functional descriptors on the control interface to
+ *  a) verify that this is indeed a handled interface (CDC Union
+ *     header lists it as slave)
+ *  b) get MAC address and other ethernet config from the CDC Ethernet
+ *     header
+ *  c) enable user bind requests against the control interface, which
+ *     is the common way to bind to CDC Ethernet Control Model type
+ *     interfaces
+ *  d) provide a hint to the user about which interface is the
+ *     corresponding management interface
+ */
+
+static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	int status = -1;
+	struct usb_interface *control = NULL;
+	u8 *buf = intf->cur_altsetting->extra;
+	int len = intf->cur_altsetting->extralen;
+	struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc;
+	struct usb_cdc_union_desc *cdc_union = NULL;
+	struct usb_cdc_ether_desc *cdc_ether = NULL;
+	u32 required = 1 << USB_CDC_HEADER_TYPE | 1 << USB_CDC_UNION_TYPE;
+	u32 found = 0;
+	atomic_t *pmcount = (void *)&dev->data[1];
+
+	atomic_set(pmcount, 0);
+
+	/*
+	 * assume a data interface has no additional descriptors and
+	 * that the control and data interface are numbered
+	 * consecutively - this holds for the Huawei device at least
+	 */
+	if (len == 0 && desc->bInterfaceNumber > 0) {
+		control = usb_ifnum_to_if(dev->udev, desc->bInterfaceNumber - 1);
+		if (!control)
+			goto err;
+
+		buf = control->cur_altsetting->extra;
+		len = control->cur_altsetting->extralen;
+		dev_dbg(&intf->dev, "guessing \"control\" => %s, \"data\" => this\n",
+			dev_name(&control->dev));
+	}
+
+	while (len > 3) {
+		struct usb_descriptor_header *h = (void *)buf;
+
+		/* ignore any misplaced descriptors */
+		if (h->bDescriptorType != USB_DT_CS_INTERFACE)
+			goto next_desc;
+
+		/* buf[2] is CDC descriptor subtype */
+		switch (buf[2]) {
+		case USB_CDC_HEADER_TYPE:
+			if (found & 1 << USB_CDC_HEADER_TYPE) {
+				dev_dbg(&intf->dev, "extra CDC header\n");
+				goto err;
+			}
+			if (h->bLength != sizeof(struct usb_cdc_header_desc)) {
+				dev_dbg(&intf->dev, "CDC header len %u\n", h->bLength);
+				goto err;
+			}
+			break;
+		case USB_CDC_UNION_TYPE:
+			if (found & 1 << USB_CDC_UNION_TYPE) {
+				dev_dbg(&intf->dev, "extra CDC union\n");
+				goto err;
+			}
+			if (h->bLength != sizeof(struct usb_cdc_union_desc)) {
+				dev_dbg(&intf->dev, "CDC union len %u\n", h->bLength);
+				goto err;
+			}
+			cdc_union = (struct usb_cdc_union_desc *)buf;
+			break;
+		case USB_CDC_ETHERNET_TYPE:
+			if (found & 1 << USB_CDC_ETHERNET_TYPE) {
+				dev_dbg(&intf->dev, "extra CDC ether\n");
+				goto err;
+			}
+			if (h->bLength != sizeof(struct usb_cdc_ether_desc)) {
+				dev_dbg(&intf->dev, "CDC ether len %u\n",  h->bLength);
+				goto err;
+			}
+			cdc_ether = (struct usb_cdc_ether_desc *)buf;
+			break;
+		}
+
+		/*
+		 * Remember which CDC functional descriptors we've seen.  Works
+		 * for all types we care about, of which USB_CDC_ETHERNET_TYPE
+		 * (0x0f) is the highest numbered
+		 */
+		if (buf[2] < 32)
+			found |= 1 << buf[2];
+
+next_desc:
+		len -= h->bLength;
+		buf += h->bLength;
+	}
+
+	/* did we find all the required ones? */
+	if ((found & required) != required) {
+		dev_err(&intf->dev, "CDC functional descriptors missing\n");
+		goto err;
+	}
+
+	/* give the user a helpful hint if trying to bind to the wrong interface */
+	if (cdc_union && desc->bInterfaceNumber == cdc_union->bMasterInterface0) {
+		dev_err(&intf->dev, "leaving \"control\" interface for " DM_DRIVER " - try binding to %s instead!\n",
+			dev_name(&usb_ifnum_to_if(dev->udev, cdc_union->bSlaveInterface0)->dev));
+		goto err;
+	}
+
+	/* errors aren't fatal - we can live with the dynamic address */
+	if (cdc_ether) {
+		dev->hard_mtu = le16_to_cpu(cdc_ether->wMaxSegmentSize);
+		usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress);
+	}
+
+	/* success! point the user to the management interface */
+	if (control)
+		dev_info(&intf->dev, "Use \"" DM_DRIVER "\" for QMI interface %s\n",
+			dev_name(&control->dev));
+
+	/* XXX: add a sysfs symlink somewhere to help management applications find it? */
+
+	/* collect bulk endpoints now that we know intf == "data" interface */
+	status = usbnet_get_endpoints(dev, intf);
+
+err:
+	return status;
+}
+
+/* using a counter to merge subdriver requests with our own into a combined state */
+static int qmi_wwan_manage_power(struct usbnet *dev, int on)
+{
+	atomic_t *pmcount = (void *)&dev->data[1];
+	int rv = 0;
+
+	dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__, atomic_read(pmcount), on);
+
+	if ((on && atomic_add_return(1, pmcount) == 1) || (!on && atomic_dec_and_test(pmcount))) {
+		/* need autopm_get/put here to ensure the usbcore sees the new value */
+		rv = usb_autopm_get_interface(dev->intf);
+		if (rv < 0)
+			goto err;
+		dev->intf->needs_remote_wakeup = on;
+		usb_autopm_put_interface(dev->intf);
+	}
+err:
+	return rv;
+}
+
+static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on)
+{
+	struct usbnet *dev = usb_get_intfdata(intf);
+	return qmi_wwan_manage_power(dev, on);
+}
+
+/* Some devices combine the "control" and "data" functions into a
+ * single interface with all three endpoints: interrupt + bulk in and
+ * out
+ *
+ * Setting up cdc-wdm as a subdriver owning the interrupt endpoint
+ * will let it provide userspace access to the encapsulated QMI
+ * protocol without interfering with the usbnet operations.
+  */
+static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf)
+{
+	int rv;
+	struct usb_driver *subdriver = NULL;
+	atomic_t *pmcount = (void *)&dev->data[1];
+
+	/* ZTE makes devices where the interface descriptors and endpoint
+	 * configurations of two or more interfaces are identical, even
+	 * though the functions are completely different.  If set, then
+	 * driver_info->data is a bitmap of acceptable interface numbers
+	 * allowing us to bind to one such interface without binding to
+	 * all of them
+	 */
+	if (dev->driver_info->data &&
+	    !test_bit(intf->cur_altsetting->desc.bInterfaceNumber, &dev->driver_info->data)) {
+		dev_info(&intf->dev, "not on our whitelist - ignored");
+		rv = -ENODEV;
+		goto err;
+	}
+
+	atomic_set(pmcount, 0);
+
+	/* collect all three endpoints */
+	rv = usbnet_get_endpoints(dev, intf);
+	if (rv < 0)
+		goto err;
+
+	/* require interrupt endpoint for subdriver */
+	if (!dev->status) {
+		rv = -EINVAL;
+		goto err;
+	}
+
+	subdriver = usb_cdc_wdm_register(intf, &dev->status->desc, 512, &qmi_wwan_cdc_wdm_manage_power);
+	if (IS_ERR(subdriver)) {
+		rv = PTR_ERR(subdriver);
+		goto err;
+	}
+
+	/* can't let usbnet use the interrupt endpoint */
+	dev->status = NULL;
+
+	/* save subdriver struct for suspend/resume wrappers */
+	dev->data[0] = (unsigned long)subdriver;
+
+err:
+	return rv;
+}
+
+/* Gobi devices uses identical class/protocol codes for all interfaces regardless
+ * of function. Some of these are CDC ACM like and have the exact same endpoints
+ * we are looking for. This leaves two possible strategies for identifying the
+ * correct interface:
+ *   a) hardcoding interface number, or
+ *   b) use the fact that the wwan interface is the only one lacking additional
+ *      (CDC functional) descriptors
+ *
+ * Let's see if we can get away with the generic b) solution.
+ */
+static int qmi_wwan_bind_gobi(struct usbnet *dev, struct usb_interface *intf)
+{
+	int rv = -EINVAL;
+
+	/* ignore any interface with additional descriptors */
+	if (intf->cur_altsetting->extralen)
+		goto err;
+
+	rv = qmi_wwan_bind_shared(dev, intf);
+err:
+	return rv;
+}
+
+static void qmi_wwan_unbind_shared(struct usbnet *dev, struct usb_interface *intf)
+{
+	struct usb_driver *subdriver = (void *)dev->data[0];
+
+	if (subdriver && subdriver->disconnect)
+		subdriver->disconnect(intf);
+
+	dev->data[0] = (unsigned long)NULL;
+}
+
+/* suspend/resume wrappers calling both usbnet and the cdc-wdm
+ * subdriver if present.
+ *
+ * NOTE: cdc-wdm also supports pre/post_reset, but we cannot provide
+ * wrappers for those without adding usbnet reset support first.
+ */
+static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct usbnet *dev = usb_get_intfdata(intf);
+	struct usb_driver *subdriver = (void *)dev->data[0];
+	int ret;
+
+	ret = usbnet_suspend(intf, message);
+	if (ret < 0)
+		goto err;
+
+	if (subdriver && subdriver->suspend)
+		ret = subdriver->suspend(intf, message);
+	if (ret < 0)
+		usbnet_resume(intf);
+err:
+	return ret;
+}
+
+static int qmi_wwan_resume(struct usb_interface *intf)
+{
+	struct usbnet *dev = usb_get_intfdata(intf);
+	struct usb_driver *subdriver = (void *)dev->data[0];
+	int ret = 0;
+
+	if (subdriver && subdriver->resume)
+		ret = subdriver->resume(intf);
+	if (ret < 0)
+		goto err;
+	ret = usbnet_resume(intf);
+	if (ret < 0 && subdriver && subdriver->resume && subdriver->suspend)
+		subdriver->suspend(intf, PMSG_SUSPEND);
+err:
+	return ret;
+}
+
+
+static const struct driver_info	qmi_wwan_info = {
+	.description	= "QMI speaking wwan device",
+	.flags		= FLAG_WWAN,
+	.bind		= qmi_wwan_bind,
+	.manage_power	= qmi_wwan_manage_power,
+};
+
+static const struct driver_info	qmi_wwan_shared = {
+	.description	= "QMI speaking wwan device with combined interface",
+	.flags		= FLAG_WWAN,
+	.bind		= qmi_wwan_bind_shared,
+	.unbind		= qmi_wwan_unbind_shared,
+	.manage_power	= qmi_wwan_manage_power,
+};
+
+static const struct driver_info	qmi_wwan_gobi = {
+	.description	= "Qualcomm Gobi wwan/QMI device",
+	.flags		= FLAG_WWAN,
+	.bind		= qmi_wwan_bind_gobi,
+	.unbind		= qmi_wwan_unbind_shared,
+	.manage_power	= qmi_wwan_manage_power,
+};
+
+/* ZTE suck at making USB descriptors */
+static const struct driver_info	qmi_wwan_force_int4 = {
+	.description	= "Qualcomm Gobi wwan/QMI device",
+	.flags		= FLAG_WWAN,
+	.bind		= qmi_wwan_bind_gobi,
+	.unbind		= qmi_wwan_unbind_shared,
+	.manage_power	= qmi_wwan_manage_power,
+	.data		= BIT(4), /* interface whitelist bitmap */
+};
+
+
+#define HUAWEI_VENDOR_ID	0x12D1
+#define QMI_GOBI_DEVICE(vend, prod) \
+	USB_DEVICE(vend, prod), \
+	.driver_info = (unsigned long)&qmi_wwan_gobi
+
+static const struct usb_device_id products[] = {
+	{	/* Huawei E392, E398 and possibly others sharing both device id and more... */
+		.match_flags        = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
+		.idVendor           = HUAWEI_VENDOR_ID,
+		.bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
+		.bInterfaceSubClass = 1,
+		.bInterfaceProtocol = 8, /* NOTE: This is the *slave* interface of the CDC Union! */
+		.driver_info        = (unsigned long)&qmi_wwan_info,
+	},
+	{	/* Huawei E392, E398 and possibly others in "Windows mode"
+		 * using a combined control and data interface without any CDC
+		 * functional descriptors
+		 */
+		.match_flags        = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
+		.idVendor           = HUAWEI_VENDOR_ID,
+		.bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
+		.bInterfaceSubClass = 1,
+		.bInterfaceProtocol = 17,
+		.driver_info        = (unsigned long)&qmi_wwan_shared,
+	},
+	{	/* Pantech UML290 */
+		.match_flags	    = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
+		.idVendor           = 0x106c,
+		.idProduct          = 0x3718,
+		.bInterfaceClass    = 0xff,
+		.bInterfaceSubClass = 0xf0,
+		.bInterfaceProtocol = 0xff,
+		.driver_info        = (unsigned long)&qmi_wwan_shared,
+	},
+	{	/* ZTE MF820D */
+		.match_flags	    = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
+		.idVendor           = 0x19d2,
+		.idProduct          = 0x0167,
+		.bInterfaceClass    = 0xff,
+		.bInterfaceSubClass = 0xff,
+		.bInterfaceProtocol = 0xff,
+		.driver_info        = (unsigned long)&qmi_wwan_force_int4,
+	},
+	{QMI_GOBI_DEVICE(0x05c6, 0x9212)},	/* Acer Gobi Modem Device */
+	{QMI_GOBI_DEVICE(0x03f0, 0x1f1d)},	/* HP un2400 Gobi Modem Device */
+	{QMI_GOBI_DEVICE(0x03f0, 0x371d)},	/* HP un2430 Mobile Broadband Module */
+	{QMI_GOBI_DEVICE(0x04da, 0x250d)},	/* Panasonic Gobi Modem device */
+	{QMI_GOBI_DEVICE(0x413c, 0x8172)},	/* Dell Gobi Modem device */
+	{QMI_GOBI_DEVICE(0x1410, 0xa001)},	/* Novatel Gobi Modem device */
+	{QMI_GOBI_DEVICE(0x0b05, 0x1776)},	/* Asus Gobi Modem device */
+	{QMI_GOBI_DEVICE(0x19d2, 0xfff3)},	/* ONDA Gobi Modem device */
+	{QMI_GOBI_DEVICE(0x05c6, 0x9001)},	/* Generic Gobi Modem device */
+	{QMI_GOBI_DEVICE(0x05c6, 0x9002)},	/* Generic Gobi Modem device */
+	{QMI_GOBI_DEVICE(0x05c6, 0x9202)},	/* Generic Gobi Modem device */
+	{QMI_GOBI_DEVICE(0x05c6, 0x9203)},	/* Generic Gobi Modem device */
+	{QMI_GOBI_DEVICE(0x05c6, 0x9222)},	/* Generic Gobi Modem device */
+	{QMI_GOBI_DEVICE(0x05c6, 0x9009)},	/* Generic Gobi Modem device */
+	{QMI_GOBI_DEVICE(0x413c, 0x8186)},	/* Dell Gobi 2000 Modem device (N0218, VU936) */
+	{QMI_GOBI_DEVICE(0x05c6, 0x920b)},	/* Generic Gobi 2000 Modem device */
+	{QMI_GOBI_DEVICE(0x05c6, 0x9225)},	/* Sony Gobi 2000 Modem device (N0279, VU730) */
+	{QMI_GOBI_DEVICE(0x05c6, 0x9245)},	/* Samsung Gobi 2000 Modem device (VL176) */
+	{QMI_GOBI_DEVICE(0x03f0, 0x251d)},	/* HP Gobi 2000 Modem device (VP412) */
+	{QMI_GOBI_DEVICE(0x05c6, 0x9215)},	/* Acer Gobi 2000 Modem device (VP413) */
+	{QMI_GOBI_DEVICE(0x05c6, 0x9265)},	/* Asus Gobi 2000 Modem device (VR305) */
+	{QMI_GOBI_DEVICE(0x05c6, 0x9235)},	/* Top Global Gobi 2000 Modem device (VR306) */
+	{QMI_GOBI_DEVICE(0x05c6, 0x9275)},	/* iRex Technologies Gobi 2000 Modem device (VR307) */
+	{QMI_GOBI_DEVICE(0x1199, 0x9001)},	/* Sierra Wireless Gobi 2000 Modem device (VT773) */
+	{QMI_GOBI_DEVICE(0x1199, 0x9002)},	/* Sierra Wireless Gobi 2000 Modem device (VT773) */
+	{QMI_GOBI_DEVICE(0x1199, 0x9003)},	/* Sierra Wireless Gobi 2000 Modem device (VT773) */
+	{QMI_GOBI_DEVICE(0x1199, 0x9004)},	/* Sierra Wireless Gobi 2000 Modem device (VT773) */
+	{QMI_GOBI_DEVICE(0x1199, 0x9005)},	/* Sierra Wireless Gobi 2000 Modem device (VT773) */
+	{QMI_GOBI_DEVICE(0x1199, 0x9006)},	/* Sierra Wireless Gobi 2000 Modem device (VT773) */
+	{QMI_GOBI_DEVICE(0x1199, 0x9007)},	/* Sierra Wireless Gobi 2000 Modem device (VT773) */
+	{QMI_GOBI_DEVICE(0x1199, 0x9008)},	/* Sierra Wireless Gobi 2000 Modem device (VT773) */
+	{QMI_GOBI_DEVICE(0x1199, 0x9009)},	/* Sierra Wireless Gobi 2000 Modem device (VT773) */
+	{QMI_GOBI_DEVICE(0x1199, 0x900a)},	/* Sierra Wireless Gobi 2000 Modem device (VT773) */
+	{QMI_GOBI_DEVICE(0x1199, 0x9011)},	/* Sierra Wireless Gobi 2000 Modem device (MC8305) */
+	{QMI_GOBI_DEVICE(0x16d8, 0x8002)},	/* CMDTech Gobi 2000 Modem device (VU922) */
+	{QMI_GOBI_DEVICE(0x05c6, 0x9205)},	/* Gobi 2000 Modem device */
+	{QMI_GOBI_DEVICE(0x1199, 0x9013)},	/* Sierra Wireless Gobi 3000 Modem device (MC8355) */
+	{ }					/* END */
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver qmi_wwan_driver = {
+	.name		      = "qmi_wwan",
+	.id_table	      = products,
+	.probe		      =	usbnet_probe,
+	.disconnect	      = usbnet_disconnect,
+	.suspend	      = qmi_wwan_suspend,
+	.resume		      =	qmi_wwan_resume,
+	.reset_resume         = qmi_wwan_resume,
+	.supports_autosuspend = 1,
+};
+
+static int __init qmi_wwan_init(void)
+{
+	return usb_register(&qmi_wwan_driver);
+}
+module_init(qmi_wwan_init);
+
+static void __exit qmi_wwan_exit(void)
+{
+	usb_deregister(&qmi_wwan_driver);
+}
+module_exit(qmi_wwan_exit);
+
+MODULE_AUTHOR("Bjørn Mork <bjorn@mork.no>");
+MODULE_DESCRIPTION("Qualcomm MSM Interface (QMI) WWAN driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 81b96e3..59681f0 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -328,13 +328,13 @@
 	unsigned long		lockflags;
 	size_t			size = dev->rx_urb_size;
 
-	if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) {
+	skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);
+	if (!skb) {
 		netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
 		usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
 		usb_free_urb (urb);
 		return -ENOMEM;
 	}
-	skb_reserve (skb, NET_IP_ALIGN);
 
 	entry = (struct skb_data *) skb->cb;
 	entry->urb = urb;
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
index 1eeedd6..cb0f8d9 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -299,7 +299,6 @@
 void cpc_tty_unregister_service(pc300dev_t * pc300dev);
 void cpc_tty_receive(pc300dev_t * pc300dev);
 void cpc_tty_trigger_poll(pc300dev_t * pc300dev);
-void cpc_tty_reset_var(void);
 #endif
 
 /************************/
@@ -3232,7 +3231,7 @@
 
 }
 
-static inline void show_version(void)
+static void show_version(void)
 {
 	char *rcsvers, *rcsdate, *tmp;
 
@@ -3413,19 +3412,10 @@
 static int __devinit
 cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	static int first_time = 1;
 	int err, eeprom_outdated = 0;
 	u16 device_id;
 	pc300_t *card;
 
-	if (first_time) {
-		first_time = 0;
-		show_version();
-#ifdef CONFIG_PC300_MLPPP
-		cpc_tty_reset_var();
-#endif
-	}
-
 	if ((err = pci_enable_device(pdev)) < 0)
 		return err;
 
@@ -3661,6 +3651,7 @@
 
 static int __init cpc_init(void)
 {
+	show_version();
 	return pci_register_driver(&cpc_driver);
 }
 
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c
index d47d2cd..4709f42 100644
--- a/drivers/net/wan/pc300_tty.c
+++ b/drivers/net/wan/pc300_tty.c
@@ -139,7 +139,6 @@
 void cpc_tty_unregister_service(pc300dev_t *pc300dev);
 void cpc_tty_receive(pc300dev_t *pc300dev);
 void cpc_tty_trigger_poll(pc300dev_t *pc300dev);
-void cpc_tty_reset_var(void);
 
 /*
  * PC300 TTY clear "signal"
@@ -1078,20 +1077,3 @@
 	}
 	schedule_work(&(cpc_tty->tty_tx_work)); 
 } 
-
-/*
- * PC300 TTY reset var routine
- * This routine is called by pc300driver to init the TTY area. 
- */
-
-void cpc_tty_reset_var(void)
-{
-	int i ; 
-
-	CPC_TTY_DBG("hdlcX-tty: reset variables\n");
-	/* reset  the tty_driver structure - serial_drv */ 
-	memset(&serial_drv, 0, sizeof(struct tty_driver));
-	for (i=0; i < CPC_TTY_NPORTS; i++){
-		memset(&cpc_tty_area[i],0, sizeof(st_cpc_tty_area)); 
-	}
-}
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
index 64a1106..63e4b70 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -367,38 +367,28 @@
 {
 	struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
 	struct device *dev = i2400m_dev(i2400m);
-	int result;
+	int result = -1;
 
 	d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev);
-	if (skb_header_cloned(skb)) {
-		/*
-		 * Make tcpdump/wireshark happy -- if they are
-		 * running, the skb is cloned and we will overwrite
-		 * the mac fields in i2400m_tx_prep_header. Expand
-		 * seems to fix this...
-		 */
-		result = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
-		if (result) {
-			result = NETDEV_TX_BUSY;
-			goto error_expand;
-		}
-	}
+
+	if (skb_header_cloned(skb) && 
+	    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+		goto drop;
 
 	if (i2400m->state == I2400M_SS_IDLE)
 		result = i2400m_net_wake_tx(i2400m, net_dev, skb);
 	else
 		result = i2400m_net_tx(i2400m, net_dev, skb);
-	if (result <  0)
+	if (result <  0) {
+drop:
 		net_dev->stats.tx_dropped++;
-	else {
+	} else {
 		net_dev->stats.tx_packets++;
 		net_dev->stats.tx_bytes += skb->len;
 	}
-	result = NETDEV_TX_OK;
-error_expand:
-	kfree_skb(skb);
+	dev_kfree_skb(skb);
 	d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result);
-	return result;
+	return NETDEV_TX_OK;
 }
 
 
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c
index 54b2d39..a7dfba8 100644
--- a/drivers/net/wireless/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/iwlegacy/3945-mac.c
@@ -2475,7 +2475,7 @@
 	    container_of(data, struct il_priv, alive_start.work);
 
 	mutex_lock(&il->mutex);
-	if (test_bit(S_EXIT_PENDING, &il->status))
+	if (test_bit(S_EXIT_PENDING, &il->status) || il->txq == NULL)
 		goto out;
 
 	il3945_alive_start(il);
diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c
index 1489b15..c80eb9b 100644
--- a/drivers/net/wireless/iwlegacy/3945.c
+++ b/drivers/net/wireless/iwlegacy/3945.c
@@ -1870,11 +1870,12 @@
 	struct il_priv *il = container_of(work, struct il_priv,
 					  _3945.thermal_periodic.work);
 
-	if (test_bit(S_EXIT_PENDING, &il->status))
-		return;
-
 	mutex_lock(&il->mutex);
+	if (test_bit(S_EXIT_PENDING, &il->status) || il->txq == NULL)
+		goto out;
+
 	il3945_reg_txpower_periodic(il);
+out:
 	mutex_unlock(&il->mutex);
 }
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index d2a1ea9..fd356b7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -426,10 +426,14 @@
 	/*
 	 * If the data queue was below the threshold before the txdone
 	 * handler we must make sure the packet queue in the mac80211 stack
-	 * is reenabled when the txdone handler has finished.
+	 * is reenabled when the txdone handler has finished. This has to be
+	 * serialized with rt2x00mac_tx(), otherwise we can wake up queue
+	 * before it was stopped.
 	 */
+	spin_lock_bh(&entry->queue->tx_lock);
 	if (!rt2x00queue_threshold(entry->queue))
 		rt2x00queue_unpause_queue(entry->queue);
+	spin_unlock_bh(&entry->queue->tx_lock);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index ede3c58..2df2eb6 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -152,13 +152,22 @@
 	if (unlikely(rt2x00queue_write_tx_frame(queue, skb, false)))
 		goto exit_fail;
 
+	/*
+	 * Pausing queue has to be serialized with rt2x00lib_txdone(). Note
+	 * we should not use spin_lock_bh variant as bottom halve was already
+	 * disabled before ieee80211_xmit() call.
+	 */
+	spin_lock(&queue->tx_lock);
 	if (rt2x00queue_threshold(queue))
 		rt2x00queue_pause_queue(queue);
+	spin_unlock(&queue->tx_lock);
 
 	return;
 
  exit_fail:
+	spin_lock(&queue->tx_lock);
 	rt2x00queue_pause_queue(queue);
+	spin_unlock(&queue->tx_lock);
  exit_free_skb:
 	ieee80211_free_txskb(hw, skb);
 }
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 5adfb3e..9b1b2b7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -619,6 +619,9 @@
 	else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags))
 		rt2x00queue_align_frame(skb);
 
+	/*
+	 * That function must be called with bh disabled.
+	 */
 	spin_lock(&queue->tx_lock);
 
 	if (unlikely(rt2x00queue_full(queue))) {
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 3623d65..8d9616b 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -72,9 +72,7 @@
 	list_add_tail(&dynid->node, &drv->dynids.list);
 	spin_unlock(&drv->dynids.lock);
 
-	get_driver(&drv->driver);
 	retval = driver_attach(&drv->driver);
-	put_driver(&drv->driver);
 
 	return retval;
 }
@@ -190,43 +188,34 @@
 static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);
 
 static int
-pci_create_newid_file(struct pci_driver *drv)
+pci_create_newid_files(struct pci_driver *drv)
 {
 	int error = 0;
-	if (drv->probe != NULL)
+
+	if (drv->probe != NULL) {
 		error = driver_create_file(&drv->driver, &driver_attr_new_id);
+		if (error == 0) {
+			error = driver_create_file(&drv->driver,
+					&driver_attr_remove_id);
+			if (error)
+				driver_remove_file(&drv->driver,
+						&driver_attr_new_id);
+		}
+	}
 	return error;
 }
 
-static void pci_remove_newid_file(struct pci_driver *drv)
-{
-	driver_remove_file(&drv->driver, &driver_attr_new_id);
-}
-
-static int
-pci_create_removeid_file(struct pci_driver *drv)
-{
-	int error = 0;
-	if (drv->probe != NULL)
-		error = driver_create_file(&drv->driver,&driver_attr_remove_id);
-	return error;
-}
-
-static void pci_remove_removeid_file(struct pci_driver *drv)
+static void pci_remove_newid_files(struct pci_driver *drv)
 {
 	driver_remove_file(&drv->driver, &driver_attr_remove_id);
+	driver_remove_file(&drv->driver, &driver_attr_new_id);
 }
 #else /* !CONFIG_HOTPLUG */
-static inline int pci_create_newid_file(struct pci_driver *drv)
+static inline int pci_create_newid_files(struct pci_driver *drv)
 {
 	return 0;
 }
-static inline void pci_remove_newid_file(struct pci_driver *drv) {}
-static inline int pci_create_removeid_file(struct pci_driver *drv)
-{
-	return 0;
-}
-static inline void pci_remove_removeid_file(struct pci_driver *drv) {}
+static inline void pci_remove_newid_files(struct pci_driver *drv) {}
 #endif
 
 /**
@@ -1138,18 +1127,12 @@
 	if (error)
 		goto out;
 
-	error = pci_create_newid_file(drv);
+	error = pci_create_newid_files(drv);
 	if (error)
 		goto out_newid;
-
-	error = pci_create_removeid_file(drv);
-	if (error)
-		goto out_removeid;
 out:
 	return error;
 
-out_removeid:
-	pci_remove_newid_file(drv);
 out_newid:
 	driver_unregister(&drv->driver);
 	goto out;
@@ -1168,8 +1151,7 @@
 void
 pci_unregister_driver(struct pci_driver *drv)
 {
-	pci_remove_removeid_file(drv);
-	pci_remove_newid_file(drv);
+	pci_remove_newid_files(drv);
 	driver_unregister(&drv->driver);
 	pci_free_dynids(drv);
 }
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 1cfbf22..24f049e 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -500,6 +500,9 @@
 	int pos;
 	u32 reg32;
 
+	if (aspm_disabled)
+		return 0;
+
 	/*
 	 * Some functions in a slot might not all be PCIe functions,
 	 * very strange. Disable ASPM for the whole slot
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index 1620088..4010901 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -593,7 +593,7 @@
 	}
 	pdrv = pcidev->driver;
 
-	if (get_driver(&pdrv->driver)) {
+	if (pdrv) {
 		if (pdrv->err_handler && pdrv->err_handler->error_detected) {
 			dev_dbg(&pcidev->dev,
 				"trying to call AER service\n");
@@ -623,7 +623,6 @@
 				}
 			}
 		}
-		put_driver(&pdrv->driver);
 	}
 	if (!flag)
 		result = PCI_ERS_RESULT_NONE;
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 1932029..079629b 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -127,10 +127,7 @@
 	list_add_tail(&dynid->node, &pdrv->dynids.list);
 	mutex_unlock(&pdrv->dynids.lock);
 
-	if (get_driver(&pdrv->drv)) {
-		retval = driver_attach(&pdrv->drv);
-		put_driver(&pdrv->drv);
-	}
+	retval = driver_attach(&pdrv->drv);
 
 	if (retval)
 		return retval;
@@ -160,6 +157,11 @@
 	return error;
 }
 
+static void
+pcmcia_remove_newid_file(struct pcmcia_driver *drv)
+{
+	driver_remove_file(&drv->drv, &driver_attr_new_id);
+}
 
 /**
  * pcmcia_register_driver - register a PCMCIA driver with the bus core
@@ -204,6 +206,7 @@
 void pcmcia_unregister_driver(struct pcmcia_driver *driver)
 {
 	pr_debug("unregistering driver %s\n", driver->name);
+	pcmcia_remove_newid_file(driver);
 	driver_unregister(&driver->drv);
 	pcmcia_free_dynids(driver);
 }
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index f995e6e..15dbd8c 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -143,6 +143,30 @@
 
 	  If you are not sure, say N here.
 
+config FUJITSU_TABLET
+       tristate "Fujitsu Tablet Extras"
+       depends on ACPI
+       depends on INPUT
+       ---help---
+         This is a driver for tablets built by Fujitsu:
+
+           * Lifebook P1510/P1610/P1620/Txxxx
+           * Stylistic ST5xxx
+           * Possibly other Fujitsu tablet models
+
+         It adds support for the panel buttons, docking station detection,
+         tablet/notebook mode detection for convertible and
+         orientation detection for docked slates.
+
+         If you have a Fujitsu convertible or slate, say Y or M here.
+
+config AMILO_RFKILL
+	tristate "Fujitsu-Siemens Amilo rfkill support"
+	depends on RFKILL
+	---help---
+	  This is a driver for enabling wifi on some Fujitsu-Siemens Amilo
+	  laptops.
+
 config TC1100_WMI
 	tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)"
 	depends on !X86_64
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 293a320..d328f21 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -17,12 +17,14 @@
 obj-$(CONFIG_ACERHDF)		+= acerhdf.o
 obj-$(CONFIG_HP_ACCEL)		+= hp_accel.o
 obj-$(CONFIG_HP_WMI)		+= hp-wmi.o
+obj-$(CONFIG_AMILO_RFKILL)	+= amilo-rfkill.o
 obj-$(CONFIG_TC1100_WMI)	+= tc1100-wmi.o
 obj-$(CONFIG_SONY_LAPTOP)	+= sony-laptop.o
 obj-$(CONFIG_IDEAPAD_LAPTOP)	+= ideapad-laptop.o
 obj-$(CONFIG_THINKPAD_ACPI)	+= thinkpad_acpi.o
 obj-$(CONFIG_SENSORS_HDAPS)	+= hdaps.o
 obj-$(CONFIG_FUJITSU_LAPTOP)	+= fujitsu-laptop.o
+obj-$(CONFIG_FUJITSU_TABLET)	+= fujitsu-tablet.o
 obj-$(CONFIG_PANASONIC_LAPTOP)	+= panasonic-laptop.o
 obj-$(CONFIG_INTEL_MENLOW)	+= intel_menlow.o
 obj-$(CONFIG_ACPI_WMI)		+= wmi.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index b848277..1e5290b 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -679,6 +679,32 @@
 	return AE_OK;
 }
 
+static int AMW0_set_cap_acpi_check_device_found;
+
+static acpi_status AMW0_set_cap_acpi_check_device_cb(acpi_handle handle,
+	u32 level, void *context, void **retval)
+{
+	AMW0_set_cap_acpi_check_device_found = 1;
+	return AE_OK;
+}
+
+static const struct acpi_device_id norfkill_ids[] = {
+	{ "VPC2004", 0},
+	{ "IBM0068", 0},
+	{ "LEN0068", 0},
+	{ "", 0},
+};
+
+static int AMW0_set_cap_acpi_check_device(void)
+{
+	const struct acpi_device_id *id;
+
+	for (id = norfkill_ids; id->id[0]; id++)
+		acpi_get_devices(id->id, AMW0_set_cap_acpi_check_device_cb,
+				NULL, NULL);
+	return AMW0_set_cap_acpi_check_device_found;
+}
+
 static acpi_status AMW0_set_capabilities(void)
 {
 	struct wmab_args args;
@@ -692,7 +718,9 @@
 	 * work.
 	 */
 	if (wmi_has_guid(AMW0_GUID2)) {
-		interface->capability |= ACER_CAP_WIRELESS;
+		if ((quirks != &quirk_unknown) ||
+		    !AMW0_set_cap_acpi_check_device())
+			interface->capability |= ACER_CAP_WIRELESS;
 		return AE_OK;
 	}
 
diff --git a/drivers/platform/x86/amilo-rfkill.c b/drivers/platform/x86/amilo-rfkill.c
new file mode 100644
index 0000000..19170bb
--- /dev/null
+++ b/drivers/platform/x86/amilo-rfkill.c
@@ -0,0 +1,173 @@
+/*
+ * Support for rfkill on some Fujitsu-Siemens Amilo laptops.
+ * Copyright 2011 Ben Hutchings.
+ *
+ * Based in part on the fsam7440 driver, which is:
+ * Copyright 2005 Alejandro Vidal Mata & Javier Vidal Mata.
+ * and on the fsaa1655g driver, which is:
+ * Copyright 2006 Martin Večeřa.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/dmi.h>
+#include <linux/i8042.h>
+#include <linux/io.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/rfkill.h>
+
+/*
+ * These values were obtained from disassembling and debugging the
+ * PM.exe program installed in the Fujitsu-Siemens AMILO A1655G
+ */
+#define A1655_WIFI_COMMAND	0x10C5
+#define A1655_WIFI_ON		0x25
+#define A1655_WIFI_OFF		0x45
+
+static int amilo_a1655_rfkill_set_block(void *data, bool blocked)
+{
+	u8 param = blocked ? A1655_WIFI_OFF : A1655_WIFI_ON;
+	int rc;
+
+	i8042_lock_chip();
+	rc = i8042_command(&param, A1655_WIFI_COMMAND);
+	i8042_unlock_chip();
+	return rc;
+}
+
+static const struct rfkill_ops amilo_a1655_rfkill_ops = {
+	.set_block = amilo_a1655_rfkill_set_block
+};
+
+/*
+ * These values were obtained from disassembling the PM.exe program
+ * installed in the Fujitsu-Siemens AMILO M 7440
+ */
+#define M7440_PORT1		0x118f
+#define M7440_PORT2		0x118e
+#define M7440_RADIO_ON1		0x12
+#define M7440_RADIO_ON2		0x80
+#define M7440_RADIO_OFF1	0x10
+#define M7440_RADIO_OFF2	0x00
+
+static int amilo_m7440_rfkill_set_block(void *data, bool blocked)
+{
+	u8 val1 = blocked ? M7440_RADIO_OFF1 : M7440_RADIO_ON1;
+	u8 val2 = blocked ? M7440_RADIO_OFF2 : M7440_RADIO_ON2;
+
+	outb(val1, M7440_PORT1);
+	outb(val2, M7440_PORT2);
+
+	/* Check whether the state has changed correctly */
+	if (inb(M7440_PORT1) != val1 || inb(M7440_PORT2) != val2)
+		return -EIO;
+
+	return 0;
+}
+
+static const struct rfkill_ops amilo_m7440_rfkill_ops = {
+	.set_block = amilo_m7440_rfkill_set_block
+};
+
+static const struct dmi_system_id __devinitdata amilo_rfkill_id_table[] = {
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+			DMI_MATCH(DMI_BOARD_NAME, "AMILO A1655"),
+		},
+		.driver_data = (void *)&amilo_a1655_rfkill_ops
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+			DMI_MATCH(DMI_BOARD_NAME, "AMILO M7440"),
+		},
+		.driver_data = (void *)&amilo_m7440_rfkill_ops
+	},
+	{}
+};
+
+static struct platform_device *amilo_rfkill_pdev;
+static struct rfkill *amilo_rfkill_dev;
+
+static int __devinit amilo_rfkill_probe(struct platform_device *device)
+{
+	const struct dmi_system_id *system_id =
+		dmi_first_match(amilo_rfkill_id_table);
+	int rc;
+
+	amilo_rfkill_dev = rfkill_alloc(KBUILD_MODNAME, &device->dev,
+					RFKILL_TYPE_WLAN,
+					system_id->driver_data, NULL);
+	if (!amilo_rfkill_dev)
+		return -ENOMEM;
+
+	rc = rfkill_register(amilo_rfkill_dev);
+	if (rc)
+		goto fail;
+
+	return 0;
+
+fail:
+	rfkill_destroy(amilo_rfkill_dev);
+	return rc;
+}
+
+static int amilo_rfkill_remove(struct platform_device *device)
+{
+	rfkill_unregister(amilo_rfkill_dev);
+	rfkill_destroy(amilo_rfkill_dev);
+	return 0;
+}
+
+static struct platform_driver amilo_rfkill_driver = {
+	.driver = {
+		.name	= KBUILD_MODNAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe	= amilo_rfkill_probe,
+	.remove	= amilo_rfkill_remove,
+};
+
+static int __init amilo_rfkill_init(void)
+{
+	int rc;
+
+	if (dmi_first_match(amilo_rfkill_id_table) == NULL)
+		return -ENODEV;
+
+	rc = platform_driver_register(&amilo_rfkill_driver);
+	if (rc)
+		return rc;
+
+	amilo_rfkill_pdev = platform_device_register_simple(KBUILD_MODNAME, -1,
+							    NULL, 0);
+	if (IS_ERR(amilo_rfkill_pdev)) {
+		rc = PTR_ERR(amilo_rfkill_pdev);
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	platform_driver_unregister(&amilo_rfkill_driver);
+	return rc;
+}
+
+static void __exit amilo_rfkill_exit(void)
+{
+	platform_device_unregister(amilo_rfkill_pdev);
+	platform_driver_unregister(&amilo_rfkill_driver);
+}
+
+MODULE_AUTHOR("Ben Hutchings <ben@decadent.org.uk>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(dmi, amilo_rfkill_id_table);
+
+module_init(amilo_rfkill_init);
+module_exit(amilo_rfkill_exit);
diff --git a/drivers/platform/x86/fujitsu-tablet.c b/drivers/platform/x86/fujitsu-tablet.c
new file mode 100644
index 0000000..580d80a
--- /dev/null
+++ b/drivers/platform/x86/fujitsu-tablet.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2006-2012 Robert Gerlach <khnz@gmx.de>
+ * Copyright (C) 2005-2006 Jan Rychter <jan@rychter.com>
+ *
+ * You can redistribute and/or modify this program under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * 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.,
+ * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/dmi.h>
+
+#define MODULENAME "fujitsu-tablet"
+
+#define ACPI_FUJITSU_CLASS "fujitsu"
+
+#define INVERT_TABLET_MODE_BIT      0x01
+#define FORCE_TABLET_MODE_IF_UNDOCK 0x02
+
+#define KEYMAP_LEN 16
+
+static const struct acpi_device_id fujitsu_ids[] = {
+	{ .id = "FUJ02BD" },
+	{ .id = "FUJ02BF" },
+	{ .id = "" }
+};
+
+struct fujitsu_config {
+	unsigned short keymap[KEYMAP_LEN];
+	unsigned int quirks;
+};
+
+static unsigned short keymap_Lifebook_Tseries[KEYMAP_LEN] __initconst = {
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_SCROLLDOWN,
+	KEY_SCROLLUP,
+	KEY_DIRECTION,
+	KEY_LEFTCTRL,
+	KEY_BRIGHTNESSUP,
+	KEY_BRIGHTNESSDOWN,
+	KEY_BRIGHTNESS_ZERO,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_LEFTALT
+};
+
+static unsigned short keymap_Lifebook_U810[KEYMAP_LEN] __initconst = {
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_PROG1,
+	KEY_PROG2,
+	KEY_DIRECTION,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_UP,
+	KEY_DOWN,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_LEFTCTRL,
+	KEY_LEFTALT
+};
+
+static unsigned short keymap_Stylistic_Tseries[KEYMAP_LEN] __initconst = {
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_PRINT,
+	KEY_BACKSPACE,
+	KEY_SPACE,
+	KEY_ENTER,
+	KEY_BRIGHTNESSUP,
+	KEY_BRIGHTNESSDOWN,
+	KEY_DOWN,
+	KEY_UP,
+	KEY_SCROLLUP,
+	KEY_SCROLLDOWN,
+	KEY_LEFTCTRL,
+	KEY_LEFTALT
+};
+
+static unsigned short keymap_Stylistic_ST5xxx[KEYMAP_LEN] __initconst = {
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_MAIL,
+	KEY_DIRECTION,
+	KEY_ESC,
+	KEY_ENTER,
+	KEY_BRIGHTNESSUP,
+	KEY_BRIGHTNESSDOWN,
+	KEY_DOWN,
+	KEY_UP,
+	KEY_SCROLLUP,
+	KEY_SCROLLDOWN,
+	KEY_LEFTCTRL,
+	KEY_LEFTALT
+};
+
+static struct {
+	struct input_dev *idev;
+	struct fujitsu_config config;
+	unsigned long prev_keymask;
+
+	char phys[21];
+
+	int irq;
+	int io_base;
+	int io_length;
+} fujitsu;
+
+static u8 fujitsu_ack(void)
+{
+	return inb(fujitsu.io_base + 2);
+}
+
+static u8 fujitsu_status(void)
+{
+	return inb(fujitsu.io_base + 6);
+}
+
+static u8 fujitsu_read_register(const u8 addr)
+{
+	outb(addr, fujitsu.io_base);
+	return inb(fujitsu.io_base + 4);
+}
+
+static void fujitsu_send_state(void)
+{
+	int state;
+	int dock, tablet_mode;
+
+	state = fujitsu_read_register(0xdd);
+
+	dock = state & 0x02;
+
+	if ((fujitsu.config.quirks & FORCE_TABLET_MODE_IF_UNDOCK) && (!dock)) {
+		tablet_mode = 1;
+	} else{
+		tablet_mode = state & 0x01;
+		if (fujitsu.config.quirks & INVERT_TABLET_MODE_BIT)
+			tablet_mode = !tablet_mode;
+	}
+
+	input_report_switch(fujitsu.idev, SW_DOCK, dock);
+	input_report_switch(fujitsu.idev, SW_TABLET_MODE, tablet_mode);
+	input_sync(fujitsu.idev);
+}
+
+static void fujitsu_reset(void)
+{
+	int timeout = 50;
+
+	fujitsu_ack();
+
+	while ((fujitsu_status() & 0x02) && (--timeout))
+		msleep(20);
+
+	fujitsu_send_state();
+}
+
+static int __devinit input_fujitsu_setup(struct device *parent,
+					 const char *name, const char *phys)
+{
+	struct input_dev *idev;
+	int error;
+	int i;
+
+	idev = input_allocate_device();
+	if (!idev)
+		return -ENOMEM;
+
+	idev->dev.parent = parent;
+	idev->phys = phys;
+	idev->name = name;
+	idev->id.bustype = BUS_HOST;
+	idev->id.vendor  = 0x1734;	/* Fujitsu Siemens Computer GmbH */
+	idev->id.product = 0x0001;
+	idev->id.version = 0x0101;
+
+	idev->keycode = fujitsu.config.keymap;
+	idev->keycodesize = sizeof(fujitsu.config.keymap[0]);
+	idev->keycodemax = ARRAY_SIZE(fujitsu.config.keymap);
+
+	__set_bit(EV_REP, idev->evbit);
+
+	for (i = 0; i < ARRAY_SIZE(fujitsu.config.keymap); i++)
+		if (fujitsu.config.keymap[i])
+			input_set_capability(idev, EV_KEY, fujitsu.config.keymap[i]);
+
+	input_set_capability(idev, EV_MSC, MSC_SCAN);
+
+	input_set_capability(idev, EV_SW, SW_DOCK);
+	input_set_capability(idev, EV_SW, SW_TABLET_MODE);
+
+	input_set_capability(idev, EV_SW, SW_DOCK);
+	input_set_capability(idev, EV_SW, SW_TABLET_MODE);
+
+	error = input_register_device(idev);
+	if (error) {
+		input_free_device(idev);
+		return error;
+	}
+
+	fujitsu.idev = idev;
+	return 0;
+}
+
+static void input_fujitsu_remove(void)
+{
+	input_unregister_device(fujitsu.idev);
+}
+
+static irqreturn_t fujitsu_interrupt(int irq, void *dev_id)
+{
+	unsigned long keymask, changed;
+	unsigned int keycode;
+	int pressed;
+	int i;
+
+	if (unlikely(!(fujitsu_status() & 0x01)))
+		return IRQ_NONE;
+
+	fujitsu_send_state();
+
+	keymask  = fujitsu_read_register(0xde);
+	keymask |= fujitsu_read_register(0xdf) << 8;
+	keymask ^= 0xffff;
+
+	changed = keymask ^ fujitsu.prev_keymask;
+	if (changed) {
+		fujitsu.prev_keymask = keymask;
+
+		for_each_set_bit(i, &changed, KEYMAP_LEN) {
+			keycode = fujitsu.config.keymap[i];
+			pressed = keymask & changed & BIT(i);
+
+			if (pressed)
+				input_event(fujitsu.idev, EV_MSC, MSC_SCAN, i);
+
+			input_report_key(fujitsu.idev, keycode, pressed);
+			input_sync(fujitsu.idev);
+		}
+	}
+
+	fujitsu_ack();
+	return IRQ_HANDLED;
+}
+
+static int __devinit fujitsu_dmi_default(const struct dmi_system_id *dmi)
+{
+	printk(KERN_INFO MODULENAME ": %s\n", dmi->ident);
+	memcpy(fujitsu.config.keymap, dmi->driver_data,
+			sizeof(fujitsu.config.keymap));
+	return 1;
+}
+
+static int __devinit fujitsu_dmi_stylistic(const struct dmi_system_id *dmi)
+{
+	fujitsu_dmi_default(dmi);
+	fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK;
+	fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT;
+	return 1;
+}
+
+static struct dmi_system_id dmi_ids[] __initconst = {
+	{
+		.callback = fujitsu_dmi_default,
+		.ident = "Fujitsu Siemens P/T Series",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK")
+		},
+		.driver_data = keymap_Lifebook_Tseries
+	},
+	{
+		.callback = fujitsu_dmi_default,
+		.ident = "Fujitsu Lifebook T Series",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook T")
+		},
+		.driver_data = keymap_Lifebook_Tseries
+	},
+	{
+		.callback = fujitsu_dmi_stylistic,
+		.ident = "Fujitsu Siemens Stylistic T Series",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Stylistic T")
+		},
+		.driver_data = keymap_Stylistic_Tseries
+	},
+	{
+		.callback = fujitsu_dmi_default,
+		.ident = "Fujitsu LifeBook U810",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook U810")
+		},
+		.driver_data = keymap_Lifebook_U810
+	},
+	{
+		.callback = fujitsu_dmi_stylistic,
+		.ident = "Fujitsu Siemens Stylistic ST5xxx Series",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "STYLISTIC ST5")
+		},
+		.driver_data = keymap_Stylistic_ST5xxx
+	},
+	{
+		.callback = fujitsu_dmi_stylistic,
+		.ident = "Fujitsu Siemens Stylistic ST5xxx Series",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Stylistic ST5")
+		},
+		.driver_data = keymap_Stylistic_ST5xxx
+	},
+	{
+		.callback = fujitsu_dmi_default,
+		.ident = "Unknown (using defaults)",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, ""),
+			DMI_MATCH(DMI_PRODUCT_NAME, "")
+		},
+		.driver_data = keymap_Lifebook_Tseries
+	},
+	{ NULL }
+};
+
+static acpi_status __devinit
+fujitsu_walk_resources(struct acpi_resource *res, void *data)
+{
+	switch (res->type) {
+	case ACPI_RESOURCE_TYPE_IRQ:
+		fujitsu.irq = res->data.irq.interrupts[0];
+		return AE_OK;
+
+	case ACPI_RESOURCE_TYPE_IO:
+		fujitsu.io_base = res->data.io.minimum;
+		fujitsu.io_length = res->data.io.address_length;
+		return AE_OK;
+
+	case ACPI_RESOURCE_TYPE_END_TAG:
+		if (fujitsu.irq && fujitsu.io_base)
+			return AE_OK;
+		else
+			return AE_NOT_FOUND;
+
+	default:
+		return AE_ERROR;
+	}
+}
+
+static int __devinit acpi_fujitsu_add(struct acpi_device *adev)
+{
+	acpi_status status;
+	int error;
+
+	if (!adev)
+		return -EINVAL;
+
+	status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
+			fujitsu_walk_resources, NULL);
+	if (ACPI_FAILURE(status) || !fujitsu.irq || !fujitsu.io_base)
+		return -ENODEV;
+
+	sprintf(acpi_device_name(adev), "Fujitsu %s", acpi_device_hid(adev));
+	sprintf(acpi_device_class(adev), "%s", ACPI_FUJITSU_CLASS);
+
+	snprintf(fujitsu.phys, sizeof(fujitsu.phys),
+			"%s/input0", acpi_device_hid(adev));
+
+	error = input_fujitsu_setup(&adev->dev,
+		acpi_device_name(adev), fujitsu.phys);
+	if (error)
+		return error;
+
+	if (!request_region(fujitsu.io_base, fujitsu.io_length, MODULENAME)) {
+		input_fujitsu_remove();
+		return -EBUSY;
+	}
+
+	fujitsu_reset();
+
+	error = request_irq(fujitsu.irq, fujitsu_interrupt,
+			IRQF_SHARED, MODULENAME, fujitsu_interrupt);
+	if (error) {
+		release_region(fujitsu.io_base, fujitsu.io_length);
+		input_fujitsu_remove();
+		return error;
+	}
+
+	return 0;
+}
+
+static int __devexit acpi_fujitsu_remove(struct acpi_device *adev, int type)
+{
+	free_irq(fujitsu.irq, fujitsu_interrupt);
+	release_region(fujitsu.io_base, fujitsu.io_length);
+	input_fujitsu_remove();
+	return 0;
+}
+
+static int acpi_fujitsu_resume(struct acpi_device *adev)
+{
+	fujitsu_reset();
+	return 0;
+}
+
+static struct acpi_driver acpi_fujitsu_driver = {
+	.name  = MODULENAME,
+	.class = "hotkey",
+	.ids   = fujitsu_ids,
+	.ops   = {
+		.add    = acpi_fujitsu_add,
+		.remove	= acpi_fujitsu_remove,
+		.resume = acpi_fujitsu_resume,
+	}
+};
+
+static int __init fujitsu_module_init(void)
+{
+	int error;
+
+	dmi_check_system(dmi_ids);
+
+	error = acpi_bus_register_driver(&acpi_fujitsu_driver);
+	if (error)
+		return error;
+
+	return 0;
+}
+
+static void __exit fujitsu_module_exit(void)
+{
+	acpi_bus_unregister_driver(&acpi_fujitsu_driver);
+}
+
+module_init(fujitsu_module_init);
+module_exit(fujitsu_module_exit);
+
+MODULE_AUTHOR("Robert Gerlach <khnz@gmx.de>");
+MODULE_DESCRIPTION("Fujitsu tablet pc extras driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("2.4");
+
+MODULE_DEVICE_TABLE(acpi, fujitsu_ids);
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index 05be30e..ffff8b4 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -562,8 +562,8 @@
 
 	num_sifr = acpi_pcc_get_sqty(device);
 
-	if (num_sifr > 255) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr too large"));
+	if (num_sifr < 0 || num_sifr > 255) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr out of range"));
 		return -ENODEV;
 	}
 
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 3a8daf8..459f664 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -76,6 +76,20 @@
 	help
 	  Say Y here to enable support for batteries with ds2780 chip.
 
+config BATTERY_DS2781
+	tristate "2781 battery driver"
+	depends on HAS_IOMEM
+	select W1
+	select W1_SLAVE_DS2781
+	help
+	  If you enable this you will have the DS2781 battery driver support.
+
+	  The battery monitor chip is used in many batteries/devices
+	  as the one who is responsible for charging/discharging/monitoring
+	  Li+ batteries.
+
+	  If you are unsure, say N.
+
 config BATTERY_DS2782
 	tristate "DS2782/DS2786 standalone gas-gauge"
 	depends on I2C
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index e429008..c590fa5 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -16,6 +16,7 @@
 
 obj-$(CONFIG_BATTERY_DS2760)	+= ds2760_battery.o
 obj-$(CONFIG_BATTERY_DS2780)	+= ds2780_battery.o
+obj-$(CONFIG_BATTERY_DS2781)	+= ds2781_battery.o
 obj-$(CONFIG_BATTERY_DS2782)	+= ds2782_battery.o
 obj-$(CONFIG_BATTERY_PMU)	+= pmu_battery.o
 obj-$(CONFIG_BATTERY_OLPC)	+= olpc_battery.o
diff --git a/drivers/power/ds2781_battery.c b/drivers/power/ds2781_battery.c
new file mode 100644
index 0000000..ca0d653
--- /dev/null
+++ b/drivers/power/ds2781_battery.c
@@ -0,0 +1,874 @@
+/*
+ * 1-wire client/driver for the Maxim/Dallas DS2781 Stand-Alone Fuel Gauge IC
+ *
+ * Author: Renata Sayakhova <renata@oktetlabs.ru>
+ *
+ * Based on ds2780_battery drivers
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/param.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/idr.h>
+
+#include "../w1/w1.h"
+#include "../w1/slaves/w1_ds2781.h"
+
+/* Current unit measurement in uA for a 1 milli-ohm sense resistor */
+#define DS2781_CURRENT_UNITS	1563
+/* Charge unit measurement in uAh for a 1 milli-ohm sense resistor */
+#define DS2781_CHARGE_UNITS		6250
+/* Number of bytes in user EEPROM space */
+#define DS2781_USER_EEPROM_SIZE		(DS2781_EEPROM_BLOCK0_END - \
+					DS2781_EEPROM_BLOCK0_START + 1)
+/* Number of bytes in parameter EEPROM space */
+#define DS2781_PARAM_EEPROM_SIZE	(DS2781_EEPROM_BLOCK1_END - \
+					DS2781_EEPROM_BLOCK1_START + 1)
+
+struct ds2781_device_info {
+	struct device *dev;
+	struct power_supply bat;
+	struct device *w1_dev;
+	struct task_struct *mutex_holder;
+};
+
+enum current_types {
+	CURRENT_NOW,
+	CURRENT_AVG,
+};
+
+static const char model[] = "DS2781";
+static const char manufacturer[] = "Maxim/Dallas";
+
+static inline struct ds2781_device_info *
+to_ds2781_device_info(struct power_supply *psy)
+{
+	return container_of(psy, struct ds2781_device_info, bat);
+}
+
+static inline struct power_supply *to_power_supply(struct device *dev)
+{
+	return dev_get_drvdata(dev);
+}
+
+static inline int ds2781_battery_io(struct ds2781_device_info *dev_info,
+	char *buf, int addr, size_t count, int io)
+{
+	if (dev_info->mutex_holder == current)
+		return w1_ds2781_io_nolock(dev_info->w1_dev, buf, addr,
+				count, io);
+	else
+		return w1_ds2781_io(dev_info->w1_dev, buf, addr, count, io);
+}
+
+int w1_ds2781_read(struct ds2781_device_info *dev_info, char *buf,
+		int addr, size_t count)
+{
+	return ds2781_battery_io(dev_info, buf, addr, count, 0);
+}
+
+static inline int ds2781_read8(struct ds2781_device_info *dev_info, u8 *val,
+	int addr)
+{
+	return ds2781_battery_io(dev_info, val, addr, sizeof(u8), 0);
+}
+
+static int ds2781_read16(struct ds2781_device_info *dev_info, s16 *val,
+	int addr)
+{
+	int ret;
+	u8 raw[2];
+
+	ret = ds2781_battery_io(dev_info, raw, addr, sizeof(raw), 0);
+	if (ret < 0)
+		return ret;
+
+	*val = (raw[0] << 8) | raw[1];
+
+	return 0;
+}
+
+static inline int ds2781_read_block(struct ds2781_device_info *dev_info,
+	u8 *val, int addr, size_t count)
+{
+	return ds2781_battery_io(dev_info, val, addr, count, 0);
+}
+
+static inline int ds2781_write(struct ds2781_device_info *dev_info, u8 *val,
+	int addr, size_t count)
+{
+	return ds2781_battery_io(dev_info, val, addr, count, 1);
+}
+
+static inline int ds2781_store_eeprom(struct device *dev, int addr)
+{
+	return w1_ds2781_eeprom_cmd(dev, addr, W1_DS2781_COPY_DATA);
+}
+
+static inline int ds2781_recall_eeprom(struct device *dev, int addr)
+{
+	return w1_ds2781_eeprom_cmd(dev, addr, W1_DS2781_RECALL_DATA);
+}
+
+static int ds2781_save_eeprom(struct ds2781_device_info *dev_info, int reg)
+{
+	int ret;
+
+	ret = ds2781_store_eeprom(dev_info->w1_dev, reg);
+	if (ret < 0)
+		return ret;
+
+	ret = ds2781_recall_eeprom(dev_info->w1_dev, reg);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+/* Set sense resistor value in mhos */
+static int ds2781_set_sense_register(struct ds2781_device_info *dev_info,
+	u8 conductance)
+{
+	int ret;
+
+	ret = ds2781_write(dev_info, &conductance,
+				DS2781_RSNSP, sizeof(u8));
+	if (ret < 0)
+		return ret;
+
+	return ds2781_save_eeprom(dev_info, DS2781_RSNSP);
+}
+
+/* Get RSGAIN value from 0 to 1.999 in steps of 0.001 */
+static int ds2781_get_rsgain_register(struct ds2781_device_info *dev_info,
+	u16 *rsgain)
+{
+	return ds2781_read16(dev_info, rsgain, DS2781_RSGAIN_MSB);
+}
+
+/* Set RSGAIN value from 0 to 1.999 in steps of 0.001 */
+static int ds2781_set_rsgain_register(struct ds2781_device_info *dev_info,
+	u16 rsgain)
+{
+	int ret;
+	u8 raw[] = {rsgain >> 8, rsgain & 0xFF};
+
+	ret = ds2781_write(dev_info, raw,
+				DS2781_RSGAIN_MSB, sizeof(raw));
+	if (ret < 0)
+		return ret;
+
+	return ds2781_save_eeprom(dev_info, DS2781_RSGAIN_MSB);
+}
+
+static int ds2781_get_voltage(struct ds2781_device_info *dev_info,
+	int *voltage_uV)
+{
+	int ret;
+	char val[2];
+	int voltage_raw;
+
+	ret = w1_ds2781_read(dev_info, val, DS2781_VOLT_MSB, 2 * sizeof(u8));
+	if (ret < 0)
+		return ret;
+	/*
+	 * The voltage value is located in 10 bits across the voltage MSB
+	 * and LSB registers in two's compliment form
+	 * Sign bit of the voltage value is in bit 7 of the voltage MSB register
+	 * Bits 9 - 3 of the voltage value are in bits 6 - 0 of the
+	 * voltage MSB register
+	 * Bits 2 - 0 of the voltage value are in bits 7 - 5 of the
+	 * voltage LSB register
+	 */
+	voltage_raw = (val[0] << 3) |
+		(val[1] >> 5);
+
+	/* DS2781 reports voltage in units of 9.76mV, but the battery class
+	 * reports in units of uV, so convert by multiplying by 9760. */
+	*voltage_uV = voltage_raw * 9760;
+
+	return 0;
+}
+
+static int ds2781_get_temperature(struct ds2781_device_info *dev_info,
+	int *temp)
+{
+	int ret;
+	char val[2];
+	int temp_raw;
+
+	ret = w1_ds2781_read(dev_info, val, DS2781_TEMP_MSB, 2 * sizeof(u8));
+	if (ret < 0)
+		return ret;
+	/*
+	 * The temperature value is located in 10 bits across the temperature
+	 * MSB and LSB registers in two's compliment form
+	 * Sign bit of the temperature value is in bit 7 of the temperature
+	 * MSB register
+	 * Bits 9 - 3 of the temperature value are in bits 6 - 0 of the
+	 * temperature MSB register
+	 * Bits 2 - 0 of the temperature value are in bits 7 - 5 of the
+	 * temperature LSB register
+	 */
+	temp_raw = ((val[0]) << 3) |
+		(val[1] >> 5);
+	*temp = temp_raw + (temp_raw / 4);
+
+	return 0;
+}
+
+static int ds2781_get_current(struct ds2781_device_info *dev_info,
+	enum current_types type, int *current_uA)
+{
+	int ret, sense_res;
+	s16 current_raw;
+	u8 sense_res_raw, reg_msb;
+
+	/*
+	 * The units of measurement for current are dependent on the value of
+	 * the sense resistor.
+	 */
+	ret = ds2781_read8(dev_info, &sense_res_raw, DS2781_RSNSP);
+	if (ret < 0)
+		return ret;
+
+	if (sense_res_raw == 0) {
+		dev_err(dev_info->dev, "sense resistor value is 0\n");
+		return -EINVAL;
+	}
+	sense_res = 1000 / sense_res_raw;
+
+	if (type == CURRENT_NOW)
+		reg_msb = DS2781_CURRENT_MSB;
+	else if (type == CURRENT_AVG)
+		reg_msb = DS2781_IAVG_MSB;
+	else
+		return -EINVAL;
+
+	/*
+	 * The current value is located in 16 bits across the current MSB
+	 * and LSB registers in two's compliment form
+	 * Sign bit of the current value is in bit 7 of the current MSB register
+	 * Bits 14 - 8 of the current value are in bits 6 - 0 of the current
+	 * MSB register
+	 * Bits 7 - 0 of the current value are in bits 7 - 0 of the current
+	 * LSB register
+	 */
+	ret = ds2781_read16(dev_info, &current_raw, reg_msb);
+	if (ret < 0)
+		return ret;
+
+	*current_uA = current_raw * (DS2781_CURRENT_UNITS / sense_res);
+	return 0;
+}
+
+static int ds2781_get_accumulated_current(struct ds2781_device_info *dev_info,
+	int *accumulated_current)
+{
+	int ret, sense_res;
+	s16 current_raw;
+	u8 sense_res_raw;
+
+	/*
+	 * The units of measurement for accumulated current are dependent on
+	 * the value of the sense resistor.
+	 */
+	ret = ds2781_read8(dev_info, &sense_res_raw, DS2781_RSNSP);
+	if (ret < 0)
+		return ret;
+
+	if (sense_res_raw == 0) {
+		dev_err(dev_info->dev, "sense resistor value is 0\n");
+		return -EINVAL;
+	}
+	sense_res = 1000 / sense_res_raw;
+
+	/*
+	 * The ACR value is located in 16 bits across the ACR MSB and
+	 * LSB registers
+	 * Bits 15 - 8 of the ACR value are in bits 7 - 0 of the ACR
+	 * MSB register
+	 * Bits 7 - 0 of the ACR value are in bits 7 - 0 of the ACR
+	 * LSB register
+	 */
+	ret = ds2781_read16(dev_info, &current_raw, DS2781_ACR_MSB);
+	if (ret < 0)
+		return ret;
+
+	*accumulated_current = current_raw * (DS2781_CHARGE_UNITS / sense_res);
+	return 0;
+}
+
+static int ds2781_get_capacity(struct ds2781_device_info *dev_info,
+	int *capacity)
+{
+	int ret;
+	u8 raw;
+
+	ret = ds2781_read8(dev_info, &raw, DS2781_RARC);
+	if (ret < 0)
+		return ret;
+
+	*capacity = raw;
+	return 0;
+}
+
+static int ds2781_get_status(struct ds2781_device_info *dev_info, int *status)
+{
+	int ret, current_uA, capacity;
+
+	ret = ds2781_get_current(dev_info, CURRENT_NOW, &current_uA);
+	if (ret < 0)
+		return ret;
+
+	ret = ds2781_get_capacity(dev_info, &capacity);
+	if (ret < 0)
+		return ret;
+
+	if (power_supply_am_i_supplied(&dev_info->bat)) {
+		if (capacity == 100)
+			*status = POWER_SUPPLY_STATUS_FULL;
+		else if (current_uA > 50000)
+			*status = POWER_SUPPLY_STATUS_CHARGING;
+		else
+			*status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+	} else {
+		*status = POWER_SUPPLY_STATUS_DISCHARGING;
+	}
+	return 0;
+}
+
+static int ds2781_get_charge_now(struct ds2781_device_info *dev_info,
+	int *charge_now)
+{
+	int ret;
+	u16 charge_raw;
+
+	/*
+	 * The RAAC value is located in 16 bits across the RAAC MSB and
+	 * LSB registers
+	 * Bits 15 - 8 of the RAAC value are in bits 7 - 0 of the RAAC
+	 * MSB register
+	 * Bits 7 - 0 of the RAAC value are in bits 7 - 0 of the RAAC
+	 * LSB register
+	 */
+	ret = ds2781_read16(dev_info, &charge_raw, DS2781_RAAC_MSB);
+	if (ret < 0)
+		return ret;
+
+	*charge_now = charge_raw * 1600;
+	return 0;
+}
+
+static int ds2781_get_control_register(struct ds2781_device_info *dev_info,
+	u8 *control_reg)
+{
+	return ds2781_read8(dev_info, control_reg, DS2781_CONTROL);
+}
+
+static int ds2781_set_control_register(struct ds2781_device_info *dev_info,
+	u8 control_reg)
+{
+	int ret;
+
+	ret = ds2781_write(dev_info, &control_reg,
+				DS2781_CONTROL, sizeof(u8));
+	if (ret < 0)
+		return ret;
+
+	return ds2781_save_eeprom(dev_info, DS2781_CONTROL);
+}
+
+static int ds2781_battery_get_property(struct power_supply *psy,
+	enum power_supply_property psp,
+	union power_supply_propval *val)
+{
+	int ret = 0;
+	struct ds2781_device_info *dev_info = to_ds2781_device_info(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		ret = ds2781_get_voltage(dev_info, &val->intval);
+		break;
+
+	case POWER_SUPPLY_PROP_TEMP:
+		ret = ds2781_get_temperature(dev_info, &val->intval);
+		break;
+
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = model;
+		break;
+
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		val->strval = manufacturer;
+		break;
+
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		ret = ds2781_get_current(dev_info, CURRENT_NOW, &val->intval);
+		break;
+
+	case POWER_SUPPLY_PROP_CURRENT_AVG:
+		ret = ds2781_get_current(dev_info, CURRENT_AVG, &val->intval);
+		break;
+
+	case POWER_SUPPLY_PROP_STATUS:
+		ret = ds2781_get_status(dev_info, &val->intval);
+		break;
+
+	case POWER_SUPPLY_PROP_CAPACITY:
+		ret = ds2781_get_capacity(dev_info, &val->intval);
+		break;
+
+	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+		ret = ds2781_get_accumulated_current(dev_info, &val->intval);
+		break;
+
+	case POWER_SUPPLY_PROP_CHARGE_NOW:
+		ret = ds2781_get_charge_now(dev_info, &val->intval);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static enum power_supply_property ds2781_battery_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CURRENT_AVG,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_CHARGE_COUNTER,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
+};
+
+static ssize_t ds2781_get_pmod_enabled(struct device *dev,
+	struct device_attribute *attr,
+	char *buf)
+{
+	int ret;
+	u8 control_reg;
+	struct power_supply *psy = to_power_supply(dev);
+	struct ds2781_device_info *dev_info = to_ds2781_device_info(psy);
+
+	/* Get power mode */
+	ret = ds2781_get_control_register(dev_info, &control_reg);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n",
+		 !!(control_reg & DS2781_CONTROL_PMOD));
+}
+
+static ssize_t ds2781_set_pmod_enabled(struct device *dev,
+	struct device_attribute *attr,
+	const char *buf,
+	size_t count)
+{
+	int ret;
+	u8 control_reg, new_setting;
+	struct power_supply *psy = to_power_supply(dev);
+	struct ds2781_device_info *dev_info = to_ds2781_device_info(psy);
+
+	/* Set power mode */
+	ret = ds2781_get_control_register(dev_info, &control_reg);
+	if (ret < 0)
+		return ret;
+
+	ret = kstrtou8(buf, 0, &new_setting);
+	if (ret < 0)
+		return ret;
+
+	if ((new_setting != 0) && (new_setting != 1)) {
+		dev_err(dev_info->dev, "Invalid pmod setting (0 or 1)\n");
+		return -EINVAL;
+	}
+
+	if (new_setting)
+		control_reg |= DS2781_CONTROL_PMOD;
+	else
+		control_reg &= ~DS2781_CONTROL_PMOD;
+
+	ret = ds2781_set_control_register(dev_info, control_reg);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t ds2781_get_sense_resistor_value(struct device *dev,
+	struct device_attribute *attr,
+	char *buf)
+{
+	int ret;
+	u8 sense_resistor;
+	struct power_supply *psy = to_power_supply(dev);
+	struct ds2781_device_info *dev_info = to_ds2781_device_info(psy);
+
+	ret = ds2781_read8(dev_info, &sense_resistor, DS2781_RSNSP);
+	if (ret < 0)
+		return ret;
+
+	ret = sprintf(buf, "%d\n", sense_resistor);
+	return ret;
+}
+
+static ssize_t ds2781_set_sense_resistor_value(struct device *dev,
+	struct device_attribute *attr,
+	const char *buf,
+	size_t count)
+{
+	int ret;
+	u8 new_setting;
+	struct power_supply *psy = to_power_supply(dev);
+	struct ds2781_device_info *dev_info = to_ds2781_device_info(psy);
+
+	ret = kstrtou8(buf, 0, &new_setting);
+	if (ret < 0)
+		return ret;
+
+	ret = ds2781_set_sense_register(dev_info, new_setting);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t ds2781_get_rsgain_setting(struct device *dev,
+	struct device_attribute *attr,
+	char *buf)
+{
+	int ret;
+	u16 rsgain;
+	struct power_supply *psy = to_power_supply(dev);
+	struct ds2781_device_info *dev_info = to_ds2781_device_info(psy);
+
+	ret = ds2781_get_rsgain_register(dev_info, &rsgain);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", rsgain);
+}
+
+static ssize_t ds2781_set_rsgain_setting(struct device *dev,
+	struct device_attribute *attr,
+	const char *buf,
+	size_t count)
+{
+	int ret;
+	u16 new_setting;
+	struct power_supply *psy = to_power_supply(dev);
+	struct ds2781_device_info *dev_info = to_ds2781_device_info(psy);
+
+	ret = kstrtou16(buf, 0, &new_setting);
+	if (ret < 0)
+		return ret;
+
+	/* Gain can only be from 0 to 1.999 in steps of .001 */
+	if (new_setting > 1999) {
+		dev_err(dev_info->dev, "Invalid rsgain setting (0 - 1999)\n");
+		return -EINVAL;
+	}
+
+	ret = ds2781_set_rsgain_register(dev_info, new_setting);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t ds2781_get_pio_pin(struct device *dev,
+	struct device_attribute *attr,
+	char *buf)
+{
+	int ret;
+	u8 sfr;
+	struct power_supply *psy = to_power_supply(dev);
+	struct ds2781_device_info *dev_info = to_ds2781_device_info(psy);
+
+	ret = ds2781_read8(dev_info, &sfr, DS2781_SFR);
+	if (ret < 0)
+		return ret;
+
+	ret = sprintf(buf, "%d\n", sfr & DS2781_SFR_PIOSC);
+	return ret;
+}
+
+static ssize_t ds2781_set_pio_pin(struct device *dev,
+	struct device_attribute *attr,
+	const char *buf,
+	size_t count)
+{
+	int ret;
+	u8 new_setting;
+	struct power_supply *psy = to_power_supply(dev);
+	struct ds2781_device_info *dev_info = to_ds2781_device_info(psy);
+
+	ret = kstrtou8(buf, 0, &new_setting);
+	if (ret < 0)
+		return ret;
+
+	if ((new_setting != 0) && (new_setting != 1)) {
+		dev_err(dev_info->dev, "Invalid pio_pin setting (0 or 1)\n");
+		return -EINVAL;
+	}
+
+	ret = ds2781_write(dev_info, &new_setting,
+				DS2781_SFR, sizeof(u8));
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t ds2781_read_param_eeprom_bin(struct file *filp,
+				struct kobject *kobj,
+				struct bin_attribute *bin_attr,
+				char *buf, loff_t off, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct power_supply *psy = to_power_supply(dev);
+	struct ds2781_device_info *dev_info = to_ds2781_device_info(psy);
+
+	count = min_t(loff_t, count,
+		DS2781_EEPROM_BLOCK1_END -
+		DS2781_EEPROM_BLOCK1_START + 1 - off);
+
+	return ds2781_read_block(dev_info, buf,
+				DS2781_EEPROM_BLOCK1_START + off, count);
+}
+
+static ssize_t ds2781_write_param_eeprom_bin(struct file *filp,
+				struct kobject *kobj,
+				struct bin_attribute *bin_attr,
+				char *buf, loff_t off, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct power_supply *psy = to_power_supply(dev);
+	struct ds2781_device_info *dev_info = to_ds2781_device_info(psy);
+	int ret;
+
+	count = min_t(loff_t, count,
+		DS2781_EEPROM_BLOCK1_END -
+		DS2781_EEPROM_BLOCK1_START + 1 - off);
+
+	ret = ds2781_write(dev_info, buf,
+				DS2781_EEPROM_BLOCK1_START + off, count);
+	if (ret < 0)
+		return ret;
+
+	ret = ds2781_save_eeprom(dev_info, DS2781_EEPROM_BLOCK1_START);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static struct bin_attribute ds2781_param_eeprom_bin_attr = {
+	.attr = {
+		.name = "param_eeprom",
+		.mode = S_IRUGO | S_IWUSR,
+	},
+	.size = DS2781_EEPROM_BLOCK1_END - DS2781_EEPROM_BLOCK1_START + 1,
+	.read = ds2781_read_param_eeprom_bin,
+	.write = ds2781_write_param_eeprom_bin,
+};
+
+static ssize_t ds2781_read_user_eeprom_bin(struct file *filp,
+				struct kobject *kobj,
+				struct bin_attribute *bin_attr,
+				char *buf, loff_t off, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct power_supply *psy = to_power_supply(dev);
+	struct ds2781_device_info *dev_info = to_ds2781_device_info(psy);
+
+	count = min_t(loff_t, count,
+		DS2781_EEPROM_BLOCK0_END -
+		DS2781_EEPROM_BLOCK0_START + 1 - off);
+
+	return ds2781_read_block(dev_info, buf,
+				DS2781_EEPROM_BLOCK0_START + off, count);
+
+}
+
+static ssize_t ds2781_write_user_eeprom_bin(struct file *filp,
+				struct kobject *kobj,
+				struct bin_attribute *bin_attr,
+				char *buf, loff_t off, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct power_supply *psy = to_power_supply(dev);
+	struct ds2781_device_info *dev_info = to_ds2781_device_info(psy);
+	int ret;
+
+	count = min_t(loff_t, count,
+		DS2781_EEPROM_BLOCK0_END -
+		DS2781_EEPROM_BLOCK0_START + 1 - off);
+
+	ret = ds2781_write(dev_info, buf,
+				DS2781_EEPROM_BLOCK0_START + off, count);
+	if (ret < 0)
+		return ret;
+
+	ret = ds2781_save_eeprom(dev_info, DS2781_EEPROM_BLOCK0_START);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static struct bin_attribute ds2781_user_eeprom_bin_attr = {
+	.attr = {
+		.name = "user_eeprom",
+		.mode = S_IRUGO | S_IWUSR,
+	},
+	.size = DS2781_EEPROM_BLOCK0_END - DS2781_EEPROM_BLOCK0_START + 1,
+	.read = ds2781_read_user_eeprom_bin,
+	.write = ds2781_write_user_eeprom_bin,
+};
+
+static DEVICE_ATTR(pmod_enabled, S_IRUGO | S_IWUSR, ds2781_get_pmod_enabled,
+	ds2781_set_pmod_enabled);
+static DEVICE_ATTR(sense_resistor_value, S_IRUGO | S_IWUSR,
+	ds2781_get_sense_resistor_value, ds2781_set_sense_resistor_value);
+static DEVICE_ATTR(rsgain_setting, S_IRUGO | S_IWUSR, ds2781_get_rsgain_setting,
+	ds2781_set_rsgain_setting);
+static DEVICE_ATTR(pio_pin, S_IRUGO | S_IWUSR, ds2781_get_pio_pin,
+	ds2781_set_pio_pin);
+
+
+static struct attribute *ds2781_attributes[] = {
+	&dev_attr_pmod_enabled.attr,
+	&dev_attr_sense_resistor_value.attr,
+	&dev_attr_rsgain_setting.attr,
+	&dev_attr_pio_pin.attr,
+	NULL
+};
+
+static const struct attribute_group ds2781_attr_group = {
+	.attrs = ds2781_attributes,
+};
+
+static int __devinit ds2781_battery_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct ds2781_device_info *dev_info;
+
+	dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL);
+	if (!dev_info) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	platform_set_drvdata(pdev, dev_info);
+
+	dev_info->dev			= &pdev->dev;
+	dev_info->w1_dev		= pdev->dev.parent;
+	dev_info->bat.name		= dev_name(&pdev->dev);
+	dev_info->bat.type		= POWER_SUPPLY_TYPE_BATTERY;
+	dev_info->bat.properties	= ds2781_battery_props;
+	dev_info->bat.num_properties	= ARRAY_SIZE(ds2781_battery_props);
+	dev_info->bat.get_property	= ds2781_battery_get_property;
+	dev_info->mutex_holder		= current;
+
+	ret = power_supply_register(&pdev->dev, &dev_info->bat);
+	if (ret) {
+		dev_err(dev_info->dev, "failed to register battery\n");
+		goto fail_free_info;
+	}
+
+	ret = sysfs_create_group(&dev_info->bat.dev->kobj, &ds2781_attr_group);
+	if (ret) {
+		dev_err(dev_info->dev, "failed to create sysfs group\n");
+		goto fail_unregister;
+	}
+
+	ret = sysfs_create_bin_file(&dev_info->bat.dev->kobj,
+					&ds2781_param_eeprom_bin_attr);
+	if (ret) {
+		dev_err(dev_info->dev,
+				"failed to create param eeprom bin file");
+		goto fail_remove_group;
+	}
+
+	ret = sysfs_create_bin_file(&dev_info->bat.dev->kobj,
+					&ds2781_user_eeprom_bin_attr);
+	if (ret) {
+		dev_err(dev_info->dev,
+				"failed to create user eeprom bin file");
+		goto fail_remove_bin_file;
+	}
+
+	dev_info->mutex_holder = NULL;
+
+	return 0;
+
+fail_remove_bin_file:
+	sysfs_remove_bin_file(&dev_info->bat.dev->kobj,
+				&ds2781_param_eeprom_bin_attr);
+fail_remove_group:
+	sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2781_attr_group);
+fail_unregister:
+	power_supply_unregister(&dev_info->bat);
+fail_free_info:
+	kfree(dev_info);
+fail:
+	return ret;
+}
+
+static int __devexit ds2781_battery_remove(struct platform_device *pdev)
+{
+	struct ds2781_device_info *dev_info = platform_get_drvdata(pdev);
+
+	dev_info->mutex_holder = current;
+
+	/* remove attributes */
+	sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2781_attr_group);
+
+	power_supply_unregister(&dev_info->bat);
+
+	kfree(dev_info);
+	return 0;
+}
+
+static struct platform_driver ds2781_battery_driver = {
+	.driver = {
+		.name = "ds2781-battery",
+	},
+	.probe	  = ds2781_battery_probe,
+	.remove   = __devexit_p(ds2781_battery_remove),
+};
+
+static int __init ds2781_battery_init(void)
+{
+	return platform_driver_register(&ds2781_battery_driver);
+}
+
+static void __exit ds2781_battery_exit(void)
+{
+	platform_driver_unregister(&ds2781_battery_driver);
+}
+
+module_init(ds2781_battery_init);
+module_exit(ds2781_battery_exit);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Renata Sayakhova <renata@oktetlabs.ru>");
+MODULE_DESCRIPTION("Maxim/Dallas DS2781 Stand-Alone Fuel Gauage IC driver");
+MODULE_ALIAS("platform:ds2781-battery");
+
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c
index b806667..1289a5f 100644
--- a/drivers/power/isp1704_charger.c
+++ b/drivers/power/isp1704_charger.c
@@ -56,7 +56,7 @@
 struct isp1704_charger {
 	struct device		*dev;
 	struct power_supply	psy;
-	struct otg_transceiver	*otg;
+	struct usb_phy		*phy;
 	struct notifier_block	nb;
 	struct work_struct	work;
 
@@ -71,6 +71,16 @@
 	unsigned		max_power;
 };
 
+static inline int isp1704_read(struct isp1704_charger *isp, u32 reg)
+{
+	return usb_phy_io_read(isp->phy, reg);
+}
+
+static inline int isp1704_write(struct isp1704_charger *isp, u32 val, u32 reg)
+{
+	return usb_phy_io_write(isp->phy, val, reg);
+}
+
 /*
  * Disable/enable the power from the isp1704 if a function for it
  * has been provided with platform data.
@@ -97,31 +107,31 @@
 	u8 otg_ctrl;
 	int type = POWER_SUPPLY_TYPE_USB_DCP;
 
-	func_ctrl = otg_io_read(isp->otg, ULPI_FUNC_CTRL);
-	otg_ctrl = otg_io_read(isp->otg, ULPI_OTG_CTRL);
+	func_ctrl = isp1704_read(isp, ULPI_FUNC_CTRL);
+	otg_ctrl = isp1704_read(isp, ULPI_OTG_CTRL);
 
 	/* disable pulldowns */
 	reg = ULPI_OTG_CTRL_DM_PULLDOWN | ULPI_OTG_CTRL_DP_PULLDOWN;
-	otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), reg);
+	isp1704_write(isp, ULPI_CLR(ULPI_OTG_CTRL), reg);
 
 	/* full speed */
-	otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
+	isp1704_write(isp, ULPI_CLR(ULPI_FUNC_CTRL),
 			ULPI_FUNC_CTRL_XCVRSEL_MASK);
-	otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL),
+	isp1704_write(isp, ULPI_SET(ULPI_FUNC_CTRL),
 			ULPI_FUNC_CTRL_FULL_SPEED);
 
 	/* Enable strong pull-up on DP (1.5K) and reset */
 	reg = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET;
-	otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), reg);
+	isp1704_write(isp, ULPI_SET(ULPI_FUNC_CTRL), reg);
 	usleep_range(1000, 2000);
 
-	reg = otg_io_read(isp->otg, ULPI_DEBUG);
+	reg = isp1704_read(isp, ULPI_DEBUG);
 	if ((reg & 3) != 3)
 		type = POWER_SUPPLY_TYPE_USB_CDP;
 
 	/* recover original state */
-	otg_io_write(isp->otg, ULPI_FUNC_CTRL, func_ctrl);
-	otg_io_write(isp->otg, ULPI_OTG_CTRL, otg_ctrl);
+	isp1704_write(isp, ULPI_FUNC_CTRL, func_ctrl);
+	isp1704_write(isp, ULPI_OTG_CTRL, otg_ctrl);
 
 	return type;
 }
@@ -136,28 +146,28 @@
 	u8	r;
 
 	/* Reset the transceiver */
-	r = otg_io_read(isp->otg, ULPI_FUNC_CTRL);
+	r = isp1704_read(isp, ULPI_FUNC_CTRL);
 	r |= ULPI_FUNC_CTRL_RESET;
-	otg_io_write(isp->otg, ULPI_FUNC_CTRL, r);
+	isp1704_write(isp, ULPI_FUNC_CTRL, r);
 	usleep_range(1000, 2000);
 
 	/* Set normal mode */
 	r &= ~(ULPI_FUNC_CTRL_RESET | ULPI_FUNC_CTRL_OPMODE_MASK);
-	otg_io_write(isp->otg, ULPI_FUNC_CTRL, r);
+	isp1704_write(isp, ULPI_FUNC_CTRL, r);
 
 	/* Clear the DP and DM pull-down bits */
 	r = ULPI_OTG_CTRL_DP_PULLDOWN | ULPI_OTG_CTRL_DM_PULLDOWN;
-	otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), r);
+	isp1704_write(isp, ULPI_CLR(ULPI_OTG_CTRL), r);
 
 	/* Enable strong pull-up on DP (1.5K) and reset */
 	r = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET;
-	otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), r);
+	isp1704_write(isp, ULPI_SET(ULPI_FUNC_CTRL), r);
 	usleep_range(1000, 2000);
 
 	/* Read the line state */
-	if (!otg_io_read(isp->otg, ULPI_DEBUG)) {
+	if (!isp1704_read(isp, ULPI_DEBUG)) {
 		/* Disable strong pull-up on DP (1.5K) */
-		otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
+		isp1704_write(isp, ULPI_CLR(ULPI_FUNC_CTRL),
 				ULPI_FUNC_CTRL_TERMSELECT);
 		return 1;
 	}
@@ -165,23 +175,23 @@
 	/* Is it a charger or PS/2 connection */
 
 	/* Enable weak pull-up resistor on DP */
-	otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL),
+	isp1704_write(isp, ULPI_SET(ISP1704_PWR_CTRL),
 			ISP1704_PWR_CTRL_DP_WKPU_EN);
 
 	/* Disable strong pull-up on DP (1.5K) */
-	otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
+	isp1704_write(isp, ULPI_CLR(ULPI_FUNC_CTRL),
 			ULPI_FUNC_CTRL_TERMSELECT);
 
 	/* Enable weak pull-down resistor on DM */
-	otg_io_write(isp->otg, ULPI_SET(ULPI_OTG_CTRL),
+	isp1704_write(isp, ULPI_SET(ULPI_OTG_CTRL),
 			ULPI_OTG_CTRL_DM_PULLDOWN);
 
 	/* It's a charger if the line states are clear */
-	if (!(otg_io_read(isp->otg, ULPI_DEBUG)))
+	if (!(isp1704_read(isp, ULPI_DEBUG)))
 		ret = 1;
 
 	/* Disable weak pull-up resistor on DP */
-	otg_io_write(isp->otg, ULPI_CLR(ISP1704_PWR_CTRL),
+	isp1704_write(isp, ULPI_CLR(ISP1704_PWR_CTRL),
 			ISP1704_PWR_CTRL_DP_WKPU_EN);
 
 	return ret;
@@ -193,14 +203,14 @@
 	u8		pwr_ctrl;
 	int		ret = 0;
 
-	pwr_ctrl = otg_io_read(isp->otg, ISP1704_PWR_CTRL);
+	pwr_ctrl = isp1704_read(isp, ISP1704_PWR_CTRL);
 
 	/* set SW control bit in PWR_CTRL register */
-	otg_io_write(isp->otg, ISP1704_PWR_CTRL,
+	isp1704_write(isp, ISP1704_PWR_CTRL,
 			ISP1704_PWR_CTRL_SWCTRL);
 
 	/* enable manual charger detection */
-	otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL),
+	isp1704_write(isp, ULPI_SET(ISP1704_PWR_CTRL),
 			ISP1704_PWR_CTRL_SWCTRL
 			| ISP1704_PWR_CTRL_DPVSRC_EN);
 	usleep_range(1000, 2000);
@@ -208,7 +218,7 @@
 	timeout = jiffies + msecs_to_jiffies(300);
 	do {
 		/* Check if there is a charger */
-		if (otg_io_read(isp->otg, ISP1704_PWR_CTRL)
+		if (isp1704_read(isp, ISP1704_PWR_CTRL)
 				& ISP1704_PWR_CTRL_VDAT_DET) {
 			ret = isp1704_charger_verify(isp);
 			break;
@@ -216,7 +226,7 @@
 	} while (!time_after(jiffies, timeout) && isp->online);
 
 	/* recover original state */
-	otg_io_write(isp->otg, ISP1704_PWR_CTRL, pwr_ctrl);
+	isp1704_write(isp, ISP1704_PWR_CTRL, pwr_ctrl);
 
 	return ret;
 }
@@ -264,8 +274,8 @@
 		case POWER_SUPPLY_TYPE_USB:
 		default:
 			/* enable data pullups */
-			if (isp->otg->gadget)
-				usb_gadget_connect(isp->otg->gadget);
+			if (isp->phy->otg->gadget)
+				usb_gadget_connect(isp->phy->otg->gadget);
 		}
 		break;
 	case USB_EVENT_NONE:
@@ -283,8 +293,8 @@
 		 * chargers. The pullups may be enabled elsewhere, so this can
 		 * not be the final solution.
 		 */
-		if (isp->otg->gadget)
-			usb_gadget_disconnect(isp->otg->gadget);
+		if (isp->phy->otg->gadget)
+			usb_gadget_disconnect(isp->phy->otg->gadget);
 
 		isp1704_charger_set_power(isp, 0);
 		break;
@@ -364,11 +374,11 @@
 	int ret = -ENODEV;
 
 	/* Test ULPI interface */
-	ret = otg_io_write(isp->otg, ULPI_SCRATCH, 0xaa);
+	ret = isp1704_write(isp, ULPI_SCRATCH, 0xaa);
 	if (ret < 0)
 		return ret;
 
-	ret = otg_io_read(isp->otg, ULPI_SCRATCH);
+	ret = isp1704_read(isp, ULPI_SCRATCH);
 	if (ret < 0)
 		return ret;
 
@@ -376,13 +386,13 @@
 		return -ENODEV;
 
 	/* Verify the product and vendor id matches */
-	vendor = otg_io_read(isp->otg, ULPI_VENDOR_ID_LOW);
-	vendor |= otg_io_read(isp->otg, ULPI_VENDOR_ID_HIGH) << 8;
+	vendor = isp1704_read(isp, ULPI_VENDOR_ID_LOW);
+	vendor |= isp1704_read(isp, ULPI_VENDOR_ID_HIGH) << 8;
 	if (vendor != NXP_VENDOR_ID)
 		return -ENODEV;
 
-	product = otg_io_read(isp->otg, ULPI_PRODUCT_ID_LOW);
-	product |= otg_io_read(isp->otg, ULPI_PRODUCT_ID_HIGH) << 8;
+	product = isp1704_read(isp, ULPI_PRODUCT_ID_LOW);
+	product |= isp1704_read(isp, ULPI_PRODUCT_ID_HIGH) << 8;
 
 	for (i = 0; i < ARRAY_SIZE(isp170x_id); i++) {
 		if (product == isp170x_id[i]) {
@@ -405,8 +415,8 @@
 	if (!isp)
 		return -ENOMEM;
 
-	isp->otg = otg_get_transceiver();
-	if (!isp->otg)
+	isp->phy = usb_get_transceiver();
+	if (!isp->phy)
 		goto fail0;
 
 	isp->dev = &pdev->dev;
@@ -429,14 +439,14 @@
 		goto fail1;
 
 	/*
-	 * REVISIT: using work in order to allow the otg notifications to be
+	 * REVISIT: using work in order to allow the usb notifications to be
 	 * made atomically in the future.
 	 */
 	INIT_WORK(&isp->work, isp1704_charger_work);
 
 	isp->nb.notifier_call = isp1704_notifier_call;
 
-	ret = otg_register_notifier(isp->otg, &isp->nb);
+	ret = usb_register_notifier(isp->phy, &isp->nb);
 	if (ret)
 		goto fail2;
 
@@ -449,13 +459,13 @@
 	 * enumerated. The charger driver should be always loaded before any
 	 * gadget is loaded.
 	 */
-	if (isp->otg->gadget)
-		usb_gadget_disconnect(isp->otg->gadget);
+	if (isp->phy->otg->gadget)
+		usb_gadget_disconnect(isp->phy->otg->gadget);
 
 	/* Detect charger if VBUS is valid (the cable was already plugged). */
-	ret = otg_io_read(isp->otg, ULPI_USB_INT_STS);
+	ret = isp1704_read(isp, ULPI_USB_INT_STS);
 	isp1704_charger_set_power(isp, 0);
-	if ((ret & ULPI_INT_VBUS_VALID) && !isp->otg->default_a) {
+	if ((ret & ULPI_INT_VBUS_VALID) && !isp->phy->otg->default_a) {
 		isp->event = USB_EVENT_VBUS;
 		schedule_work(&isp->work);
 	}
@@ -464,7 +474,7 @@
 fail2:
 	power_supply_unregister(&isp->psy);
 fail1:
-	otg_put_transceiver(isp->otg);
+	usb_put_transceiver(isp->phy);
 fail0:
 	kfree(isp);
 
@@ -477,9 +487,9 @@
 {
 	struct isp1704_charger *isp = platform_get_drvdata(pdev);
 
-	otg_unregister_notifier(isp->otg, &isp->nb);
+	usb_unregister_notifier(isp->phy, &isp->nb);
 	power_supply_unregister(&isp->psy);
-	otg_put_transceiver(isp->otg);
+	usb_put_transceiver(isp->phy);
 	isp1704_charger_set_power(isp, 0);
 	kfree(isp);
 
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c
index fd49689..214468f 100644
--- a/drivers/power/pda_power.c
+++ b/drivers/power/pda_power.c
@@ -40,7 +40,7 @@
 static int polling;
 
 #ifdef CONFIG_USB_OTG_UTILS
-static struct otg_transceiver *transceiver;
+static struct usb_phy *transceiver;
 static struct notifier_block otg_nb;
 #endif
 
@@ -321,7 +321,7 @@
 	}
 
 #ifdef CONFIG_USB_OTG_UTILS
-	transceiver = otg_get_transceiver();
+	transceiver = usb_get_transceiver();
 	if (transceiver && !pdata->is_usb_online) {
 		pdata->is_usb_online = otg_is_usb_online;
 	}
@@ -375,7 +375,7 @@
 #ifdef CONFIG_USB_OTG_UTILS
 	if (transceiver && pdata->use_otg_notifier) {
 		otg_nb.notifier_call = otg_handle_notification;
-		ret = otg_register_notifier(transceiver, &otg_nb);
+		ret = usb_register_notifier(transceiver, &otg_nb);
 		if (ret) {
 			dev_err(dev, "failure to register otg notifier\n");
 			goto otg_reg_notifier_failed;
@@ -409,7 +409,7 @@
 		free_irq(ac_irq->start, &pda_psy_ac);
 #ifdef CONFIG_USB_OTG_UTILS
 	if (transceiver)
-		otg_put_transceiver(transceiver);
+		usb_put_transceiver(transceiver);
 #endif
 ac_irq_failed:
 	if (pdata->is_ac_online)
@@ -444,7 +444,7 @@
 		power_supply_unregister(&pda_psy_ac);
 #ifdef CONFIG_USB_OTG_UTILS
 	if (transceiver)
-		otg_put_transceiver(transceiver);
+		usb_put_transceiver(transceiver);
 #endif
 	if (ac_draw) {
 		regulator_put(ac_draw);
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 54b9198..fdad850 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -69,8 +69,8 @@
 	struct device		*dev;
 	struct power_supply	ac;
 	struct power_supply	usb;
-	struct otg_transceiver	*transceiver;
-	struct notifier_block	otg_nb;
+	struct usb_phy		*transceiver;
+	struct notifier_block	usb_nb;
 	struct work_struct	work;
 	int			irq_chg;
 	int			irq_bci;
@@ -279,7 +279,7 @@
 static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val,
 			       void *priv)
 {
-	struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb);
+	struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, usb_nb);
 
 	dev_dbg(bci->dev, "OTG notify %lu\n", val);
 
@@ -479,10 +479,10 @@
 
 	INIT_WORK(&bci->work, twl4030_bci_usb_work);
 
-	bci->transceiver = otg_get_transceiver();
+	bci->transceiver = usb_get_transceiver();
 	if (bci->transceiver != NULL) {
-		bci->otg_nb.notifier_call = twl4030_bci_usb_ncb;
-		otg_register_notifier(bci->transceiver, &bci->otg_nb);
+		bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
+		usb_register_notifier(bci->transceiver, &bci->usb_nb);
 	}
 
 	/* Enable interrupts now. */
@@ -508,8 +508,8 @@
 
 fail_unmask_interrupts:
 	if (bci->transceiver != NULL) {
-		otg_unregister_notifier(bci->transceiver, &bci->otg_nb);
-		otg_put_transceiver(bci->transceiver);
+		usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
+		usb_put_transceiver(bci->transceiver);
 	}
 	free_irq(bci->irq_bci, bci);
 fail_bci_irq:
@@ -539,8 +539,8 @@
 			 TWL4030_INTERRUPTS_BCIIMR2A);
 
 	if (bci->transceiver != NULL) {
-		otg_unregister_notifier(bci->transceiver, &bci->otg_nb);
-		otg_put_transceiver(bci->transceiver);
+		usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
+		usb_put_transceiver(bci->transceiver);
 	}
 	free_irq(bci->irq_bci, bci);
 	free_irq(bci->irq_chg, bci);
diff --git a/drivers/rapidio/devices/tsi721.h b/drivers/rapidio/devices/tsi721.h
index 822e54c..1c226b3 100644
--- a/drivers/rapidio/devices/tsi721.h
+++ b/drivers/rapidio/devices/tsi721.h
@@ -118,34 +118,34 @@
 
 #define TSI721_IDB_ENTRY_SIZE	64
 
-#define TSI721_IDQ_CTL(x)	(0x20000 + (x) * 1000)
+#define TSI721_IDQ_CTL(x)	(0x20000 + (x) * 0x1000)
 #define TSI721_IDQ_SUSPEND	0x00000002
 #define TSI721_IDQ_INIT		0x00000001
 
-#define TSI721_IDQ_STS(x)	(0x20004 + (x) * 1000)
+#define TSI721_IDQ_STS(x)	(0x20004 + (x) * 0x1000)
 #define TSI721_IDQ_RUN		0x00200000
 
-#define TSI721_IDQ_MASK(x)	(0x20008 + (x) * 1000)
+#define TSI721_IDQ_MASK(x)	(0x20008 + (x) * 0x1000)
 #define TSI721_IDQ_MASK_MASK	0xffff0000
 #define TSI721_IDQ_MASK_PATT	0x0000ffff
 
-#define TSI721_IDQ_RP(x)	(0x2000c + (x) * 1000)
+#define TSI721_IDQ_RP(x)	(0x2000c + (x) * 0x1000)
 #define TSI721_IDQ_RP_PTR	0x0007ffff
 
-#define TSI721_IDQ_WP(x)	(0x20010 + (x) * 1000)
+#define TSI721_IDQ_WP(x)	(0x20010 + (x) * 0x1000)
 #define TSI721_IDQ_WP_PTR	0x0007ffff
 
-#define TSI721_IDQ_BASEL(x)	(0x20014 + (x) * 1000)
+#define TSI721_IDQ_BASEL(x)	(0x20014 + (x) * 0x1000)
 #define TSI721_IDQ_BASEL_ADDR	0xffffffc0
-#define TSI721_IDQ_BASEU(x)	(0x20018 + (x) * 1000)
-#define TSI721_IDQ_SIZE(x)	(0x2001c + (x) * 1000)
+#define TSI721_IDQ_BASEU(x)	(0x20018 + (x) * 0x1000)
+#define TSI721_IDQ_SIZE(x)	(0x2001c + (x) * 0x1000)
 #define TSI721_IDQ_SIZE_VAL(size)	(__fls(size) - 4)
 #define TSI721_IDQ_SIZE_MIN	512
 #define TSI721_IDQ_SIZE_MAX	(512 * 1024)
 
-#define TSI721_SR_CHINT(x)	(0x20040 + (x) * 1000)
-#define TSI721_SR_CHINTE(x)	(0x20044 + (x) * 1000)
-#define TSI721_SR_CHINTSET(x)	(0x20048 + (x) * 1000)
+#define TSI721_SR_CHINT(x)	(0x20040 + (x) * 0x1000)
+#define TSI721_SR_CHINTE(x)	(0x20044 + (x) * 0x1000)
+#define TSI721_SR_CHINTSET(x)	(0x20048 + (x) * 0x1000)
 #define TSI721_SR_CHINT_ODBOK	0x00000020
 #define TSI721_SR_CHINT_IDBQRCV	0x00000010
 #define TSI721_SR_CHINT_SUSP	0x00000008
@@ -156,7 +156,7 @@
 
 #define TSI721_IBWIN_NUM	8
 
-#define TSI721_IBWINLB(x)	(0x29000 + (x) * 20)
+#define TSI721_IBWINLB(x)	(0x29000 + (x) * 0x20)
 #define TSI721_IBWINLB_BA	0xfffff000
 #define TSI721_IBWINLB_WEN	0x00000001
 
@@ -187,13 +187,13 @@
  */
 #define TSI721_OBWIN_NUM	TSI721_PC2SR_WINS
 
-#define TSI721_OBWINLB(x)	(0x40000 + (x) * 20)
+#define TSI721_OBWINLB(x)	(0x40000 + (x) * 0x20)
 #define TSI721_OBWINLB_BA	0xffff8000
 #define TSI721_OBWINLB_WEN	0x00000001
 
-#define TSI721_OBWINUB(x)	(0x40004 + (x) * 20)
+#define TSI721_OBWINUB(x)	(0x40004 + (x) * 0x20)
 
-#define TSI721_OBWINSZ(x)	(0x40008 + (x) * 20)
+#define TSI721_OBWINSZ(x)	(0x40008 + (x) * 0x20)
 #define TSI721_OBWINSZ_SIZE	0x00001f00
 #define TSI721_OBWIN_SIZE(size)	(__fls(size) - 15)
 
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index e9a83f8..fcde037 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1210,7 +1210,7 @@
 {
 	struct regulator_dev *rdev;
 	struct regulator_map *map;
-	struct regulator *regulator = ERR_PTR(-ENODEV);
+	struct regulator *regulator = ERR_PTR(-EPROBE_DEFER);
 	const char *devname = NULL;
 	int ret;
 
@@ -2834,7 +2834,7 @@
 
 		if (!r) {
 			dev_err(dev, "Failed to find supply %s\n", supply);
-			ret = -ENODEV;
+			ret = -EPROBE_DEFER;
 			goto scrub;
 		}
 
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
index ea4d8f5..09915e8 100644
--- a/drivers/regulator/da9052-regulator.c
+++ b/drivers/regulator/da9052-regulator.c
@@ -226,7 +226,7 @@
 	if (min_uV < info->min_uV)
 		min_uV = info->min_uV;
 
-	*selector = (min_uV - info->min_uV) / info->step_uV;
+	*selector = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
 
 	ret = da9052_list_voltage(rdev, *selector);
 	if (ret < 0)
@@ -318,10 +318,10 @@
 	if ((regulator->da9052->chip_id == DA9052) &&
 	    (min_uV >= DA9052_CONST_3uV))
 		*selector = DA9052_BUCK_PERI_REG_MAP_UPTO_3uV +
-			    ((min_uV - DA9052_CONST_3uV) /
-			    (DA9052_BUCK_PERI_3uV_STEP));
+			    DIV_ROUND_UP(min_uV - DA9052_CONST_3uV,
+					 DA9052_BUCK_PERI_3uV_STEP);
 	else
-		*selector = (min_uV - info->min_uV) / info->step_uV;
+		*selector = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
 
 	ret = da9052_list_buckperi_voltage(rdev, *selector);
 	if (ret < 0)
@@ -400,6 +400,7 @@
 		.ops = &da9052_ldo5_6_ops,\
 		.type = REGULATOR_VOLTAGE,\
 		.id = _id,\
+		.n_voltages = (max - min) / step + 1, \
 		.owner = THIS_MODULE,\
 	},\
 	.min_uV = (min) * 1000,\
@@ -417,6 +418,7 @@
 		.ops = &da9052_ldo_ops,\
 		.type = REGULATOR_VOLTAGE,\
 		.id = _id,\
+		.n_voltages = (max - min) / step + 1, \
 		.owner = THIS_MODULE,\
 	},\
 	.min_uV = (min) * 1000,\
@@ -434,6 +436,7 @@
 		.ops = &da9052_dcdc_ops,\
 		.type = REGULATOR_VOLTAGE,\
 		.id = _id,\
+		.n_voltages = (max - min) / step + 1, \
 		.owner = THIS_MODULE,\
 	},\
 	.min_uV = (min) * 1000,\
@@ -451,6 +454,7 @@
 		.ops = &da9052_buckperi_ops,\
 		.type = REGULATOR_VOLTAGE,\
 		.id = _id,\
+		.n_voltages = (max - min) / step + 1, \
 		.owner = THIS_MODULE,\
 	},\
 	.min_uV = (min) * 1000,\
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c
index 70b7b1f..2e94686 100644
--- a/drivers/regulator/tps6524x-regulator.c
+++ b/drivers/regulator/tps6524x-regulator.c
@@ -481,7 +481,7 @@
 	if (i >= info->n_voltages)
 		i = info->n_voltages - 1;
 
-	*selector = info->voltages[i];
+	*selector = i;
 
 	return write_field(hw, &info->voltage, i);
 }
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 8a1c031..dc87eda 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -73,6 +73,8 @@
 		err = -EINVAL;
 
 	mutex_unlock(&rtc->ops_lock);
+	/* A timer might have just expired */
+	schedule_work(&rtc->irqwork);
 	return err;
 }
 EXPORT_SYMBOL_GPL(rtc_set_time);
@@ -112,6 +114,8 @@
 		err = -EINVAL;
 
 	mutex_unlock(&rtc->ops_lock);
+	/* A timer might have just expired */
+	schedule_work(&rtc->irqwork);
 
 	return err;
 }
@@ -380,18 +384,27 @@
 int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 {
 	int err;
+	struct rtc_time now;
 
 	err = rtc_valid_tm(&alarm->time);
 	if (err != 0)
 		return err;
 
+	err = rtc_read_time(rtc, &now);
+	if (err)
+		return err;
+
 	err = mutex_lock_interruptible(&rtc->ops_lock);
 	if (err)
 		return err;
 
 	rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
 	rtc->aie_timer.period = ktime_set(0, 0);
-	if (alarm->enabled) {
+
+	/* Alarm has to be enabled & in the futrure for us to enqueue it */
+	if (alarm->enabled && (rtc_tm_to_ktime(now).tv64 <
+			 rtc->aie_timer.node.expires.tv64)) {
+
 		rtc->aie_timer.enabled = 1;
 		timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node);
 	}
@@ -763,6 +776,14 @@
 	return 0;
 }
 
+static void rtc_alarm_disable(struct rtc_device *rtc)
+{
+	if (!rtc->ops || !rtc->ops->alarm_irq_enable)
+		return;
+
+	rtc->ops->alarm_irq_enable(rtc->dev.parent, false);
+}
+
 /**
  * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue
  * @rtc rtc device
@@ -784,8 +805,10 @@
 		struct rtc_wkalrm alarm;
 		int err;
 		next = timerqueue_getnext(&rtc->timerqueue);
-		if (!next)
+		if (!next) {
+			rtc_alarm_disable(rtc);
 			return;
+		}
 		alarm.time = rtc_ktime_to_tm(next->expires);
 		alarm.enabled = 1;
 		err = __rtc_set_alarm(rtc, &alarm);
@@ -847,7 +870,8 @@
 		err = __rtc_set_alarm(rtc, &alarm);
 		if (err == -ETIME)
 			goto again;
-	}
+	} else
+		rtc_alarm_disable(rtc);
 
 	mutex_unlock(&rtc->ops_lock);
 }
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index e71a50d..4f9f1dc 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -933,13 +933,9 @@
 static int tty3215_open(struct tty_struct *tty, struct file * filp)
 {
 	struct raw3215_info *raw;
-	int retval, line;
+	int retval;
 
-	line = tty->index;
-	if ((line < 0) || (line >= NR_3215))
-		return -ENODEV;
-
-	raw = raw3215[line];
+	raw = raw3215[tty->index];
 	if (raw == NULL)
 		return -ENODEV;
 
@@ -1145,7 +1141,6 @@
 	 * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
 	 */
 
-	driver->owner = THIS_MODULE;
 	driver->driver_name = "tty3215";
 	driver->name = "ttyS";
 	driver->major = TTY_MAJOR;
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index a879c13..40a9d69 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -551,7 +551,6 @@
 		return rc;
 	}
 
-	driver->owner = THIS_MODULE;
 	driver->driver_name = "sclp_line";
 	driver->name = "sclp_line";
 	driver->major = TTY_MAJOR;
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 5d706e6..b635472 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -685,7 +685,6 @@
 	if (rc)
 		goto out_driver;
 
-	driver->owner = THIS_MODULE;
 	driver->driver_name = SCLP_VT220_DRIVER_NAME;
 	driver->name = SCLP_VT220_DEVICE_NAME;
 	driver->major = SCLP_VT220_MAJOR;
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 2db1482..b43445a 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -1784,7 +1784,6 @@
 	 * Entries in tty3270_driver that are NOT initialized:
 	 * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
 	 */
-	driver->owner = THIS_MODULE;
 	driver->driver_name = "ttyTUB";
 	driver->name = "ttyTUB";
 	driver->major = IBM_TTY3270_MAJOR;
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 4f1989d..5f1dc6f 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -580,7 +580,6 @@
 	struct device *dev;
 
 	/* We don't want ccwgroup devices to live longer than their driver. */
-	get_driver(&cdriver->driver);
 	while ((dev = driver_find_device(&cdriver->driver, NULL, NULL,
 					 __ccwgroup_match_all))) {
 		struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
@@ -592,7 +591,6 @@
 		mutex_unlock(&gdev->reg_mutex);
 		put_device(dev);
 	}
-	put_driver(&cdriver->driver);
 	driver_unregister(&cdriver->driver);
 }
 EXPORT_SYMBOL(ccwgroup_driver_unregister);
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 4726985..02d0152 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1676,15 +1676,9 @@
 				       const char *bus_id)
 {
 	struct device *dev;
-	struct device_driver *drv;
 
-	drv = get_driver(&cdrv->driver);
-	if (!drv)
-		return NULL;
-
-	dev = driver_find_device(drv, NULL, (void *)bus_id,
+	dev = driver_find_device(&cdrv->driver, NULL, (void *)bus_id,
 				 __ccwdev_check_busid);
-	put_driver(drv);
 
 	return dev ? to_ccwdev(dev) : NULL;
 }
diff --git a/drivers/s390/net/smsgiucv_app.c b/drivers/s390/net/smsgiucv_app.c
index 4d2ea40..32515a2 100644
--- a/drivers/s390/net/smsgiucv_app.c
+++ b/drivers/s390/net/smsgiucv_app.c
@@ -168,7 +168,7 @@
 	rc = dev_set_name(smsg_app_dev, KMSG_COMPONENT);
 	if (rc) {
 		kfree(smsg_app_dev);
-		goto fail_put_driver;
+		goto fail;
 	}
 	smsg_app_dev->bus = &iucv_bus;
 	smsg_app_dev->parent = iucv_root;
@@ -177,7 +177,7 @@
 	rc = device_register(smsg_app_dev);
 	if (rc) {
 		put_device(smsg_app_dev);
-		goto fail_put_driver;
+		goto fail;
 	}
 
 	/* convert sender to uppercase characters */
@@ -191,12 +191,11 @@
 	rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback);
 	if (rc) {
 		device_unregister(smsg_app_dev);
-		goto fail_put_driver;
+		goto fail;
 	}
 
 	rc = 0;
-fail_put_driver:
-	put_driver(smsgiucv_drv);
+fail:
 	return rc;
 }
 module_init(smsgiucv_app_init);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 16570aa..d3d18e8 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -662,6 +662,13 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called vmw_pvscsi.
 
+config HYPERV_STORAGE
+	tristate "Microsoft Hyper-V virtual storage driver"
+	depends on SCSI && HYPERV
+	default HYPERV
+	help
+	  Select this option to enable the Hyper-V virtual storage driver.
+
 config LIBFC
 	tristate "LibFC module"
 	select SCSI_FC_ATTRS
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 2b88749..e4c1a69 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -142,6 +142,7 @@
 obj-$(CONFIG_BE2ISCSI)		+= libiscsi.o be2iscsi/
 obj-$(CONFIG_SCSI_PMCRAID)	+= pmcraid.o
 obj-$(CONFIG_VMWARE_PVSCSI)	+= vmw_pvscsi.o
+obj-$(CONFIG_HYPERV_STORAGE)	+= hv_storvsc.o
 
 obj-$(CONFIG_ARM)		+= arm/
 
@@ -170,6 +171,8 @@
 scsi_mod-y			+= scsi_trace.o
 scsi_mod-$(CONFIG_PM)		+= scsi_pm.o
 
+hv_storvsc-y			:= storvsc_drv.o
+
 scsi_tgt-y			+= scsi_tgt_lib.o scsi_tgt_if.o
 
 sd_mod-objs	:= sd.o
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 29c4c04..01b0374 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -1295,6 +1295,7 @@
  *   LUNs even if it's older than SCSI-3.
  *   If BLIST_NOREPORTLUN is set, return 1 always.
  *   If BLIST_NOLUN is set, return 0 always.
+ *   If starget->no_report_luns is set, return 1 always.
  *
  * Return:
  *     0: scan completed (or no memory, so further scanning is futile)
@@ -1321,6 +1322,7 @@
 	 * Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set.
 	 * Also allow SCSI-2 if BLIST_REPORTLUN2 is set and host adapter does
 	 * support more than 8 LUNs.
+	 * Don't attempt if the target doesn't support REPORT LUNS.
 	 */
 	if (bflags & BLIST_NOREPORTLUN)
 		return 1;
@@ -1332,6 +1334,8 @@
 		return 1;
 	if (bflags & BLIST_NOLUN)
 		return 0;
+	if (starget->no_report_luns)
+		return 1;
 
 	if (!(sdev = scsi_device_lookup_by_target(starget, 0))) {
 		sdev = scsi_alloc_sdev(starget, 0, NULL);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index c691fb5..d173b90 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -2349,7 +2349,7 @@
 	 * some USB ones crash on receiving them, and the pages
 	 * we currently ask for are for SPC-3 and beyond
 	 */
-	if (sdp->scsi_level > SCSI_SPC_2)
+	if (sdp->scsi_level > SCSI_SPC_2 && !sdp->skip_vpd_pages)
 		return 1;
 	return 0;
 }
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
similarity index 84%
rename from drivers/staging/hv/storvsc_drv.c
rename to drivers/scsi/storvsc_drv.c
index eb853f7..695ffc3 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -42,56 +42,23 @@
 #include <scsi/scsi_devinfo.h>
 #include <scsi/scsi_dbg.h>
 
+/*
+ * All wire protocol details (storage protocol between the guest and the host)
+ * are consolidated here.
+ *
+ * Begin protocol definitions.
+ */
 
-#define STORVSC_MIN_BUF_NR				64
-#define STORVSC_RING_BUFFER_SIZE			(20*PAGE_SIZE)
-static int storvsc_ringbuffer_size = STORVSC_RING_BUFFER_SIZE;
+/*
+ * Version history:
+ * V1 Beta: 0.1
+ * V1 RC < 2008/1/31: 1.0
+ * V1 RC > 2008/1/31:  2.0
+ * Win7: 4.2
+ */
 
-module_param(storvsc_ringbuffer_size, int, S_IRUGO);
-MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
-
-/* to alert the user that structure sizes may be mismatched even though the */
-/* protocol versions match. */
-
-
-#define REVISION_STRING(REVISION_) #REVISION_
-#define FILL_VMSTOR_REVISION(RESULT_LVALUE_)				\
-	do {								\
-		char *revision_string					\
-			= REVISION_STRING($Rev : 6 $) + 6;		\
-		RESULT_LVALUE_ = 0;					\
-		while (*revision_string >= '0'				\
-			&& *revision_string <= '9') {			\
-			RESULT_LVALUE_ *= 10;				\
-			RESULT_LVALUE_ += *revision_string - '0';	\
-			revision_string++;				\
-		}							\
-	} while (0)
-
-/* Major/minor macros.  Minor version is in LSB, meaning that earlier flat */
-/* version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1). */
-#define VMSTOR_PROTOCOL_MAJOR(VERSION_)		(((VERSION_) >> 8) & 0xff)
-#define VMSTOR_PROTOCOL_MINOR(VERSION_)		(((VERSION_))      & 0xff)
-#define VMSTOR_PROTOCOL_VERSION(MAJOR_, MINOR_)	((((MAJOR_) & 0xff) << 8) | \
-						 (((MINOR_) & 0xff)))
-#define VMSTOR_INVALID_PROTOCOL_VERSION		(-1)
-
-/* Version history: */
-/* V1 Beta                    0.1 */
-/* V1 RC < 2008/1/31          1.0 */
-/* V1 RC > 2008/1/31          2.0 */
-#define VMSTOR_PROTOCOL_VERSION_CURRENT VMSTOR_PROTOCOL_VERSION(4, 2)
-
-
-
-
-/*  This will get replaced with the max transfer length that is possible on */
-/*  the host adapter. */
-/*  The max transfer length will be published when we offer a vmbus channel. */
-#define MAX_TRANSFER_LENGTH	0x40000
-#define DEFAULT_PACKET_SIZE (sizeof(struct vmdata_gpa_direct) +	\
-			sizeof(struct vstor_packet) +		\
-			sizesizeof(u64) * (MAX_TRANSFER_LENGTH / PAGE_SIZE)))
+#define VMSTOR_CURRENT_MAJOR  4
+#define VMSTOR_CURRENT_MINOR  2
 
 
 /*  Packet structure describing virtual storage requests. */
@@ -115,35 +82,31 @@
  * this remains the same across the write regardless of 32/64 bit
  * note: it's patterned off the SCSI_PASS_THROUGH structure
  */
-#define CDB16GENERIC_LENGTH			0x10
-
-#ifndef SENSE_BUFFER_SIZE
-#define SENSE_BUFFER_SIZE			0x12
-#endif
-
-#define MAX_DATA_BUF_LEN_WITH_PADDING		0x14
+#define STORVSC_MAX_CMD_LEN			0x10
+#define STORVSC_SENSE_BUFFER_SIZE		0x12
+#define STORVSC_MAX_BUF_LEN_WITH_PADDING	0x14
 
 struct vmscsi_request {
-	unsigned short length;
-	unsigned char srb_status;
-	unsigned char scsi_status;
+	u16 length;
+	u8 srb_status;
+	u8 scsi_status;
 
-	unsigned char port_number;
-	unsigned char path_id;
-	unsigned char target_id;
-	unsigned char lun;
+	u8  port_number;
+	u8  path_id;
+	u8  target_id;
+	u8  lun;
 
-	unsigned char cdb_length;
-	unsigned char sense_info_length;
-	unsigned char data_in;
-	unsigned char reserved;
+	u8  cdb_length;
+	u8  sense_info_length;
+	u8  data_in;
+	u8  reserved;
 
-	unsigned int data_transfer_length;
+	u32 data_transfer_length;
 
 	union {
-		unsigned char cdb[CDB16GENERIC_LENGTH];
-		unsigned char sense_data[SENSE_BUFFER_SIZE];
-		unsigned char reserved_array[MAX_DATA_BUF_LEN_WITH_PADDING];
+		u8 cdb[STORVSC_MAX_CMD_LEN];
+		u8 sense_data[STORVSC_SENSE_BUFFER_SIZE];
+		u8 reserved_array[STORVSC_MAX_BUF_LEN_WITH_PADDING];
 	};
 } __attribute((packed));
 
@@ -153,32 +116,36 @@
  * properties of the channel.
  */
 struct vmstorage_channel_properties {
-	unsigned short protocol_version;
-	unsigned char path_id;
-	unsigned char target_id;
+	u16 protocol_version;
+	u8  path_id;
+	u8 target_id;
 
 	/* Note: port number is only really known on the client side */
-	unsigned int port_number;
-	unsigned int flags;
-	unsigned int max_transfer_bytes;
+	u32  port_number;
+	u32  flags;
+	u32   max_transfer_bytes;
 
-	/*  This id is unique for each channel and will correspond with */
-	/*  vendor specific data in the inquirydata */
-	unsigned long long unique_id;
+	/*
+	 * This id is unique for each channel and will correspond with
+	 * vendor specific data in the inquiry data.
+	 */
+
+	u64  unique_id;
 } __packed;
 
 /*  This structure is sent during the storage protocol negotiations. */
 struct vmstorage_protocol_version {
 	/* Major (MSW) and minor (LSW) version numbers. */
-	unsigned short major_minor;
+	u16 major_minor;
 
 	/*
 	 * Revision number is auto-incremented whenever this file is changed
 	 * (See FILL_VMSTOR_REVISION macro above).  Mismatch does not
 	 * definitely indicate incompatibility--but it does indicate mismatched
 	 * builds.
+	 * This is only used on the windows side. Just set it to 0.
 	 */
-	unsigned short revision;
+	u16 revision;
 } __packed;
 
 /* Channel Property Flags */
@@ -190,10 +157,10 @@
 	enum vstor_packet_operation operation;
 
 	/*  Flags - see below for values */
-	unsigned int flags;
+	u32 flags;
 
 	/* Status of the request returned from the server side. */
-	unsigned int status;
+	u32 status;
 
 	/* Data payload area */
 	union {
@@ -211,18 +178,47 @@
 	};
 } __packed;
 
-/* Packet flags */
 /*
+ * Packet Flags:
+ *
  * This flag indicates that the server should send back a completion for this
  * packet.
  */
+
 #define REQUEST_COMPLETION_FLAG	0x1
 
-/*  This is the set of flags that the vsc can set in any packets it sends */
-#define VSC_LEGAL_FLAGS		(REQUEST_COMPLETION_FLAG)
+/* Matches Windows-end */
+enum storvsc_request_type {
+	WRITE_TYPE = 0,
+	READ_TYPE,
+	UNKNOWN_TYPE,
+};
+
+/*
+ * SRB status codes and masks; a subset of the codes used here.
+ */
+
+#define SRB_STATUS_AUTOSENSE_VALID	0x80
+#define SRB_STATUS_INVALID_LUN	0x20
+#define SRB_STATUS_SUCCESS	0x01
+#define SRB_STATUS_ERROR	0x04
+
+/*
+ * This is the end of Protocol specific defines.
+ */
 
 
-/* Defines */
+/*
+ * We setup a mempool to allocate request structures for this driver
+ * on a per-lun basis. The following define specifies the number of
+ * elements in the pool.
+ */
+
+#define STORVSC_MIN_BUF_NR				64
+static int storvsc_ringbuffer_size = (20 * PAGE_SIZE);
+
+module_param(storvsc_ringbuffer_size, int, S_IRUGO);
+MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
 
 #define STORVSC_MAX_IO_REQUESTS				128
 
@@ -235,27 +231,23 @@
 #define STORVSC_MAX_LUNS_PER_TARGET			64
 #define STORVSC_MAX_TARGETS				1
 #define STORVSC_MAX_CHANNELS				1
-#define STORVSC_MAX_CMD_LEN				16
-
-/* Matches Windows-end */
-enum storvsc_request_type {
-	WRITE_TYPE,
-	READ_TYPE,
-	UNKNOWN_TYPE,
-};
 
 
-struct hv_storvsc_request {
+
+struct storvsc_cmd_request {
+	struct list_head entry;
+	struct scsi_cmnd *cmd;
+
+	unsigned int bounce_sgl_count;
+	struct scatterlist *bounce_sgl;
+
 	struct hv_device *device;
 
 	/* Synchronize the request/response if needed */
 	struct completion wait_event;
 
 	unsigned char *sense_buffer;
-	void *context;
-	void (*on_io_completion)(struct hv_storvsc_request *request);
 	struct hv_multipage_buffer data_buffer;
-
 	struct vstor_packet vstor_packet;
 };
 
@@ -281,8 +273,8 @@
 	unsigned char target_id;
 
 	/* Used for vsc/vsp channel reset process */
-	struct hv_storvsc_request init_request;
-	struct hv_storvsc_request reset_request;
+	struct storvsc_cmd_request init_request;
+	struct storvsc_cmd_request reset_request;
 };
 
 struct stor_mem_pools {
@@ -297,16 +289,6 @@
 	unsigned char target;
 };
 
-struct storvsc_cmd_request {
-	struct list_head entry;
-	struct scsi_cmnd *cmd;
-
-	unsigned int bounce_sgl_count;
-	struct scatterlist *bounce_sgl;
-
-	struct hv_storvsc_request request;
-};
-
 struct storvsc_scan_work {
 	struct work_struct work;
 	struct Scsi_Host *host;
@@ -352,6 +334,34 @@
 	kfree(wrk);
 }
 
+/*
+ * Major/minor macros.  Minor version is in LSB, meaning that earlier flat
+ * version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1).
+ */
+
+static inline u16 storvsc_get_version(u8 major, u8 minor)
+{
+	u16 version;
+
+	version = ((major << 8) | minor);
+	return version;
+}
+
+/*
+ * We can get incoming messages from the host that are not in response to
+ * messages that we have sent out. An example of this would be messages
+ * received by the guest to notify dynamic addition/removal of LUNs. To
+ * deal with potential race conditions where the driver may be in the
+ * midst of being unloaded when we might receive an unsolicited message
+ * from the host, we have implemented a mechanism to gurantee sequential
+ * consistency:
+ *
+ * 1) Once the device is marked as being destroyed, we will fail all
+ *    outgoing messages.
+ * 2) We permit incoming messages when the device is being destroyed,
+ *    only to properly account for messages already sent out.
+ */
+
 static inline struct storvsc_device *get_out_stor_device(
 					struct hv_device *device)
 {
@@ -398,457 +408,6 @@
 
 }
 
-static int storvsc_channel_init(struct hv_device *device)
-{
-	struct storvsc_device *stor_device;
-	struct hv_storvsc_request *request;
-	struct vstor_packet *vstor_packet;
-	int ret, t;
-
-	stor_device = get_out_stor_device(device);
-	if (!stor_device)
-		return -ENODEV;
-
-	request = &stor_device->init_request;
-	vstor_packet = &request->vstor_packet;
-
-	/*
-	 * Now, initiate the vsc/vsp initialization protocol on the open
-	 * channel
-	 */
-	memset(request, 0, sizeof(struct hv_storvsc_request));
-	init_completion(&request->wait_event);
-	vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
-	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
-
-	ret = vmbus_sendpacket(device->channel, vstor_packet,
-			       sizeof(struct vstor_packet),
-			       (unsigned long)request,
-			       VM_PKT_DATA_INBAND,
-			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-	if (ret != 0)
-		goto cleanup;
-
-	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-	if (t == 0) {
-		ret = -ETIMEDOUT;
-		goto cleanup;
-	}
-
-	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
-	    vstor_packet->status != 0)
-		goto cleanup;
-
-
-	/* reuse the packet for version range supported */
-	memset(vstor_packet, 0, sizeof(struct vstor_packet));
-	vstor_packet->operation = VSTOR_OPERATION_QUERY_PROTOCOL_VERSION;
-	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
-
-	vstor_packet->version.major_minor = VMSTOR_PROTOCOL_VERSION_CURRENT;
-	FILL_VMSTOR_REVISION(vstor_packet->version.revision);
-
-	ret = vmbus_sendpacket(device->channel, vstor_packet,
-			       sizeof(struct vstor_packet),
-			       (unsigned long)request,
-			       VM_PKT_DATA_INBAND,
-			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-	if (ret != 0)
-		goto cleanup;
-
-	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-	if (t == 0) {
-		ret = -ETIMEDOUT;
-		goto cleanup;
-	}
-
-	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
-	    vstor_packet->status != 0)
-		goto cleanup;
-
-
-	memset(vstor_packet, 0, sizeof(struct vstor_packet));
-	vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES;
-	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
-	vstor_packet->storage_channel_properties.port_number =
-					stor_device->port_number;
-
-	ret = vmbus_sendpacket(device->channel, vstor_packet,
-			       sizeof(struct vstor_packet),
-			       (unsigned long)request,
-			       VM_PKT_DATA_INBAND,
-			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-
-	if (ret != 0)
-		goto cleanup;
-
-	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-	if (t == 0) {
-		ret = -ETIMEDOUT;
-		goto cleanup;
-	}
-
-	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
-	    vstor_packet->status != 0)
-		goto cleanup;
-
-	stor_device->path_id = vstor_packet->storage_channel_properties.path_id;
-	stor_device->target_id
-		= vstor_packet->storage_channel_properties.target_id;
-
-	memset(vstor_packet, 0, sizeof(struct vstor_packet));
-	vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
-	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
-
-	ret = vmbus_sendpacket(device->channel, vstor_packet,
-			       sizeof(struct vstor_packet),
-			       (unsigned long)request,
-			       VM_PKT_DATA_INBAND,
-			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-
-	if (ret != 0)
-		goto cleanup;
-
-	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-	if (t == 0) {
-		ret = -ETIMEDOUT;
-		goto cleanup;
-	}
-
-	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
-	    vstor_packet->status != 0)
-		goto cleanup;
-
-
-cleanup:
-	return ret;
-}
-
-static void storvsc_on_io_completion(struct hv_device *device,
-				  struct vstor_packet *vstor_packet,
-				  struct hv_storvsc_request *request)
-{
-	struct storvsc_device *stor_device;
-	struct vstor_packet *stor_pkt;
-
-	stor_device = hv_get_drvdata(device);
-	stor_pkt = &request->vstor_packet;
-
-	/*
-	 * The current SCSI handling on the host side does
-	 * not correctly handle:
-	 * INQUIRY command with page code parameter set to 0x80
-	 * MODE_SENSE command with cmd[2] == 0x1c
-	 *
-	 * Setup srb and scsi status so this won't be fatal.
-	 * We do this so we can distinguish truly fatal failues
-	 * (srb status == 0x4) and off-line the device in that case.
-	 */
-
-	if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) ||
-		(stor_pkt->vm_srb.cdb[0] == MODE_SENSE)) {
-		vstor_packet->vm_srb.scsi_status = 0;
-		vstor_packet->vm_srb.srb_status = 0x1;
-	}
-
-
-	/* Copy over the status...etc */
-	stor_pkt->vm_srb.scsi_status = vstor_packet->vm_srb.scsi_status;
-	stor_pkt->vm_srb.srb_status = vstor_packet->vm_srb.srb_status;
-	stor_pkt->vm_srb.sense_info_length =
-	vstor_packet->vm_srb.sense_info_length;
-
-	if (vstor_packet->vm_srb.scsi_status != 0 ||
-		vstor_packet->vm_srb.srb_status != 1){
-		dev_warn(&device->device,
-			 "cmd 0x%x scsi status 0x%x srb status 0x%x\n",
-			 stor_pkt->vm_srb.cdb[0],
-			 vstor_packet->vm_srb.scsi_status,
-			 vstor_packet->vm_srb.srb_status);
-	}
-
-	if ((vstor_packet->vm_srb.scsi_status & 0xFF) == 0x02) {
-		/* CHECK_CONDITION */
-		if (vstor_packet->vm_srb.srb_status & 0x80) {
-			/* autosense data available */
-			dev_warn(&device->device,
-				 "stor pkt %p autosense data valid - len %d\n",
-				 request,
-				 vstor_packet->vm_srb.sense_info_length);
-
-			memcpy(request->sense_buffer,
-			       vstor_packet->vm_srb.sense_data,
-			       vstor_packet->vm_srb.sense_info_length);
-
-		}
-	}
-
-	stor_pkt->vm_srb.data_transfer_length =
-	vstor_packet->vm_srb.data_transfer_length;
-
-	request->on_io_completion(request);
-
-	if (atomic_dec_and_test(&stor_device->num_outstanding_req) &&
-		stor_device->drain_notify)
-		wake_up(&stor_device->waiting_to_drain);
-
-
-}
-
-static void storvsc_on_receive(struct hv_device *device,
-			     struct vstor_packet *vstor_packet,
-			     struct hv_storvsc_request *request)
-{
-	struct storvsc_scan_work *work;
-	struct storvsc_device *stor_device;
-
-	switch (vstor_packet->operation) {
-	case VSTOR_OPERATION_COMPLETE_IO:
-		storvsc_on_io_completion(device, vstor_packet, request);
-		break;
-
-	case VSTOR_OPERATION_REMOVE_DEVICE:
-	case VSTOR_OPERATION_ENUMERATE_BUS:
-		stor_device = get_in_stor_device(device);
-		work = kmalloc(sizeof(struct storvsc_scan_work), GFP_ATOMIC);
-		if (!work)
-			return;
-
-		INIT_WORK(&work->work, storvsc_bus_scan);
-		work->host = stor_device->host;
-		schedule_work(&work->work);
-		break;
-
-	default:
-		break;
-	}
-}
-
-static void storvsc_on_channel_callback(void *context)
-{
-	struct hv_device *device = (struct hv_device *)context;
-	struct storvsc_device *stor_device;
-	u32 bytes_recvd;
-	u64 request_id;
-	unsigned char packet[ALIGN(sizeof(struct vstor_packet), 8)];
-	struct hv_storvsc_request *request;
-	int ret;
-
-
-	stor_device = get_in_stor_device(device);
-	if (!stor_device)
-		return;
-
-	do {
-		ret = vmbus_recvpacket(device->channel, packet,
-				       ALIGN(sizeof(struct vstor_packet), 8),
-				       &bytes_recvd, &request_id);
-		if (ret == 0 && bytes_recvd > 0) {
-
-			request = (struct hv_storvsc_request *)
-					(unsigned long)request_id;
-
-			if ((request == &stor_device->init_request) ||
-			    (request == &stor_device->reset_request)) {
-
-				memcpy(&request->vstor_packet, packet,
-				       sizeof(struct vstor_packet));
-				complete(&request->wait_event);
-			} else {
-				storvsc_on_receive(device,
-						(struct vstor_packet *)packet,
-						request);
-			}
-		} else {
-			break;
-		}
-	} while (1);
-
-	return;
-}
-
-static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
-{
-	struct vmstorage_channel_properties props;
-	int ret;
-
-	memset(&props, 0, sizeof(struct vmstorage_channel_properties));
-
-	/* Open the channel */
-	ret = vmbus_open(device->channel,
-			 ring_size,
-			 ring_size,
-			 (void *)&props,
-			 sizeof(struct vmstorage_channel_properties),
-			 storvsc_on_channel_callback, device);
-
-	if (ret != 0)
-		return ret;
-
-	ret = storvsc_channel_init(device);
-
-	return ret;
-}
-
-static int storvsc_dev_remove(struct hv_device *device)
-{
-	struct storvsc_device *stor_device;
-	unsigned long flags;
-
-	stor_device = hv_get_drvdata(device);
-
-	spin_lock_irqsave(&device->channel->inbound_lock, flags);
-	stor_device->destroy = true;
-	spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
-
-	/*
-	 * At this point, all outbound traffic should be disable. We
-	 * only allow inbound traffic (responses) to proceed so that
-	 * outstanding requests can be completed.
-	 */
-
-	storvsc_wait_to_drain(stor_device);
-
-	/*
-	 * Since we have already drained, we don't need to busy wait
-	 * as was done in final_release_stor_device()
-	 * Note that we cannot set the ext pointer to NULL until
-	 * we have drained - to drain the outgoing packets, we need to
-	 * allow incoming packets.
-	 */
-	spin_lock_irqsave(&device->channel->inbound_lock, flags);
-	hv_set_drvdata(device, NULL);
-	spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
-
-	/* Close the channel */
-	vmbus_close(device->channel);
-
-	kfree(stor_device);
-	return 0;
-}
-
-static int storvsc_do_io(struct hv_device *device,
-			      struct hv_storvsc_request *request)
-{
-	struct storvsc_device *stor_device;
-	struct vstor_packet *vstor_packet;
-	int ret = 0;
-
-	vstor_packet = &request->vstor_packet;
-	stor_device = get_out_stor_device(device);
-
-	if (!stor_device)
-		return -ENODEV;
-
-
-	request->device  = device;
-
-
-	vstor_packet->flags |= REQUEST_COMPLETION_FLAG;
-
-	vstor_packet->vm_srb.length = sizeof(struct vmscsi_request);
-
-
-	vstor_packet->vm_srb.sense_info_length = SENSE_BUFFER_SIZE;
-
-
-	vstor_packet->vm_srb.data_transfer_length =
-	request->data_buffer.len;
-
-	vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB;
-
-	if (request->data_buffer.len) {
-		ret = vmbus_sendpacket_multipagebuffer(device->channel,
-				&request->data_buffer,
-				vstor_packet,
-				sizeof(struct vstor_packet),
-				(unsigned long)request);
-	} else {
-		ret = vmbus_sendpacket(device->channel, vstor_packet,
-			       sizeof(struct vstor_packet),
-			       (unsigned long)request,
-			       VM_PKT_DATA_INBAND,
-			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-	}
-
-	if (ret != 0)
-		return ret;
-
-	atomic_inc(&stor_device->num_outstanding_req);
-
-	return ret;
-}
-
-static void storvsc_get_ide_info(struct hv_device *dev, int *target, int *path)
-{
-	*target =
-		dev->dev_instance.b[5] << 8 | dev->dev_instance.b[4];
-
-	*path =
-		dev->dev_instance.b[3] << 24 |
-		dev->dev_instance.b[2] << 16 |
-		dev->dev_instance.b[1] << 8  | dev->dev_instance.b[0];
-}
-
-
-static int storvsc_device_alloc(struct scsi_device *sdevice)
-{
-	struct stor_mem_pools *memp;
-	int number = STORVSC_MIN_BUF_NR;
-
-	memp = kzalloc(sizeof(struct stor_mem_pools), GFP_KERNEL);
-	if (!memp)
-		return -ENOMEM;
-
-	memp->request_pool =
-		kmem_cache_create(dev_name(&sdevice->sdev_dev),
-				sizeof(struct storvsc_cmd_request), 0,
-				SLAB_HWCACHE_ALIGN, NULL);
-
-	if (!memp->request_pool)
-		goto err0;
-
-	memp->request_mempool = mempool_create(number, mempool_alloc_slab,
-						mempool_free_slab,
-						memp->request_pool);
-
-	if (!memp->request_mempool)
-		goto err1;
-
-	sdevice->hostdata = memp;
-
-	return 0;
-
-err1:
-	kmem_cache_destroy(memp->request_pool);
-
-err0:
-	kfree(memp);
-	return -ENOMEM;
-}
-
-static void storvsc_device_destroy(struct scsi_device *sdevice)
-{
-	struct stor_mem_pools *memp = sdevice->hostdata;
-
-	mempool_destroy(memp->request_mempool);
-	kmem_cache_destroy(memp->request_pool);
-	kfree(memp);
-	sdevice->hostdata = NULL;
-}
-
-static int storvsc_device_configure(struct scsi_device *sdevice)
-{
-	scsi_adjust_queue_depth(sdevice, MSG_SIMPLE_TAG,
-				STORVSC_MAX_IO_REQUESTS);
-
-	blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE);
-
-	blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY);
-
-	return 0;
-}
-
 static void destroy_bounce_buffer(struct scatterlist *sgl,
 				  unsigned int sg_count)
 {
@@ -922,7 +481,6 @@
 	return NULL;
 }
 
-
 /* Assume the original sgl has enough room */
 static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
 					    struct scatterlist *bounce_sgl,
@@ -1006,7 +564,6 @@
 	return total_copied;
 }
 
-
 /* Assume the bounce_sgl has enough room ie using the create_bounce_buffer() */
 static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
 					  struct scatterlist *bounce_sgl,
@@ -1072,21 +629,524 @@
 	return total_copied;
 }
 
-
-static int storvsc_remove(struct hv_device *dev)
+static int storvsc_channel_init(struct hv_device *device)
 {
-	struct storvsc_device *stor_device = hv_get_drvdata(dev);
-	struct Scsi_Host *host = stor_device->host;
+	struct storvsc_device *stor_device;
+	struct storvsc_cmd_request *request;
+	struct vstor_packet *vstor_packet;
+	int ret, t;
 
-	scsi_remove_host(host);
+	stor_device = get_out_stor_device(device);
+	if (!stor_device)
+		return -ENODEV;
 
-	scsi_host_put(host);
+	request = &stor_device->init_request;
+	vstor_packet = &request->vstor_packet;
 
-	storvsc_dev_remove(dev);
+	/*
+	 * Now, initiate the vsc/vsp initialization protocol on the open
+	 * channel
+	 */
+	memset(request, 0, sizeof(struct storvsc_cmd_request));
+	init_completion(&request->wait_event);
+	vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
+	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
 
+	ret = vmbus_sendpacket(device->channel, vstor_packet,
+			       sizeof(struct vstor_packet),
+			       (unsigned long)request,
+			       VM_PKT_DATA_INBAND,
+			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+	if (ret != 0)
+		goto cleanup;
+
+	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
+	if (t == 0) {
+		ret = -ETIMEDOUT;
+		goto cleanup;
+	}
+
+	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
+	    vstor_packet->status != 0)
+		goto cleanup;
+
+
+	/* reuse the packet for version range supported */
+	memset(vstor_packet, 0, sizeof(struct vstor_packet));
+	vstor_packet->operation = VSTOR_OPERATION_QUERY_PROTOCOL_VERSION;
+	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+
+	vstor_packet->version.major_minor =
+		storvsc_get_version(VMSTOR_CURRENT_MAJOR, VMSTOR_CURRENT_MINOR);
+
+	/*
+	 * The revision number is only used in Windows; set it to 0.
+	 */
+	vstor_packet->version.revision = 0;
+
+	ret = vmbus_sendpacket(device->channel, vstor_packet,
+			       sizeof(struct vstor_packet),
+			       (unsigned long)request,
+			       VM_PKT_DATA_INBAND,
+			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+	if (ret != 0)
+		goto cleanup;
+
+	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
+	if (t == 0) {
+		ret = -ETIMEDOUT;
+		goto cleanup;
+	}
+
+	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
+	    vstor_packet->status != 0)
+		goto cleanup;
+
+
+	memset(vstor_packet, 0, sizeof(struct vstor_packet));
+	vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES;
+	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+	vstor_packet->storage_channel_properties.port_number =
+					stor_device->port_number;
+
+	ret = vmbus_sendpacket(device->channel, vstor_packet,
+			       sizeof(struct vstor_packet),
+			       (unsigned long)request,
+			       VM_PKT_DATA_INBAND,
+			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+
+	if (ret != 0)
+		goto cleanup;
+
+	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
+	if (t == 0) {
+		ret = -ETIMEDOUT;
+		goto cleanup;
+	}
+
+	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
+	    vstor_packet->status != 0)
+		goto cleanup;
+
+	stor_device->path_id = vstor_packet->storage_channel_properties.path_id;
+	stor_device->target_id
+		= vstor_packet->storage_channel_properties.target_id;
+
+	memset(vstor_packet, 0, sizeof(struct vstor_packet));
+	vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
+	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+
+	ret = vmbus_sendpacket(device->channel, vstor_packet,
+			       sizeof(struct vstor_packet),
+			       (unsigned long)request,
+			       VM_PKT_DATA_INBAND,
+			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+
+	if (ret != 0)
+		goto cleanup;
+
+	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
+	if (t == 0) {
+		ret = -ETIMEDOUT;
+		goto cleanup;
+	}
+
+	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
+	    vstor_packet->status != 0)
+		goto cleanup;
+
+
+cleanup:
+	return ret;
+}
+
+
+static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
+{
+	struct scsi_cmnd *scmnd = cmd_request->cmd;
+	struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
+	void (*scsi_done_fn)(struct scsi_cmnd *);
+	struct scsi_sense_hdr sense_hdr;
+	struct vmscsi_request *vm_srb;
+	struct storvsc_scan_work *wrk;
+	struct stor_mem_pools *memp = scmnd->device->hostdata;
+
+	vm_srb = &cmd_request->vstor_packet.vm_srb;
+	if (cmd_request->bounce_sgl_count) {
+		if (vm_srb->data_in == READ_TYPE)
+			copy_from_bounce_buffer(scsi_sglist(scmnd),
+					cmd_request->bounce_sgl,
+					scsi_sg_count(scmnd),
+					cmd_request->bounce_sgl_count);
+		destroy_bounce_buffer(cmd_request->bounce_sgl,
+					cmd_request->bounce_sgl_count);
+	}
+
+	/*
+	 * If there is an error; offline the device since all
+	 * error recovery strategies would have already been
+	 * deployed on the host side.
+	 */
+	if (vm_srb->srb_status == SRB_STATUS_ERROR)
+		scmnd->result = DID_TARGET_FAILURE << 16;
+	else
+		scmnd->result = vm_srb->scsi_status;
+
+	/*
+	 * If the LUN is invalid; remove the device.
+	 */
+	if (vm_srb->srb_status == SRB_STATUS_INVALID_LUN) {
+		struct storvsc_device *stor_dev;
+		struct hv_device *dev = host_dev->dev;
+		struct Scsi_Host *host;
+
+		stor_dev = get_in_stor_device(dev);
+		host = stor_dev->host;
+
+		wrk = kmalloc(sizeof(struct storvsc_scan_work),
+				GFP_ATOMIC);
+		if (!wrk) {
+			scmnd->result = DID_TARGET_FAILURE << 16;
+		} else {
+			wrk->host = host;
+			wrk->lun = vm_srb->lun;
+			INIT_WORK(&wrk->work, storvsc_remove_lun);
+			schedule_work(&wrk->work);
+		}
+	}
+
+	if (scmnd->result) {
+		if (scsi_normalize_sense(scmnd->sense_buffer,
+				SCSI_SENSE_BUFFERSIZE, &sense_hdr))
+			scsi_print_sense_hdr("storvsc", &sense_hdr);
+	}
+
+	scsi_set_resid(scmnd,
+		cmd_request->data_buffer.len -
+		vm_srb->data_transfer_length);
+
+	scsi_done_fn = scmnd->scsi_done;
+
+	scmnd->host_scribble = NULL;
+	scmnd->scsi_done = NULL;
+
+	scsi_done_fn(scmnd);
+
+	mempool_free(cmd_request, memp->request_mempool);
+}
+
+static void storvsc_on_io_completion(struct hv_device *device,
+				  struct vstor_packet *vstor_packet,
+				  struct storvsc_cmd_request *request)
+{
+	struct storvsc_device *stor_device;
+	struct vstor_packet *stor_pkt;
+
+	stor_device = hv_get_drvdata(device);
+	stor_pkt = &request->vstor_packet;
+
+	/*
+	 * The current SCSI handling on the host side does
+	 * not correctly handle:
+	 * INQUIRY command with page code parameter set to 0x80
+	 * MODE_SENSE command with cmd[2] == 0x1c
+	 *
+	 * Setup srb and scsi status so this won't be fatal.
+	 * We do this so we can distinguish truly fatal failues
+	 * (srb status == 0x4) and off-line the device in that case.
+	 */
+
+	if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) ||
+	   (stor_pkt->vm_srb.cdb[0] == MODE_SENSE)) {
+		vstor_packet->vm_srb.scsi_status = 0;
+		vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS;
+	}
+
+
+	/* Copy over the status...etc */
+	stor_pkt->vm_srb.scsi_status = vstor_packet->vm_srb.scsi_status;
+	stor_pkt->vm_srb.srb_status = vstor_packet->vm_srb.srb_status;
+	stor_pkt->vm_srb.sense_info_length =
+	vstor_packet->vm_srb.sense_info_length;
+
+	if (vstor_packet->vm_srb.scsi_status != 0 ||
+		vstor_packet->vm_srb.srb_status != SRB_STATUS_SUCCESS){
+		dev_warn(&device->device,
+			 "cmd 0x%x scsi status 0x%x srb status 0x%x\n",
+			 stor_pkt->vm_srb.cdb[0],
+			 vstor_packet->vm_srb.scsi_status,
+			 vstor_packet->vm_srb.srb_status);
+	}
+
+	if ((vstor_packet->vm_srb.scsi_status & 0xFF) == 0x02) {
+		/* CHECK_CONDITION */
+		if (vstor_packet->vm_srb.srb_status &
+			SRB_STATUS_AUTOSENSE_VALID) {
+			/* autosense data available */
+			dev_warn(&device->device,
+				 "stor pkt %p autosense data valid - len %d\n",
+				 request,
+				 vstor_packet->vm_srb.sense_info_length);
+
+			memcpy(request->sense_buffer,
+			       vstor_packet->vm_srb.sense_data,
+			       vstor_packet->vm_srb.sense_info_length);
+
+		}
+	}
+
+	stor_pkt->vm_srb.data_transfer_length =
+	vstor_packet->vm_srb.data_transfer_length;
+
+	storvsc_command_completion(request);
+
+	if (atomic_dec_and_test(&stor_device->num_outstanding_req) &&
+		stor_device->drain_notify)
+		wake_up(&stor_device->waiting_to_drain);
+
+
+}
+
+static void storvsc_on_receive(struct hv_device *device,
+			     struct vstor_packet *vstor_packet,
+			     struct storvsc_cmd_request *request)
+{
+	struct storvsc_scan_work *work;
+	struct storvsc_device *stor_device;
+
+	switch (vstor_packet->operation) {
+	case VSTOR_OPERATION_COMPLETE_IO:
+		storvsc_on_io_completion(device, vstor_packet, request);
+		break;
+
+	case VSTOR_OPERATION_REMOVE_DEVICE:
+	case VSTOR_OPERATION_ENUMERATE_BUS:
+		stor_device = get_in_stor_device(device);
+		work = kmalloc(sizeof(struct storvsc_scan_work), GFP_ATOMIC);
+		if (!work)
+			return;
+
+		INIT_WORK(&work->work, storvsc_bus_scan);
+		work->host = stor_device->host;
+		schedule_work(&work->work);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void storvsc_on_channel_callback(void *context)
+{
+	struct hv_device *device = (struct hv_device *)context;
+	struct storvsc_device *stor_device;
+	u32 bytes_recvd;
+	u64 request_id;
+	unsigned char packet[ALIGN(sizeof(struct vstor_packet), 8)];
+	struct storvsc_cmd_request *request;
+	int ret;
+
+
+	stor_device = get_in_stor_device(device);
+	if (!stor_device)
+		return;
+
+	do {
+		ret = vmbus_recvpacket(device->channel, packet,
+				       ALIGN(sizeof(struct vstor_packet), 8),
+				       &bytes_recvd, &request_id);
+		if (ret == 0 && bytes_recvd > 0) {
+
+			request = (struct storvsc_cmd_request *)
+					(unsigned long)request_id;
+
+			if ((request == &stor_device->init_request) ||
+			    (request == &stor_device->reset_request)) {
+
+				memcpy(&request->vstor_packet, packet,
+				       sizeof(struct vstor_packet));
+				complete(&request->wait_event);
+			} else {
+				storvsc_on_receive(device,
+						(struct vstor_packet *)packet,
+						request);
+			}
+		} else {
+			break;
+		}
+	} while (1);
+
+	return;
+}
+
+static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
+{
+	struct vmstorage_channel_properties props;
+	int ret;
+
+	memset(&props, 0, sizeof(struct vmstorage_channel_properties));
+
+	ret = vmbus_open(device->channel,
+			 ring_size,
+			 ring_size,
+			 (void *)&props,
+			 sizeof(struct vmstorage_channel_properties),
+			 storvsc_on_channel_callback, device);
+
+	if (ret != 0)
+		return ret;
+
+	ret = storvsc_channel_init(device);
+
+	return ret;
+}
+
+static int storvsc_dev_remove(struct hv_device *device)
+{
+	struct storvsc_device *stor_device;
+	unsigned long flags;
+
+	stor_device = hv_get_drvdata(device);
+
+	spin_lock_irqsave(&device->channel->inbound_lock, flags);
+	stor_device->destroy = true;
+	spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
+
+	/*
+	 * At this point, all outbound traffic should be disable. We
+	 * only allow inbound traffic (responses) to proceed so that
+	 * outstanding requests can be completed.
+	 */
+
+	storvsc_wait_to_drain(stor_device);
+
+	/*
+	 * Since we have already drained, we don't need to busy wait
+	 * as was done in final_release_stor_device()
+	 * Note that we cannot set the ext pointer to NULL until
+	 * we have drained - to drain the outgoing packets, we need to
+	 * allow incoming packets.
+	 */
+	spin_lock_irqsave(&device->channel->inbound_lock, flags);
+	hv_set_drvdata(device, NULL);
+	spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
+
+	/* Close the channel */
+	vmbus_close(device->channel);
+
+	kfree(stor_device);
 	return 0;
 }
 
+static int storvsc_do_io(struct hv_device *device,
+			      struct storvsc_cmd_request *request)
+{
+	struct storvsc_device *stor_device;
+	struct vstor_packet *vstor_packet;
+	int ret = 0;
+
+	vstor_packet = &request->vstor_packet;
+	stor_device = get_out_stor_device(device);
+
+	if (!stor_device)
+		return -ENODEV;
+
+
+	request->device  = device;
+
+
+	vstor_packet->flags |= REQUEST_COMPLETION_FLAG;
+
+	vstor_packet->vm_srb.length = sizeof(struct vmscsi_request);
+
+
+	vstor_packet->vm_srb.sense_info_length = STORVSC_SENSE_BUFFER_SIZE;
+
+
+	vstor_packet->vm_srb.data_transfer_length =
+	request->data_buffer.len;
+
+	vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB;
+
+	if (request->data_buffer.len) {
+		ret = vmbus_sendpacket_multipagebuffer(device->channel,
+				&request->data_buffer,
+				vstor_packet,
+				sizeof(struct vstor_packet),
+				(unsigned long)request);
+	} else {
+		ret = vmbus_sendpacket(device->channel, vstor_packet,
+			       sizeof(struct vstor_packet),
+			       (unsigned long)request,
+			       VM_PKT_DATA_INBAND,
+			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+	}
+
+	if (ret != 0)
+		return ret;
+
+	atomic_inc(&stor_device->num_outstanding_req);
+
+	return ret;
+}
+
+static int storvsc_device_alloc(struct scsi_device *sdevice)
+{
+	struct stor_mem_pools *memp;
+	int number = STORVSC_MIN_BUF_NR;
+
+	memp = kzalloc(sizeof(struct stor_mem_pools), GFP_KERNEL);
+	if (!memp)
+		return -ENOMEM;
+
+	memp->request_pool =
+		kmem_cache_create(dev_name(&sdevice->sdev_dev),
+				sizeof(struct storvsc_cmd_request), 0,
+				SLAB_HWCACHE_ALIGN, NULL);
+
+	if (!memp->request_pool)
+		goto err0;
+
+	memp->request_mempool = mempool_create(number, mempool_alloc_slab,
+						mempool_free_slab,
+						memp->request_pool);
+
+	if (!memp->request_mempool)
+		goto err1;
+
+	sdevice->hostdata = memp;
+
+	return 0;
+
+err1:
+	kmem_cache_destroy(memp->request_pool);
+
+err0:
+	kfree(memp);
+	return -ENOMEM;
+}
+
+static void storvsc_device_destroy(struct scsi_device *sdevice)
+{
+	struct stor_mem_pools *memp = sdevice->hostdata;
+
+	mempool_destroy(memp->request_mempool);
+	kmem_cache_destroy(memp->request_pool);
+	kfree(memp);
+	sdevice->hostdata = NULL;
+}
+
+static int storvsc_device_configure(struct scsi_device *sdevice)
+{
+	scsi_adjust_queue_depth(sdevice, MSG_SIMPLE_TAG,
+				STORVSC_MAX_IO_REQUESTS);
+
+	blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE);
+
+	blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY);
+
+	return 0;
+}
 
 static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev,
 			   sector_t capacity, int *info)
@@ -1111,10 +1171,13 @@
 	return 0;
 }
 
-static int storvsc_host_reset(struct hv_device *device)
+static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
 {
+	struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
+	struct hv_device *device = host_dev->dev;
+
 	struct storvsc_device *stor_device;
-	struct hv_storvsc_request *request;
+	struct storvsc_cmd_request *request;
 	struct vstor_packet *vstor_packet;
 	int ret, t;
 
@@ -1153,105 +1216,16 @@
 	return SUCCESS;
 }
 
-
-/*
- * storvsc_host_reset_handler - Reset the scsi HBA
- */
-static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
-{
-	struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
-	struct hv_device *dev = host_dev->dev;
-
-	return storvsc_host_reset(dev);
-}
-
-
-/*
- * storvsc_command_completion - Command completion processing
- */
-static void storvsc_command_completion(struct hv_storvsc_request *request)
-{
-	struct storvsc_cmd_request *cmd_request =
-		(struct storvsc_cmd_request *)request->context;
-	struct scsi_cmnd *scmnd = cmd_request->cmd;
-	struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
-	void (*scsi_done_fn)(struct scsi_cmnd *);
-	struct scsi_sense_hdr sense_hdr;
-	struct vmscsi_request *vm_srb;
-	struct storvsc_scan_work *wrk;
-	struct stor_mem_pools *memp = scmnd->device->hostdata;
-
-	vm_srb = &request->vstor_packet.vm_srb;
-	if (cmd_request->bounce_sgl_count) {
-		if (vm_srb->data_in == READ_TYPE)
-			copy_from_bounce_buffer(scsi_sglist(scmnd),
-					cmd_request->bounce_sgl,
-					scsi_sg_count(scmnd),
-					cmd_request->bounce_sgl_count);
-		destroy_bounce_buffer(cmd_request->bounce_sgl,
-					cmd_request->bounce_sgl_count);
-	}
-
-	/*
-	 * If there is an error; offline the device since all
-	 * error recovery strategies would have already been
-	 * deployed on the host side.
-	 */
-	if (vm_srb->srb_status == 0x4)
-		scmnd->result = DID_TARGET_FAILURE << 16;
-	else
-		scmnd->result = vm_srb->scsi_status;
-
-	/*
-	 * If the LUN is invalid; remove the device.
-	 */
-	if (vm_srb->srb_status == 0x20) {
-		struct storvsc_device *stor_dev;
-		struct hv_device *dev = host_dev->dev;
-		struct Scsi_Host *host;
-
-		stor_dev = get_in_stor_device(dev);
-		host = stor_dev->host;
-
-		wrk = kmalloc(sizeof(struct storvsc_scan_work),
-				GFP_ATOMIC);
-		if (!wrk) {
-			scmnd->result = DID_TARGET_FAILURE << 16;
-		} else {
-			wrk->host = host;
-			wrk->lun = vm_srb->lun;
-			INIT_WORK(&wrk->work, storvsc_remove_lun);
-			schedule_work(&wrk->work);
-		}
-	}
-
-	if (scmnd->result) {
-		if (scsi_normalize_sense(scmnd->sense_buffer,
-				SCSI_SENSE_BUFFERSIZE, &sense_hdr))
-			scsi_print_sense_hdr("storvsc", &sense_hdr);
-	}
-
-	scsi_set_resid(scmnd,
-		request->data_buffer.len -
-		vm_srb->data_transfer_length);
-
-	scsi_done_fn = scmnd->scsi_done;
-
-	scmnd->host_scribble = NULL;
-	scmnd->scsi_done = NULL;
-
-	scsi_done_fn(scmnd);
-
-	mempool_free(cmd_request, memp->request_mempool);
-}
-
-static bool storvsc_check_scsi_cmd(struct scsi_cmnd *scmnd)
+static bool storvsc_scsi_cmd_ok(struct scsi_cmnd *scmnd)
 {
 	bool allowed = true;
 	u8 scsi_op = scmnd->cmnd[0];
 
 	switch (scsi_op) {
-	/* smartd sends this command, which will offline the device */
+	/*
+	 * smartd sends this command and the host does not handle
+	 * this. So, don't send it.
+	 */
 	case SET_WINDOW:
 		scmnd->result = ILLEGAL_REQUEST << 16;
 		allowed = false;
@@ -1262,15 +1236,11 @@
 	return allowed;
 }
 
-/*
- * storvsc_queuecommand - Initiate command processing
- */
 static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
 {
 	int ret;
 	struct hv_host_device *host_dev = shost_priv(host);
 	struct hv_device *dev = host_dev->dev;
-	struct hv_storvsc_request *request;
 	struct storvsc_cmd_request *cmd_request;
 	unsigned int request_size = 0;
 	int i;
@@ -1279,38 +1249,31 @@
 	struct vmscsi_request *vm_srb;
 	struct stor_mem_pools *memp = scmnd->device->hostdata;
 
-	if (storvsc_check_scsi_cmd(scmnd) == false) {
+	if (!storvsc_scsi_cmd_ok(scmnd)) {
 		scmnd->scsi_done(scmnd);
 		return 0;
 	}
 
-	/* If retrying, no need to prep the cmd */
-	if (scmnd->host_scribble) {
-
-		cmd_request =
-			(struct storvsc_cmd_request *)scmnd->host_scribble;
-
-		goto retry_request;
-	}
-
 	request_size = sizeof(struct storvsc_cmd_request);
 
 	cmd_request = mempool_alloc(memp->request_mempool,
 				       GFP_ATOMIC);
+
+	/*
+	 * We might be invoked in an interrupt context; hence
+	 * mempool_alloc() can fail.
+	 */
 	if (!cmd_request)
 		return SCSI_MLQUEUE_DEVICE_BUSY;
 
 	memset(cmd_request, 0, sizeof(struct storvsc_cmd_request));
 
 	/* Setup the cmd request */
-	cmd_request->bounce_sgl_count = 0;
-	cmd_request->bounce_sgl = NULL;
 	cmd_request->cmd = scmnd;
 
 	scmnd->host_scribble = (unsigned char *)cmd_request;
 
-	request = &cmd_request->request;
-	vm_srb = &request->vstor_packet.vm_srb;
+	vm_srb = &cmd_request->vstor_packet.vm_srb;
 
 
 	/* Build the SRB */
@@ -1326,8 +1289,6 @@
 		break;
 	}
 
-	request->on_io_completion = storvsc_command_completion;
-	request->context = cmd_request;/* scmnd; */
 
 	vm_srb->port_number = host_dev->port;
 	vm_srb->path_id = scmnd->device->channel;
@@ -1338,10 +1299,10 @@
 
 	memcpy(vm_srb->cdb, scmnd->cmnd, vm_srb->cdb_length);
 
-	request->sense_buffer = scmnd->sense_buffer;
+	cmd_request->sense_buffer = scmnd->sense_buffer;
 
 
-	request->data_buffer.len = scsi_bufflen(scmnd);
+	cmd_request->data_buffer.len = scsi_bufflen(scmnd);
 	if (scsi_sg_count(scmnd)) {
 		sgl = (struct scatterlist *)scsi_sglist(scmnd);
 		sg_count = scsi_sg_count(scmnd);
@@ -1353,11 +1314,8 @@
 						     scsi_bufflen(scmnd),
 						     vm_srb->data_in);
 			if (!cmd_request->bounce_sgl) {
-				scmnd->host_scribble = NULL;
-				mempool_free(cmd_request,
-						memp->request_mempool);
-
-				return SCSI_MLQUEUE_HOST_BUSY;
+				ret = SCSI_MLQUEUE_HOST_BUSY;
+				goto queue_error;
 			}
 
 			cmd_request->bounce_sgl_count =
@@ -1373,41 +1331,42 @@
 			sg_count = cmd_request->bounce_sgl_count;
 		}
 
-		request->data_buffer.offset = sgl[0].offset;
+		cmd_request->data_buffer.offset = sgl[0].offset;
 
 		for (i = 0; i < sg_count; i++)
-			request->data_buffer.pfn_array[i] =
+			cmd_request->data_buffer.pfn_array[i] =
 				page_to_pfn(sg_page((&sgl[i])));
 
 	} else if (scsi_sglist(scmnd)) {
-		request->data_buffer.offset =
+		cmd_request->data_buffer.offset =
 			virt_to_phys(scsi_sglist(scmnd)) & (PAGE_SIZE-1);
-		request->data_buffer.pfn_array[0] =
+		cmd_request->data_buffer.pfn_array[0] =
 			virt_to_phys(scsi_sglist(scmnd)) >> PAGE_SHIFT;
 	}
 
-retry_request:
 	/* Invokes the vsc to start an IO */
-	ret = storvsc_do_io(dev, &cmd_request->request);
+	ret = storvsc_do_io(dev, cmd_request);
 
 	if (ret == -EAGAIN) {
 		/* no more space */
 
-		if (cmd_request->bounce_sgl_count)
+		if (cmd_request->bounce_sgl_count) {
 			destroy_bounce_buffer(cmd_request->bounce_sgl,
 					cmd_request->bounce_sgl_count);
 
-		mempool_free(cmd_request, memp->request_mempool);
-
-		scmnd->host_scribble = NULL;
-
-		ret = SCSI_MLQUEUE_DEVICE_BUSY;
+			ret = SCSI_MLQUEUE_DEVICE_BUSY;
+			goto queue_error;
+		}
 	}
 
+	return 0;
+
+queue_error:
+	mempool_free(cmd_request, memp->request_mempool);
+	scmnd->host_scribble = NULL;
 	return ret;
 }
 
-/* Scsi driver */
 static struct scsi_host_template scsi_driver = {
 	.module	=		THIS_MODULE,
 	.name =			"storvsc_host_t",
@@ -1448,11 +1407,6 @@
 
 MODULE_DEVICE_TABLE(vmbus, id_table);
 
-
-/*
- * storvsc_probe - Add a new device for this driver
- */
-
 static int storvsc_probe(struct hv_device *device,
 			const struct hv_vmbus_device_id *dev_id)
 {
@@ -1460,7 +1414,6 @@
 	struct Scsi_Host *host;
 	struct hv_host_device *host_dev;
 	bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false);
-	int path = 0;
 	int target = 0;
 	struct storvsc_device *stor_device;
 
@@ -1493,9 +1446,6 @@
 	if (ret)
 		goto err_out1;
 
-	if (dev_is_ide)
-		storvsc_get_ide_info(device, &target, &path);
-
 	host_dev->path = stor_device->path_id;
 	host_dev->target = stor_device->target_id;
 
@@ -1515,12 +1465,14 @@
 
 	if (!dev_is_ide) {
 		scsi_scan_host(host);
-		return 0;
-	}
-	ret = scsi_add_device(host, 0, target, 0);
-	if (ret) {
-		scsi_remove_host(host);
-		goto err_out2;
+	} else {
+		target = (device->dev_instance.b[5] << 8 |
+			 device->dev_instance.b[4]);
+		ret = scsi_add_device(host, 0, target, 0);
+		if (ret) {
+			scsi_remove_host(host);
+			goto err_out2;
+		}
 	}
 	return 0;
 
@@ -1542,7 +1494,17 @@
 	return ret;
 }
 
-/* The one and only one */
+static int storvsc_remove(struct hv_device *dev)
+{
+	struct storvsc_device *stor_device = hv_get_drvdata(dev);
+	struct Scsi_Host *host = stor_device->host;
+
+	scsi_remove_host(host);
+	storvsc_dev_remove(dev);
+	scsi_host_put(host);
+
+	return 0;
+}
 
 static struct hv_driver storvsc_drv = {
 	.name = KBUILD_MODNAME,
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index bb6317f..ff109ae 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -140,19 +140,6 @@
 		put_device(dev->dev);
 }
 
-static inline struct ssb_driver *ssb_driver_get(struct ssb_driver *drv)
-{
-	if (drv)
-		get_driver(&drv->drv);
-	return drv;
-}
-
-static inline void ssb_driver_put(struct ssb_driver *drv)
-{
-	if (drv)
-		put_driver(&drv->drv);
-}
-
 static int ssb_device_resume(struct device *dev)
 {
 	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
@@ -250,11 +237,9 @@
 			ssb_device_put(sdev);
 			continue;
 		}
-		sdrv = ssb_driver_get(drv_to_ssb_drv(sdev->dev->driver));
-		if (!sdrv || SSB_WARN_ON(!sdrv->remove)) {
-			ssb_device_put(sdev);
+		sdrv = drv_to_ssb_drv(sdev->dev->driver);
+		if (SSB_WARN_ON(!sdrv->remove))
 			continue;
-		}
 		sdrv->remove(sdev);
 		ctx->device_frozen[i] = 1;
 	}
@@ -293,7 +278,6 @@
 				   dev_name(sdev->dev));
 			result = err;
 		}
-		ssb_driver_put(sdrv);
 		ssb_device_put(sdev);
 	}
 
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 9e63472..f1abfb1 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -76,8 +76,6 @@
 
 source "drivers/staging/vt6656/Kconfig"
 
-source "drivers/staging/hv/Kconfig"
-
 source "drivers/staging/vme/Kconfig"
 
 source "drivers/staging/sep/Kconfig"
@@ -88,6 +86,8 @@
 
 source "drivers/staging/zcache/Kconfig"
 
+source "drivers/staging/zsmalloc/Kconfig"
+
 source "drivers/staging/wlags49_h2/Kconfig"
 
 source "drivers/staging/wlags49_h25/Kconfig"
@@ -128,4 +128,10 @@
 
 source "drivers/staging/android/Kconfig"
 
+source "drivers/staging/telephony/Kconfig"
+
+source "drivers/staging/ramster/Kconfig"
+
+source "drivers/staging/ozwpan/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 943e148..ffe7d44 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -29,13 +29,12 @@
 obj-$(CONFIG_OCTEON_ETHERNET)	+= octeon/
 obj-$(CONFIG_VT6655)		+= vt6655/
 obj-$(CONFIG_VT6656)		+= vt6656/
-obj-$(CONFIG_HYPERV)		+= hv/
 obj-$(CONFIG_VME_BUS)		+= vme/
 obj-$(CONFIG_DX_SEP)            += sep/
 obj-$(CONFIG_IIO)		+= iio/
 obj-$(CONFIG_ZRAM)		+= zram/
-obj-$(CONFIG_XVMALLOC)		+= zram/
 obj-$(CONFIG_ZCACHE)		+= zcache/
+obj-$(CONFIG_ZSMALLOC)		+= zsmalloc/
 obj-$(CONFIG_WLAGS49_H2)	+= wlags49_h2/
 obj-$(CONFIG_WLAGS49_H25)	+= wlags49_h25/
 obj-$(CONFIG_FB_SM7XX)		+= sm7xx/
@@ -55,3 +54,6 @@
 obj-$(CONFIG_MFD_NVEC)		+= nvec/
 obj-$(CONFIG_DRM_OMAP)		+= omapdrm/
 obj-$(CONFIG_ANDROID)		+= android/
+obj-$(CONFIG_PHONE)		+= telephony/
+obj-$(CONFIG_RAMSTER)		+= ramster/
+obj-$(CONFIG_USB_WPAN_HCD)	+= ozwpan/
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index fef3580..08a3b11 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -25,65 +25,17 @@
 	tristate "Android log driver"
 	default n
 
-config ANDROID_RAM_CONSOLE
-	bool "Android RAM buffer console"
-	depends on !S390 && !UML
-	default n
-
-config ANDROID_RAM_CONSOLE_ENABLE_VERBOSE
-	bool "Enable verbose console messages on Android RAM console"
-	default y
-	depends on ANDROID_RAM_CONSOLE
-
-menuconfig ANDROID_RAM_CONSOLE_ERROR_CORRECTION
-	bool "Android RAM Console Enable error correction"
-	default n
-	depends on ANDROID_RAM_CONSOLE
-	depends on !ANDROID_RAM_CONSOLE_EARLY_INIT
+config ANDROID_PERSISTENT_RAM
+	bool
 	select REED_SOLOMON
 	select REED_SOLOMON_ENC8
 	select REED_SOLOMON_DEC8
 
-if ANDROID_RAM_CONSOLE_ERROR_CORRECTION
-
-config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE
-	int "Android RAM Console Data data size"
-	default 128
-	help
-	  Must be a power of 2.
-
-config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE
-	int "Android RAM Console ECC size"
-	default 16
-
-config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE
-	int "Android RAM Console Symbol size"
-	default 8
-
-config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL
-	hex "Android RAM Console Polynomial"
-	default 0x19 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 4)
-	default 0x29 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 5)
-	default 0x61 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 6)
-	default 0x89 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 7)
-	default 0x11d if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 8)
-
-endif # ANDROID_RAM_CONSOLE_ERROR_CORRECTION
-
-config ANDROID_RAM_CONSOLE_EARLY_INIT
-	bool "Start Android RAM console early"
+config ANDROID_RAM_CONSOLE
+	bool "Android RAM buffer console"
+	depends on !S390 && !UML
+	select ANDROID_PERSISTENT_RAM
 	default n
-	depends on ANDROID_RAM_CONSOLE
-
-config ANDROID_RAM_CONSOLE_EARLY_ADDR
-	hex "Android RAM console virtual address"
-	default 0
-	depends on ANDROID_RAM_CONSOLE_EARLY_INIT
-
-config ANDROID_RAM_CONSOLE_EARLY_SIZE
-	hex "Android RAM console buffer size"
-	default 0
-	depends on ANDROID_RAM_CONSOLE_EARLY_INIT
 
 config ANDROID_TIMED_OUTPUT
 	bool "Timed output class driver"
@@ -102,6 +54,32 @@
 
 source "drivers/staging/android/switch/Kconfig"
 
+config ANDROID_INTF_ALARM
+	bool "Android alarm driver"
+	depends on RTC_CLASS
+	default n
+	help
+	  Provides non-wakeup and rtc backed wakeup alarms based on rtc or
+	  elapsed realtime, and a non-wakeup alarm on the monotonic clock.
+	  Also provides an interface to set the wall time which must be used
+	  for elapsed realtime to work.
+
+config ANDROID_INTF_ALARM_DEV
+	bool "Android alarm device"
+	depends on ANDROID_INTF_ALARM
+	default y
+	help
+	  Exports the alarm interface to user-space.
+
+config ANDROID_ALARM_OLDDRV_COMPAT
+	bool "Android Alarm compatability with old drivers"
+	depends on ANDROID_INTF_ALARM
+	default n
+	help
+	  Provides preprocessor alias to aid compatability with
+	  older out-of-tree drivers that use the Android Alarm
+	  in-kernel API. This will be removed eventually.
+
 endif # if ANDROID
 
 endmenu
diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile
index 5fcc24f..9b6c9ed 100644
--- a/drivers/staging/android/Makefile
+++ b/drivers/staging/android/Makefile
@@ -1,8 +1,11 @@
 obj-$(CONFIG_ANDROID_BINDER_IPC)	+= binder.o
 obj-$(CONFIG_ASHMEM)			+= ashmem.o
 obj-$(CONFIG_ANDROID_LOGGER)		+= logger.o
+obj-$(CONFIG_ANDROID_PERSISTENT_RAM)	+= persistent_ram.o
 obj-$(CONFIG_ANDROID_RAM_CONSOLE)	+= ram_console.o
 obj-$(CONFIG_ANDROID_TIMED_OUTPUT)	+= timed_output.o
 obj-$(CONFIG_ANDROID_TIMED_GPIO)	+= timed_gpio.o
 obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER)	+= lowmemorykiller.o
 obj-$(CONFIG_ANDROID_SWITCH)		+= switch/
+obj-$(CONFIG_ANDROID_INTF_ALARM)	+= alarm.o
+obj-$(CONFIG_ANDROID_INTF_ALARM_DEV)	+= alarm-dev.o
diff --git a/drivers/staging/android/TODO b/drivers/staging/android/TODO
index e59c5be..b15fb0d 100644
--- a/drivers/staging/android/TODO
+++ b/drivers/staging/android/TODO
@@ -3,7 +3,7 @@
 	- sparse fixes
 	- rename files to be not so "generic"
 	- make sure things build as modules properly
-	- add proper arch dependancies as needed
+	- add proper arch dependencies as needed
 	- audit userspace interfaces to make sure they are sane
 
 Please send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc:
diff --git a/drivers/staging/android/alarm-dev.c b/drivers/staging/android/alarm-dev.c
new file mode 100644
index 0000000..03efb34
--- /dev/null
+++ b/drivers/staging/android/alarm-dev.c
@@ -0,0 +1,297 @@
+/* drivers/rtc/alarm-dev.c
+ *
+ * Copyright (C) 2007-2009 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/time.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include "android_alarm.h"
+
+/* XXX - Hack out wakelocks, while they are out of tree */
+struct wake_lock {
+	int i;
+};
+#define wake_lock(x)
+#define wake_lock_timeout(x, y)
+#define wake_unlock(x)
+#define WAKE_LOCK_SUSPEND 0
+#define wake_lock_init(x, y, z) ((x)->i = 1)
+#define wake_lock_destroy(x)
+
+#define ANDROID_ALARM_PRINT_INFO (1U << 0)
+#define ANDROID_ALARM_PRINT_IO (1U << 1)
+#define ANDROID_ALARM_PRINT_INT (1U << 2)
+
+
+static int debug_mask = ANDROID_ALARM_PRINT_INFO;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define pr_alarm(debug_level_mask, args...) \
+	do { \
+		if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \
+			pr_info(args); \
+		} \
+	} while (0)
+
+#define ANDROID_ALARM_WAKEUP_MASK ( \
+	ANDROID_ALARM_RTC_WAKEUP_MASK | \
+	ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
+
+/* support old usespace code */
+#define ANDROID_ALARM_SET_OLD               _IOW('a', 2, time_t) /* set alarm */
+#define ANDROID_ALARM_SET_AND_WAIT_OLD      _IOW('a', 3, time_t)
+
+static int alarm_opened;
+static DEFINE_SPINLOCK(alarm_slock);
+static struct wake_lock alarm_wake_lock;
+static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue);
+static uint32_t alarm_pending;
+static uint32_t alarm_enabled;
+static uint32_t wait_pending;
+
+static struct android_alarm alarms[ANDROID_ALARM_TYPE_COUNT];
+
+static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int rv = 0;
+	unsigned long flags;
+	struct timespec new_alarm_time;
+	struct timespec new_rtc_time;
+	struct timespec tmp_time;
+	enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd);
+	uint32_t alarm_type_mask = 1U << alarm_type;
+
+	if (alarm_type >= ANDROID_ALARM_TYPE_COUNT)
+		return -EINVAL;
+
+	if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_GET_TIME(0)) {
+		if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+			return -EPERM;
+		if (file->private_data == NULL &&
+		    cmd != ANDROID_ALARM_SET_RTC) {
+			spin_lock_irqsave(&alarm_slock, flags);
+			if (alarm_opened) {
+				spin_unlock_irqrestore(&alarm_slock, flags);
+				return -EBUSY;
+			}
+			alarm_opened = 1;
+			file->private_data = (void *)1;
+			spin_unlock_irqrestore(&alarm_slock, flags);
+		}
+	}
+
+	switch (ANDROID_ALARM_BASE_CMD(cmd)) {
+	case ANDROID_ALARM_CLEAR(0):
+		spin_lock_irqsave(&alarm_slock, flags);
+		pr_alarm(IO, "alarm %d clear\n", alarm_type);
+		android_alarm_try_to_cancel(&alarms[alarm_type]);
+		if (alarm_pending) {
+			alarm_pending &= ~alarm_type_mask;
+			if (!alarm_pending && !wait_pending)
+				wake_unlock(&alarm_wake_lock);
+		}
+		alarm_enabled &= ~alarm_type_mask;
+		spin_unlock_irqrestore(&alarm_slock, flags);
+		break;
+
+	case ANDROID_ALARM_SET_OLD:
+	case ANDROID_ALARM_SET_AND_WAIT_OLD:
+		if (get_user(new_alarm_time.tv_sec, (int __user *)arg)) {
+			rv = -EFAULT;
+			goto err1;
+		}
+		new_alarm_time.tv_nsec = 0;
+		goto from_old_alarm_set;
+
+	case ANDROID_ALARM_SET_AND_WAIT(0):
+	case ANDROID_ALARM_SET(0):
+		if (copy_from_user(&new_alarm_time, (void __user *)arg,
+		    sizeof(new_alarm_time))) {
+			rv = -EFAULT;
+			goto err1;
+		}
+from_old_alarm_set:
+		spin_lock_irqsave(&alarm_slock, flags);
+		pr_alarm(IO, "alarm %d set %ld.%09ld\n", alarm_type,
+			new_alarm_time.tv_sec, new_alarm_time.tv_nsec);
+		alarm_enabled |= alarm_type_mask;
+		android_alarm_start_range(&alarms[alarm_type],
+			timespec_to_ktime(new_alarm_time),
+			timespec_to_ktime(new_alarm_time));
+		spin_unlock_irqrestore(&alarm_slock, flags);
+		if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
+		    && cmd != ANDROID_ALARM_SET_AND_WAIT_OLD)
+			break;
+		/* fall though */
+	case ANDROID_ALARM_WAIT:
+		spin_lock_irqsave(&alarm_slock, flags);
+		pr_alarm(IO, "alarm wait\n");
+		if (!alarm_pending && wait_pending) {
+			wake_unlock(&alarm_wake_lock);
+			wait_pending = 0;
+		}
+		spin_unlock_irqrestore(&alarm_slock, flags);
+		rv = wait_event_interruptible(alarm_wait_queue, alarm_pending);
+		if (rv)
+			goto err1;
+		spin_lock_irqsave(&alarm_slock, flags);
+		rv = alarm_pending;
+		wait_pending = 1;
+		alarm_pending = 0;
+		spin_unlock_irqrestore(&alarm_slock, flags);
+		break;
+	case ANDROID_ALARM_SET_RTC:
+		if (copy_from_user(&new_rtc_time, (void __user *)arg,
+		    sizeof(new_rtc_time))) {
+			rv = -EFAULT;
+			goto err1;
+		}
+		rv = android_alarm_set_rtc(new_rtc_time);
+		spin_lock_irqsave(&alarm_slock, flags);
+		alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
+		wake_up(&alarm_wait_queue);
+		spin_unlock_irqrestore(&alarm_slock, flags);
+		if (rv < 0)
+			goto err1;
+		break;
+	case ANDROID_ALARM_GET_TIME(0):
+		switch (alarm_type) {
+		case ANDROID_ALARM_RTC_WAKEUP:
+		case ANDROID_ALARM_RTC:
+			getnstimeofday(&tmp_time);
+			break;
+		case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP:
+		case ANDROID_ALARM_ELAPSED_REALTIME:
+			tmp_time =
+				ktime_to_timespec(alarm_get_elapsed_realtime());
+			break;
+		case ANDROID_ALARM_TYPE_COUNT:
+		case ANDROID_ALARM_SYSTEMTIME:
+			ktime_get_ts(&tmp_time);
+			break;
+		}
+		if (copy_to_user((void __user *)arg, &tmp_time,
+		    sizeof(tmp_time))) {
+			rv = -EFAULT;
+			goto err1;
+		}
+		break;
+
+	default:
+		rv = -EINVAL;
+		goto err1;
+	}
+err1:
+	return rv;
+}
+
+static int alarm_open(struct inode *inode, struct file *file)
+{
+	file->private_data = NULL;
+	return 0;
+}
+
+static int alarm_release(struct inode *inode, struct file *file)
+{
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&alarm_slock, flags);
+	if (file->private_data != 0) {
+		for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
+			uint32_t alarm_type_mask = 1U << i;
+			if (alarm_enabled & alarm_type_mask) {
+				pr_alarm(INFO, "alarm_release: clear alarm, "
+					"pending %d\n",
+					!!(alarm_pending & alarm_type_mask));
+				alarm_enabled &= ~alarm_type_mask;
+			}
+			spin_unlock_irqrestore(&alarm_slock, flags);
+			android_alarm_cancel(&alarms[i]);
+			spin_lock_irqsave(&alarm_slock, flags);
+		}
+		if (alarm_pending | wait_pending) {
+			if (alarm_pending)
+				pr_alarm(INFO, "alarm_release: clear "
+					"pending alarms %x\n", alarm_pending);
+			wake_unlock(&alarm_wake_lock);
+			wait_pending = 0;
+			alarm_pending = 0;
+		}
+		alarm_opened = 0;
+	}
+	spin_unlock_irqrestore(&alarm_slock, flags);
+	return 0;
+}
+
+static void alarm_triggered(struct android_alarm *alarm)
+{
+	unsigned long flags;
+	uint32_t alarm_type_mask = 1U << alarm->type;
+
+	pr_alarm(INT, "alarm_triggered type %d\n", alarm->type);
+	spin_lock_irqsave(&alarm_slock, flags);
+	if (alarm_enabled & alarm_type_mask) {
+		wake_lock_timeout(&alarm_wake_lock, 5 * HZ);
+		alarm_enabled &= ~alarm_type_mask;
+		alarm_pending |= alarm_type_mask;
+		wake_up(&alarm_wait_queue);
+	}
+	spin_unlock_irqrestore(&alarm_slock, flags);
+}
+
+static const struct file_operations alarm_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = alarm_ioctl,
+	.open = alarm_open,
+	.release = alarm_release,
+};
+
+static struct miscdevice alarm_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "alarm",
+	.fops = &alarm_fops,
+};
+
+static int __init alarm_dev_init(void)
+{
+	int err;
+	int i;
+
+	err = misc_register(&alarm_device);
+	if (err)
+		return err;
+
+	for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++)
+		android_alarm_init(&alarms[i], i, alarm_triggered);
+	wake_lock_init(&alarm_wake_lock, WAKE_LOCK_SUSPEND, "alarm");
+
+	return 0;
+}
+
+static void  __exit alarm_dev_exit(void)
+{
+	misc_deregister(&alarm_device);
+	wake_lock_destroy(&alarm_wake_lock);
+}
+
+module_init(alarm_dev_init);
+module_exit(alarm_dev_exit);
+
diff --git a/drivers/staging/android/alarm.c b/drivers/staging/android/alarm.c
new file mode 100644
index 0000000..c68950b
--- /dev/null
+++ b/drivers/staging/android/alarm.c
@@ -0,0 +1,601 @@
+/* drivers/rtc/alarm.c
+ *
+ * Copyright (C) 2007-2009 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/time.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include "android_alarm.h"
+
+/* XXX - Hack out wakelocks, while they are out of tree */
+struct wake_lock {
+	int i;
+};
+#define wake_lock(x)
+#define wake_lock_timeout(x, y)
+#define wake_unlock(x)
+#define WAKE_LOCK_SUSPEND 0
+#define wake_lock_init(x, y, z) ((x)->i = 1)
+#define wake_lock_destroy(x)
+
+#define ANDROID_ALARM_PRINT_ERROR (1U << 0)
+#define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1)
+#define ANDROID_ALARM_PRINT_TSET (1U << 2)
+#define ANDROID_ALARM_PRINT_CALL (1U << 3)
+#define ANDROID_ALARM_PRINT_SUSPEND (1U << 4)
+#define ANDROID_ALARM_PRINT_INT (1U << 5)
+#define ANDROID_ALARM_PRINT_FLOW (1U << 6)
+
+static int debug_mask = ANDROID_ALARM_PRINT_ERROR | \
+			ANDROID_ALARM_PRINT_INIT_STATUS;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define pr_alarm(debug_level_mask, args...) \
+	do { \
+		if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \
+			pr_info(args); \
+		} \
+	} while (0)
+
+#define ANDROID_ALARM_WAKEUP_MASK ( \
+	ANDROID_ALARM_RTC_WAKEUP_MASK | \
+	ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
+
+/* support old usespace code */
+#define ANDROID_ALARM_SET_OLD               _IOW('a', 2, time_t) /* set alarm */
+#define ANDROID_ALARM_SET_AND_WAIT_OLD      _IOW('a', 3, time_t)
+
+struct alarm_queue {
+	struct rb_root alarms;
+	struct rb_node *first;
+	struct hrtimer timer;
+	ktime_t delta;
+	bool stopped;
+	ktime_t stopped_time;
+};
+
+static struct rtc_device *alarm_rtc_dev;
+static DEFINE_SPINLOCK(alarm_slock);
+static DEFINE_MUTEX(alarm_setrtc_mutex);
+static struct wake_lock alarm_rtc_wake_lock;
+static struct platform_device *alarm_platform_dev;
+struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT];
+static bool suspended;
+
+static void update_timer_locked(struct alarm_queue *base, bool head_removed)
+{
+	struct android_alarm *alarm;
+	bool is_wakeup = base == &alarms[ANDROID_ALARM_RTC_WAKEUP] ||
+			base == &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
+
+	if (base->stopped) {
+		pr_alarm(FLOW, "changed alarm while setting the wall time\n");
+		return;
+	}
+
+	if (is_wakeup && !suspended && head_removed)
+		wake_unlock(&alarm_rtc_wake_lock);
+
+	if (!base->first)
+		return;
+
+	alarm = container_of(base->first, struct android_alarm, node);
+
+	pr_alarm(FLOW, "selected alarm, type %d, func %pF at %lld\n",
+		alarm->type, alarm->function, ktime_to_ns(alarm->expires));
+
+	if (is_wakeup && suspended) {
+		pr_alarm(FLOW, "changed alarm while suspened\n");
+		wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
+		return;
+	}
+
+	hrtimer_try_to_cancel(&base->timer);
+	base->timer.node.expires = ktime_add(base->delta, alarm->expires);
+	base->timer._softexpires = ktime_add(base->delta, alarm->softexpires);
+	hrtimer_start_expires(&base->timer, HRTIMER_MODE_ABS);
+}
+
+static void alarm_enqueue_locked(struct android_alarm *alarm)
+{
+	struct alarm_queue *base = &alarms[alarm->type];
+	struct rb_node **link = &base->alarms.rb_node;
+	struct rb_node *parent = NULL;
+	struct android_alarm *entry;
+	int leftmost = 1;
+	bool was_first = false;
+
+	pr_alarm(FLOW, "added alarm, type %d, func %pF at %lld\n",
+		alarm->type, alarm->function, ktime_to_ns(alarm->expires));
+
+	if (base->first == &alarm->node) {
+		base->first = rb_next(&alarm->node);
+		was_first = true;
+	}
+	if (!RB_EMPTY_NODE(&alarm->node)) {
+		rb_erase(&alarm->node, &base->alarms);
+		RB_CLEAR_NODE(&alarm->node);
+	}
+
+	while (*link) {
+		parent = *link;
+		entry = rb_entry(parent, struct android_alarm, node);
+		/*
+		* We dont care about collisions. Nodes with
+		* the same expiry time stay together.
+		*/
+		if (alarm->expires.tv64 < entry->expires.tv64) {
+			link = &(*link)->rb_left;
+		} else {
+			link = &(*link)->rb_right;
+			leftmost = 0;
+		}
+	}
+	if (leftmost)
+		base->first = &alarm->node;
+	if (leftmost || was_first)
+		update_timer_locked(base, was_first);
+
+	rb_link_node(&alarm->node, parent, link);
+	rb_insert_color(&alarm->node, &base->alarms);
+}
+
+/**
+ * android_alarm_init - initialize an alarm
+ * @alarm:	the alarm to be initialized
+ * @type:	the alarm type to be used
+ * @function:	alarm callback function
+ */
+void android_alarm_init(struct android_alarm *alarm,
+	enum android_alarm_type type, void (*function)(struct android_alarm *))
+{
+	RB_CLEAR_NODE(&alarm->node);
+	alarm->type = type;
+	alarm->function = function;
+
+	pr_alarm(FLOW, "created alarm, type %d, func %pF\n", type, function);
+}
+
+
+/**
+ * android_alarm_start_range - (re)start an alarm
+ * @alarm:	the alarm to be added
+ * @start:	earliest expiry time
+ * @end:	expiry time
+ */
+void android_alarm_start_range(struct android_alarm *alarm, ktime_t start,
+								ktime_t end)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&alarm_slock, flags);
+	alarm->softexpires = start;
+	alarm->expires = end;
+	alarm_enqueue_locked(alarm);
+	spin_unlock_irqrestore(&alarm_slock, flags);
+}
+
+/**
+ * android_alarm_try_to_cancel - try to deactivate an alarm
+ * @alarm:	alarm to stop
+ *
+ * Returns:
+ *  0 when the alarm was not active
+ *  1 when the alarm was active
+ * -1 when the alarm may currently be excuting the callback function and
+ *    cannot be stopped (it may also be inactive)
+ */
+int android_alarm_try_to_cancel(struct android_alarm *alarm)
+{
+	struct alarm_queue *base = &alarms[alarm->type];
+	unsigned long flags;
+	bool first = false;
+	int ret = 0;
+
+	spin_lock_irqsave(&alarm_slock, flags);
+	if (!RB_EMPTY_NODE(&alarm->node)) {
+		pr_alarm(FLOW, "canceled alarm, type %d, func %pF at %lld\n",
+			alarm->type, alarm->function,
+			ktime_to_ns(alarm->expires));
+		ret = 1;
+		if (base->first == &alarm->node) {
+			base->first = rb_next(&alarm->node);
+			first = true;
+		}
+		rb_erase(&alarm->node, &base->alarms);
+		RB_CLEAR_NODE(&alarm->node);
+		if (first)
+			update_timer_locked(base, true);
+	} else
+		pr_alarm(FLOW, "tried to cancel alarm, type %d, func %pF\n",
+			alarm->type, alarm->function);
+	spin_unlock_irqrestore(&alarm_slock, flags);
+	if (!ret && hrtimer_callback_running(&base->timer))
+		ret = -1;
+	return ret;
+}
+
+/**
+ * android_alarm_cancel - cancel an alarm and wait for the handler to finish.
+ * @alarm:	the alarm to be cancelled
+ *
+ * Returns:
+ *  0 when the alarm was not active
+ *  1 when the alarm was active
+ */
+int android_alarm_cancel(struct android_alarm *alarm)
+{
+	for (;;) {
+		int ret = android_alarm_try_to_cancel(alarm);
+		if (ret >= 0)
+			return ret;
+		cpu_relax();
+	}
+}
+
+/**
+ * alarm_set_rtc - set the kernel and rtc walltime
+ * @new_time:	timespec value containing the new time
+ */
+int android_alarm_set_rtc(struct timespec new_time)
+{
+	int i;
+	int ret;
+	unsigned long flags;
+	struct rtc_time rtc_new_rtc_time;
+	struct timespec tmp_time;
+
+	rtc_time_to_tm(new_time.tv_sec, &rtc_new_rtc_time);
+
+	pr_alarm(TSET, "set rtc %ld %ld - rtc %02d:%02d:%02d %02d/%02d/%04d\n",
+		new_time.tv_sec, new_time.tv_nsec,
+		rtc_new_rtc_time.tm_hour, rtc_new_rtc_time.tm_min,
+		rtc_new_rtc_time.tm_sec, rtc_new_rtc_time.tm_mon + 1,
+		rtc_new_rtc_time.tm_mday,
+		rtc_new_rtc_time.tm_year + 1900);
+
+	mutex_lock(&alarm_setrtc_mutex);
+	spin_lock_irqsave(&alarm_slock, flags);
+	wake_lock(&alarm_rtc_wake_lock);
+	getnstimeofday(&tmp_time);
+	for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
+		hrtimer_try_to_cancel(&alarms[i].timer);
+		alarms[i].stopped = true;
+		alarms[i].stopped_time = timespec_to_ktime(tmp_time);
+	}
+	alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta =
+		alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta =
+		ktime_sub(alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta,
+			timespec_to_ktime(timespec_sub(tmp_time, new_time)));
+	spin_unlock_irqrestore(&alarm_slock, flags);
+	ret = do_settimeofday(&new_time);
+	spin_lock_irqsave(&alarm_slock, flags);
+	for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
+		alarms[i].stopped = false;
+		update_timer_locked(&alarms[i], false);
+	}
+	spin_unlock_irqrestore(&alarm_slock, flags);
+	if (ret < 0) {
+		pr_alarm(ERROR, "alarm_set_rtc: Failed to set time\n");
+		goto err;
+	}
+	if (!alarm_rtc_dev) {
+		pr_alarm(ERROR,
+			"alarm_set_rtc: no RTC, time will be lost on reboot\n");
+		goto err;
+	}
+	ret = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time);
+	if (ret < 0)
+		pr_alarm(ERROR, "alarm_set_rtc: "
+			"Failed to set RTC, time will be lost on reboot\n");
+err:
+	wake_unlock(&alarm_rtc_wake_lock);
+	mutex_unlock(&alarm_setrtc_mutex);
+	return ret;
+}
+
+/**
+ * alarm_get_elapsed_realtime - get the elapsed real time in ktime_t format
+ *
+ * returns the time in ktime_t format
+ */
+ktime_t alarm_get_elapsed_realtime(void)
+{
+	ktime_t now;
+	unsigned long flags;
+	struct alarm_queue *base = &alarms[ANDROID_ALARM_ELAPSED_REALTIME];
+
+	spin_lock_irqsave(&alarm_slock, flags);
+	now = base->stopped ? base->stopped_time : ktime_get_real();
+	now = ktime_sub(now, base->delta);
+	spin_unlock_irqrestore(&alarm_slock, flags);
+	return now;
+}
+
+static enum hrtimer_restart alarm_timer_triggered(struct hrtimer *timer)
+{
+	struct alarm_queue *base;
+	struct android_alarm *alarm;
+	unsigned long flags;
+	ktime_t now;
+
+	spin_lock_irqsave(&alarm_slock, flags);
+
+	base = container_of(timer, struct alarm_queue, timer);
+	now = base->stopped ? base->stopped_time : hrtimer_cb_get_time(timer);
+	now = ktime_sub(now, base->delta);
+
+	pr_alarm(INT, "alarm_timer_triggered type %ld at %lld\n",
+		base - alarms, ktime_to_ns(now));
+
+	while (base->first) {
+		alarm = container_of(base->first, struct android_alarm, node);
+		if (alarm->softexpires.tv64 > now.tv64) {
+			pr_alarm(FLOW, "don't call alarm, %pF, %lld (s %lld)\n",
+				alarm->function, ktime_to_ns(alarm->expires),
+				ktime_to_ns(alarm->softexpires));
+			break;
+		}
+		base->first = rb_next(&alarm->node);
+		rb_erase(&alarm->node, &base->alarms);
+		RB_CLEAR_NODE(&alarm->node);
+		pr_alarm(CALL, "call alarm, type %d, func %pF, %lld (s %lld)\n",
+			alarm->type, alarm->function,
+			ktime_to_ns(alarm->expires),
+			ktime_to_ns(alarm->softexpires));
+		spin_unlock_irqrestore(&alarm_slock, flags);
+		alarm->function(alarm);
+		spin_lock_irqsave(&alarm_slock, flags);
+	}
+	if (!base->first)
+		pr_alarm(FLOW, "no more alarms of type %ld\n", base - alarms);
+	update_timer_locked(base, true);
+	spin_unlock_irqrestore(&alarm_slock, flags);
+	return HRTIMER_NORESTART;
+}
+
+static void alarm_triggered_func(void *p)
+{
+	struct rtc_device *rtc = alarm_rtc_dev;
+	if (!(rtc->irq_data & RTC_AF))
+		return;
+	pr_alarm(INT, "rtc alarm triggered\n");
+	wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
+}
+
+static int alarm_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	int                 err = 0;
+	unsigned long       flags;
+	struct rtc_wkalrm   rtc_alarm;
+	struct rtc_time     rtc_current_rtc_time;
+	unsigned long       rtc_current_time;
+	unsigned long       rtc_alarm_time;
+	struct timespec     rtc_delta;
+	struct timespec     wall_time;
+	struct alarm_queue *wakeup_queue = NULL;
+	struct alarm_queue *tmp_queue = NULL;
+
+	pr_alarm(SUSPEND, "alarm_suspend(%p, %d)\n", pdev, state.event);
+
+	spin_lock_irqsave(&alarm_slock, flags);
+	suspended = true;
+	spin_unlock_irqrestore(&alarm_slock, flags);
+
+	hrtimer_cancel(&alarms[ANDROID_ALARM_RTC_WAKEUP].timer);
+	hrtimer_cancel(&alarms[
+			ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].timer);
+
+	tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP];
+	if (tmp_queue->first)
+		wakeup_queue = tmp_queue;
+	tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
+	if (tmp_queue->first && (!wakeup_queue ||
+				hrtimer_get_expires(&tmp_queue->timer).tv64 <
+				hrtimer_get_expires(&wakeup_queue->timer).tv64))
+		wakeup_queue = tmp_queue;
+	if (wakeup_queue) {
+		rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
+		getnstimeofday(&wall_time);
+		rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time);
+		set_normalized_timespec(&rtc_delta,
+					wall_time.tv_sec - rtc_current_time,
+					wall_time.tv_nsec);
+
+		rtc_alarm_time = timespec_sub(ktime_to_timespec(
+			hrtimer_get_expires(&wakeup_queue->timer)),
+			rtc_delta).tv_sec;
+
+		rtc_time_to_tm(rtc_alarm_time, &rtc_alarm.time);
+		rtc_alarm.enabled = 1;
+		rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
+		rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
+		rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time);
+		pr_alarm(SUSPEND,
+			"rtc alarm set at %ld, now %ld, rtc delta %ld.%09ld\n",
+			rtc_alarm_time, rtc_current_time,
+			rtc_delta.tv_sec, rtc_delta.tv_nsec);
+		if (rtc_current_time + 1 >= rtc_alarm_time) {
+			pr_alarm(SUSPEND, "alarm about to go off\n");
+			memset(&rtc_alarm, 0, sizeof(rtc_alarm));
+			rtc_alarm.enabled = 0;
+			rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
+
+			spin_lock_irqsave(&alarm_slock, flags);
+			suspended = false;
+			wake_lock_timeout(&alarm_rtc_wake_lock, 2 * HZ);
+			update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP],
+									false);
+			update_timer_locked(&alarms[
+				ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], false);
+			err = -EBUSY;
+			spin_unlock_irqrestore(&alarm_slock, flags);
+		}
+	}
+	return err;
+}
+
+static int alarm_resume(struct platform_device *pdev)
+{
+	struct rtc_wkalrm alarm;
+	unsigned long       flags;
+
+	pr_alarm(SUSPEND, "alarm_resume(%p)\n", pdev);
+
+	memset(&alarm, 0, sizeof(alarm));
+	alarm.enabled = 0;
+	rtc_set_alarm(alarm_rtc_dev, &alarm);
+
+	spin_lock_irqsave(&alarm_slock, flags);
+	suspended = false;
+	update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], false);
+	update_timer_locked(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP],
+									false);
+	spin_unlock_irqrestore(&alarm_slock, flags);
+
+	return 0;
+}
+
+static struct rtc_task alarm_rtc_task = {
+	.func = alarm_triggered_func
+};
+
+static int rtc_alarm_add_device(struct device *dev,
+				struct class_interface *class_intf)
+{
+	int err;
+	struct rtc_device *rtc = to_rtc_device(dev);
+
+	mutex_lock(&alarm_setrtc_mutex);
+
+	if (alarm_rtc_dev) {
+		err = -EBUSY;
+		goto err1;
+	}
+
+	alarm_platform_dev =
+		platform_device_register_simple("alarm", -1, NULL, 0);
+	if (IS_ERR(alarm_platform_dev)) {
+		err = PTR_ERR(alarm_platform_dev);
+		goto err2;
+	}
+	err = rtc_irq_register(rtc, &alarm_rtc_task);
+	if (err)
+		goto err3;
+	alarm_rtc_dev = rtc;
+	pr_alarm(INIT_STATUS, "using rtc device, %s, for alarms", rtc->name);
+	mutex_unlock(&alarm_setrtc_mutex);
+
+	return 0;
+
+err3:
+	platform_device_unregister(alarm_platform_dev);
+err2:
+err1:
+	mutex_unlock(&alarm_setrtc_mutex);
+	return err;
+}
+
+static void rtc_alarm_remove_device(struct device *dev,
+				    struct class_interface *class_intf)
+{
+	if (dev == &alarm_rtc_dev->dev) {
+		pr_alarm(INIT_STATUS, "lost rtc device for alarms");
+		rtc_irq_unregister(alarm_rtc_dev, &alarm_rtc_task);
+		platform_device_unregister(alarm_platform_dev);
+		alarm_rtc_dev = NULL;
+	}
+}
+
+static struct class_interface rtc_alarm_interface = {
+	.add_dev = &rtc_alarm_add_device,
+	.remove_dev = &rtc_alarm_remove_device,
+};
+
+static struct platform_driver alarm_driver = {
+	.suspend = alarm_suspend,
+	.resume = alarm_resume,
+	.driver = {
+		.name = "alarm"
+	}
+};
+
+static int __init alarm_late_init(void)
+{
+	unsigned long   flags;
+	struct timespec tmp_time, system_time;
+
+	/* this needs to run after the rtc is read at boot */
+	spin_lock_irqsave(&alarm_slock, flags);
+	/* We read the current rtc and system time so we can later calulate
+	 * elasped realtime to be (boot_systemtime + rtc - boot_rtc) ==
+	 * (rtc - (boot_rtc - boot_systemtime))
+	 */
+	getnstimeofday(&tmp_time);
+	ktime_get_ts(&system_time);
+	alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta =
+		alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta =
+			timespec_to_ktime(timespec_sub(tmp_time, system_time));
+
+	spin_unlock_irqrestore(&alarm_slock, flags);
+	return 0;
+}
+
+static int __init alarm_driver_init(void)
+{
+	int err;
+	int i;
+
+	for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
+		hrtimer_init(&alarms[i].timer,
+				CLOCK_REALTIME, HRTIMER_MODE_ABS);
+		alarms[i].timer.function = alarm_timer_triggered;
+	}
+	hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].timer,
+		     CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+	alarms[ANDROID_ALARM_SYSTEMTIME].timer.function = alarm_timer_triggered;
+	err = platform_driver_register(&alarm_driver);
+	if (err < 0)
+		goto err1;
+	wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc");
+	rtc_alarm_interface.class = rtc_class;
+	err = class_interface_register(&rtc_alarm_interface);
+	if (err < 0)
+		goto err2;
+
+	return 0;
+
+err2:
+	wake_lock_destroy(&alarm_rtc_wake_lock);
+	platform_driver_unregister(&alarm_driver);
+err1:
+	return err;
+}
+
+static void  __exit alarm_exit(void)
+{
+	class_interface_unregister(&rtc_alarm_interface);
+	wake_lock_destroy(&alarm_rtc_wake_lock);
+	platform_driver_unregister(&alarm_driver);
+}
+
+late_initcall(alarm_late_init);
+module_init(alarm_driver_init);
+module_exit(alarm_exit);
+
diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h
new file mode 100644
index 0000000..6eecbde
--- /dev/null
+++ b/drivers/staging/android/android_alarm.h
@@ -0,0 +1,121 @@
+/* include/linux/android_alarm.h
+ *
+ * Copyright (C) 2006-2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _LINUX_ANDROID_ALARM_H
+#define _LINUX_ANDROID_ALARM_H
+
+#include <linux/ioctl.h>
+#include <linux/time.h>
+
+enum android_alarm_type {
+	/* return code bit numbers or set alarm arg */
+	ANDROID_ALARM_RTC_WAKEUP,
+	ANDROID_ALARM_RTC,
+	ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
+	ANDROID_ALARM_ELAPSED_REALTIME,
+	ANDROID_ALARM_SYSTEMTIME,
+
+	ANDROID_ALARM_TYPE_COUNT,
+
+	/* return code bit numbers */
+	/* ANDROID_ALARM_TIME_CHANGE = 16 */
+};
+
+#ifdef __KERNEL__
+
+#include <linux/ktime.h>
+#include <linux/rbtree.h>
+
+/*
+ * The alarm interface is similar to the hrtimer interface but adds support
+ * for wakeup from suspend. It also adds an elapsed realtime clock that can
+ * be used for periodic timers that need to keep runing while the system is
+ * suspended and not be disrupted when the wall time is set.
+ */
+
+/**
+ * struct alarm - the basic alarm structure
+ * @node:	red black tree node for time ordered insertion
+ * @type:	alarm type. rtc/elapsed-realtime/systemtime, wakeup/non-wakeup.
+ * @softexpires: the absolute earliest expiry time of the alarm.
+ * @expires:	the absolute expiry time.
+ * @function:	alarm expiry callback function
+ *
+ * The alarm structure must be initialized by alarm_init()
+ *
+ */
+
+struct android_alarm {
+	struct rb_node		node;
+	enum android_alarm_type type;
+	ktime_t			softexpires;
+	ktime_t			expires;
+	void			(*function)(struct android_alarm *);
+};
+
+void android_alarm_init(struct android_alarm *alarm,
+	enum android_alarm_type type, void (*function)(struct android_alarm *));
+void android_alarm_start_range(struct android_alarm *alarm, ktime_t start,
+								ktime_t end);
+int android_alarm_try_to_cancel(struct android_alarm *alarm);
+int android_alarm_cancel(struct android_alarm *alarm);
+ktime_t alarm_get_elapsed_realtime(void);
+
+/* set rtc while preserving elapsed realtime */
+int android_alarm_set_rtc(const struct timespec ts);
+
+#ifdef CONFIG_ANDROID_ALARM_OLDDRV_COMPAT
+/*
+ * Some older drivers depend on the old API,
+ * so provide compatability macros for now.
+ */
+#define alarm android_alarm
+#define alarm_init(x, y, z) android_alarm_init(x, y, z)
+#define alarm_start_range(x, y, z) android_alarm_start_range(x, y, z)
+#define alarm_try_to_cancel(x) android_alarm_try_to_cancel(x)
+#define alarm_cancel(x) android_alarm_cancel(x)
+#define alarm_set_rtc(x) android_alarm_set_rtc(x)
+#endif
+
+
+#endif
+
+enum android_alarm_return_flags {
+	ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
+	ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
+	ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK =
+				1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
+	ANDROID_ALARM_ELAPSED_REALTIME_MASK =
+				1U << ANDROID_ALARM_ELAPSED_REALTIME,
+	ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
+	ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
+};
+
+/* Disable alarm */
+#define ANDROID_ALARM_CLEAR(type)           _IO('a', 0 | ((type) << 4))
+
+/* Ack last alarm and wait for next */
+#define ANDROID_ALARM_WAIT                  _IO('a', 1)
+
+#define ALARM_IOW(c, type, size)            _IOW('a', (c) | ((type) << 4), size)
+/* Set alarm */
+#define ANDROID_ALARM_SET(type)             ALARM_IOW(2, type, struct timespec)
+#define ANDROID_ALARM_SET_AND_WAIT(type)    ALARM_IOW(3, type, struct timespec)
+#define ANDROID_ALARM_GET_TIME(type)        ALARM_IOW(4, type, struct timespec)
+#define ANDROID_ALARM_SET_RTC               _IOW('a', 5, struct timespec)
+#define ANDROID_ALARM_BASE_CMD(cmd)         (cmd & ~(_IOC(0, 0, 0xf0, 0)))
+#define ANDROID_ALARM_IOCTL_TO_TYPE(cmd)    (_IOC_NR(cmd) >> 4)
+
+#endif
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 99052bf..9f1f27e 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -315,7 +315,7 @@
 	get_file(asma->file);
 
 	/*
-	 * XXX - Reworked to use shmem_zero_setup() instead of 
+	 * XXX - Reworked to use shmem_zero_setup() instead of
 	 * shmem_set_file while we're in staging. -jstultz
 	 */
 	if (vma->vm_flags & VM_SHARED) {
@@ -680,7 +680,7 @@
 	return ret;
 }
 
-static struct file_operations ashmem_fops = {
+static const struct file_operations ashmem_fops = {
 	.owner = THIS_MODULE,
 	.open = ashmem_open,
 	.release = ashmem_release,
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index f0b7e66..59e0953 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -103,7 +103,7 @@
 	BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION;
 module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO);
 
-static int binder_debug_no_lock;
+static bool binder_debug_no_lock;
 module_param_named(proc_no_lock, binder_debug_no_lock, bool, S_IWUSR | S_IRUGO);
 
 static DECLARE_WAIT_QUEUE_HEAD(binder_user_error_wait);
@@ -258,7 +258,7 @@
 };
 
 struct binder_buffer {
-	struct list_head entry; /* free and allocated entries by addesss */
+	struct list_head entry; /* free and allocated entries by address */
 	struct rb_node rb_node; /* free entry by size or allocated entry */
 				/* by address */
 	unsigned free:1;
@@ -288,6 +288,7 @@
 	struct rb_root refs_by_node;
 	int pid;
 	struct vm_area_struct *vma;
+	struct mm_struct *vma_vm_mm;
 	struct task_struct *tsk;
 	struct files_struct *files;
 	struct hlist_node deferred_work_node;
@@ -633,7 +634,7 @@
 	if (mm) {
 		down_write(&mm->mmap_sem);
 		vma = proc->vma;
-		if (vma && mm != vma->vm_mm) {
+		if (vma && mm != proc->vma_vm_mm) {
 			pr_err("binder: %d: vma mm and task mm mismatch\n",
 				proc->pid);
 			vma = NULL;
@@ -2776,6 +2777,7 @@
 		     (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags,
 		     (unsigned long)pgprot_val(vma->vm_page_prot));
 	proc->vma = NULL;
+	proc->vma_vm_mm = NULL;
 	binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES);
 }
 
@@ -2858,6 +2860,7 @@
 	barrier();
 	proc->files = get_files_struct(proc->tsk);
 	proc->vma = vma;
+	proc->vma_vm_mm = vma->vm_mm;
 
 	/*printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p\n",
 		 proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index ffc2d04..ea69b6a 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -60,7 +60,11 @@
 };
 
 /* logger_offset - returns index 'n' into the log via (optimized) modulus */
-#define logger_offset(n)	((n) & (log->size - 1))
+size_t logger_offset(struct logger_log *log, size_t n)
+{
+	return n & (log->size-1);
+}
+
 
 /*
  * file_get_log - Given a file structure, return the associated log
@@ -89,20 +93,24 @@
  * get_entry_len - Grabs the length of the payload of the next entry starting
  * from 'off'.
  *
+ * An entry length is 2 bytes (16 bits) in host endian order.
+ * In the log, the length does not include the size of the log entry structure.
+ * This function returns the size including the log entry structure.
+ *
  * Caller needs to hold log->mutex.
  */
 static __u32 get_entry_len(struct logger_log *log, size_t off)
 {
 	__u16 val;
 
-	switch (log->size - off) {
-	case 1:
-		memcpy(&val, log->buffer + off, 1);
-		memcpy(((char *) &val) + 1, log->buffer, 1);
-		break;
-	default:
-		memcpy(&val, log->buffer + off, 2);
-	}
+	/* copy 2 bytes from buffer, in memcpy order, */
+	/* handling possible wrap at end of buffer */
+
+	((__u8 *)&val)[0] = log->buffer[off];
+	if (likely(off+1 < log->size))
+		((__u8 *)&val)[1] = log->buffer[off+1];
+	else
+		((__u8 *)&val)[1] = log->buffer[0];
 
 	return sizeof(struct logger_entry) + val;
 }
@@ -137,7 +145,7 @@
 		if (copy_to_user(buf + len, log->buffer, count - len))
 			return -EFAULT;
 
-	reader->r_off = logger_offset(reader->r_off + count);
+	reader->r_off = logger_offset(log, reader->r_off + count);
 
 	return count;
 }
@@ -164,9 +172,10 @@
 
 start:
 	while (1) {
+		mutex_lock(&log->mutex);
+
 		prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE);
 
-		mutex_lock(&log->mutex);
 		ret = (log->w_off == reader->r_off);
 		mutex_unlock(&log->mutex);
 		if (!ret)
@@ -225,7 +234,7 @@
 
 	do {
 		size_t nr = get_entry_len(log, off);
-		off = logger_offset(off + nr);
+		off = logger_offset(log, off + nr);
 		count += nr;
 	} while (count < len);
 
@@ -233,16 +242,28 @@
 }
 
 /*
- * clock_interval - is a < c < b in mod-space? Put another way, does the line
- * from a to b cross c?
+ * is_between - is a < c < b, accounting for wrapping of a, b, and c
+ *    positions in the buffer
+ *
+ * That is, if a<b, check for c between a and b
+ * and if a>b, check for c outside (not between) a and b
+ *
+ * |------- a xxxxxxxx b --------|
+ *               c^
+ *
+ * |xxxxx b --------- a xxxxxxxxx|
+ *    c^
+ *  or                    c^
  */
-static inline int clock_interval(size_t a, size_t b, size_t c)
+static inline int is_between(size_t a, size_t b, size_t c)
 {
-	if (b < a) {
-		if (a < c || b >= c)
+	if (a < b) {
+		/* is c between a and b? */
+		if (a < c && c <= b)
 			return 1;
 	} else {
-		if (a < c && b >= c)
+		/* is c outside of b through a? */
+		if (c <= b || a < c)
 			return 1;
 	}
 
@@ -260,14 +281,14 @@
 static void fix_up_readers(struct logger_log *log, size_t len)
 {
 	size_t old = log->w_off;
-	size_t new = logger_offset(old + len);
+	size_t new = logger_offset(log, old + len);
 	struct logger_reader *reader;
 
-	if (clock_interval(old, new, log->head))
+	if (is_between(old, new, log->head))
 		log->head = get_next_entry(log, log->head, len);
 
 	list_for_each_entry(reader, &log->readers, list)
-		if (clock_interval(old, new, reader->r_off))
+		if (is_between(old, new, reader->r_off))
 			reader->r_off = get_next_entry(log, reader->r_off, len);
 }
 
@@ -286,7 +307,7 @@
 	if (count != len)
 		memcpy(log->buffer, buf + len, count - len);
 
-	log->w_off = logger_offset(log->w_off + count);
+	log->w_off = logger_offset(log, log->w_off + count);
 
 }
 
@@ -309,9 +330,15 @@
 
 	if (count != len)
 		if (copy_from_user(log->buffer, buf + len, count - len))
+			/*
+			 * Note that by not updating w_off, this abandons the
+			 * portion of the new entry that *was* successfully
+			 * copied, just above.  This is intentional to avoid
+			 * message corruption from missing fragments.
+			 */
 			return -EFAULT;
 
-	log->w_off = logger_offset(log->w_off + count);
+	log->w_off = logger_offset(log, log->w_off + count);
 
 	return count;
 }
@@ -432,7 +459,12 @@
 {
 	if (file->f_mode & FMODE_READ) {
 		struct logger_reader *reader = file->private_data;
+		struct logger_log *log = reader->log;
+
+		mutex_lock(&log->mutex);
 		list_del(&reader->list);
+		mutex_unlock(&log->mutex);
+
 		kfree(reader);
 	}
 
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index efc7dc1..052b43e 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -1,16 +1,17 @@
 /* drivers/misc/lowmemorykiller.c
  *
  * The lowmemorykiller driver lets user-space specify a set of memory thresholds
- * where processes with a range of oom_adj values will get killed. Specify the
- * minimum oom_adj values in /sys/module/lowmemorykiller/parameters/adj and the
- * number of free pages in /sys/module/lowmemorykiller/parameters/minfree. Both
- * files take a comma separated list of numbers in ascending order.
+ * where processes with a range of oom_score_adj values will get killed. Specify
+ * the minimum oom_score_adj values in
+ * /sys/module/lowmemorykiller/parameters/adj and the number of free pages in
+ * /sys/module/lowmemorykiller/parameters/minfree. Both files take a comma
+ * separated list of numbers in ascending order.
  *
  * For example, write "0,8" to /sys/module/lowmemorykiller/parameters/adj and
  * "1024,4096" to /sys/module/lowmemorykiller/parameters/minfree to kill
- * processes with a oom_adj value of 8 or higher when the free memory drops
- * below 4096 pages and kill processes with a oom_adj value of 0 or higher
- * when the free memory drops below 1024 pages.
+ * processes with a oom_score_adj value of 8 or higher when the free memory
+ * drops below 4096 pages and kill processes with a oom_score_adj value of 0 or
+ * higher when the free memory drops below 1024 pages.
  *
  * The driver considers memory used for caches to be free, but if a large
  * percentage of the cached memory is locked this can be very inaccurate
@@ -34,6 +35,7 @@
 #include <linux/mm.h>
 #include <linux/oom.h>
 #include <linux/sched.h>
+#include <linux/rcupdate.h>
 #include <linux/profile.h>
 #include <linux/notifier.h>
 
@@ -45,7 +47,7 @@
 	12,
 };
 static int lowmem_adj_size = 4;
-static size_t lowmem_minfree[6] = {
+static int lowmem_minfree[6] = {
 	3 * 512,	/* 6MB */
 	2 * 1024,	/* 8MB */
 	4 * 1024,	/* 16MB */
@@ -73,23 +75,23 @@
 task_notify_func(struct notifier_block *self, unsigned long val, void *data)
 {
 	struct task_struct *task = data;
-	if (task == lowmem_deathpending) {
+
+	if (task == lowmem_deathpending)
 		lowmem_deathpending = NULL;
-		task_handoff_unregister(&task_nb);
-	}
+
 	return NOTIFY_OK;
 }
 
 static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 {
-	struct task_struct *p;
+	struct task_struct *tsk;
 	struct task_struct *selected = NULL;
 	int rem = 0;
 	int tasksize;
 	int i;
-	int min_adj = OOM_ADJUST_MAX + 1;
+	int min_score_adj = OOM_SCORE_ADJ_MAX + 1;
 	int selected_tasksize = 0;
-	int selected_oom_adj;
+	int selected_oom_score_adj;
 	int array_size = ARRAY_SIZE(lowmem_adj);
 	int other_free = global_page_state(NR_FREE_PAGES);
 	int other_file = global_page_state(NR_FILE_PAGES) -
@@ -115,80 +117,77 @@
 	for (i = 0; i < array_size; i++) {
 		if (other_free < lowmem_minfree[i] &&
 		    other_file < lowmem_minfree[i]) {
-			min_adj = lowmem_adj[i];
+			min_score_adj = lowmem_adj[i];
 			break;
 		}
 	}
 	if (sc->nr_to_scan > 0)
 		lowmem_print(3, "lowmem_shrink %lu, %x, ofree %d %d, ma %d\n",
 				sc->nr_to_scan, sc->gfp_mask, other_free,
-				other_file, min_adj);
+				other_file, min_score_adj);
 	rem = global_page_state(NR_ACTIVE_ANON) +
 		global_page_state(NR_ACTIVE_FILE) +
 		global_page_state(NR_INACTIVE_ANON) +
 		global_page_state(NR_INACTIVE_FILE);
-	if (sc->nr_to_scan <= 0 || min_adj == OOM_ADJUST_MAX + 1) {
+	if (sc->nr_to_scan <= 0 || min_score_adj == OOM_SCORE_ADJ_MAX + 1) {
 		lowmem_print(5, "lowmem_shrink %lu, %x, return %d\n",
 			     sc->nr_to_scan, sc->gfp_mask, rem);
 		return rem;
 	}
-	selected_oom_adj = min_adj;
+	selected_oom_score_adj = min_score_adj;
 
-	read_lock(&tasklist_lock);
-	for_each_process(p) {
-		struct mm_struct *mm;
-		struct signal_struct *sig;
-		int oom_adj;
+	rcu_read_lock();
+	for_each_process(tsk) {
+		struct task_struct *p;
+		int oom_score_adj;
 
-		task_lock(p);
-		mm = p->mm;
-		sig = p->signal;
-		if (!mm || !sig) {
+		if (tsk->flags & PF_KTHREAD)
+			continue;
+
+		p = find_lock_task_mm(tsk);
+		if (!p)
+			continue;
+
+		oom_score_adj = p->signal->oom_score_adj;
+		if (oom_score_adj < min_score_adj) {
 			task_unlock(p);
 			continue;
 		}
-		oom_adj = sig->oom_adj;
-		if (oom_adj < min_adj) {
-			task_unlock(p);
-			continue;
-		}
-		tasksize = get_mm_rss(mm);
+		tasksize = get_mm_rss(p->mm);
 		task_unlock(p);
 		if (tasksize <= 0)
 			continue;
 		if (selected) {
-			if (oom_adj < selected_oom_adj)
+			if (oom_score_adj < selected_oom_score_adj)
 				continue;
-			if (oom_adj == selected_oom_adj &&
+			if (oom_score_adj == selected_oom_score_adj &&
 			    tasksize <= selected_tasksize)
 				continue;
 		}
 		selected = p;
 		selected_tasksize = tasksize;
-		selected_oom_adj = oom_adj;
+		selected_oom_score_adj = oom_score_adj;
 		lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n",
-			     p->pid, p->comm, oom_adj, tasksize);
+			     p->pid, p->comm, oom_score_adj, tasksize);
 	}
 	if (selected) {
 		lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n",
 			     selected->pid, selected->comm,
-			     selected_oom_adj, selected_tasksize);
+			     selected_oom_score_adj, selected_tasksize);
 		/*
-		 * If CONFIG_PROFILING is off, then task_handoff_register()
-		 * is a nop. In that case we don't want to stall the killer
-		 * by setting lowmem_deathpending.
+		 * If CONFIG_PROFILING is off, then we don't want to stall
+		 * the killer by setting lowmem_deathpending.
 		 */
 #ifdef CONFIG_PROFILING
 		lowmem_deathpending = selected;
 		lowmem_deathpending_timeout = jiffies + HZ;
-		task_handoff_register(&task_nb);
 #endif
-		force_sig(SIGKILL, selected);
+		send_sig(SIGKILL, selected, 0);
 		rem -= selected_tasksize;
 	}
 	lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n",
 		     sc->nr_to_scan, sc->gfp_mask, rem);
-	read_unlock(&tasklist_lock);
+	rcu_read_unlock();
 	return rem;
 }
 
@@ -199,6 +198,7 @@
 
 static int __init lowmem_init(void)
 {
+	task_handoff_register(&task_nb);
 	register_shrinker(&lowmem_shrinker);
 	return 0;
 }
@@ -206,6 +206,7 @@
 static void __exit lowmem_exit(void)
 {
 	unregister_shrinker(&lowmem_shrinker);
+	task_handoff_unregister(&task_nb);
 }
 
 module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR);
diff --git a/drivers/staging/android/persistent_ram.c b/drivers/staging/android/persistent_ram.c
new file mode 100644
index 0000000..e08f257
--- /dev/null
+++ b/drivers/staging/android/persistent_ram.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/memblock.h>
+#include <linux/rslib.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include "persistent_ram.h"
+
+struct persistent_ram_buffer {
+	uint32_t    sig;
+	atomic_t    start;
+	atomic_t    size;
+	uint8_t     data[0];
+};
+
+#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
+
+static __initdata LIST_HEAD(persistent_ram_list);
+
+static inline size_t buffer_size(struct persistent_ram_zone *prz)
+{
+	return atomic_read(&prz->buffer->size);
+}
+
+static inline size_t buffer_start(struct persistent_ram_zone *prz)
+{
+	return atomic_read(&prz->buffer->start);
+}
+
+/* increase and wrap the start pointer, returning the old value */
+static inline size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
+{
+	int old;
+	int new;
+
+	do {
+		old = atomic_read(&prz->buffer->start);
+		new = old + a;
+		while (unlikely(new > prz->buffer_size))
+			new -= prz->buffer_size;
+	} while (atomic_cmpxchg(&prz->buffer->start, old, new) != old);
+
+	return old;
+}
+
+/* increase the size counter until it hits the max size */
+static inline void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
+{
+	size_t old;
+	size_t new;
+
+	if (atomic_read(&prz->buffer->size) == prz->buffer_size)
+		return;
+
+	do {
+		old = atomic_read(&prz->buffer->size);
+		new = old + a;
+		if (new > prz->buffer_size)
+			new = prz->buffer_size;
+	} while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
+}
+
+/* increase the size counter, retuning an error if it hits the max size */
+static inline ssize_t buffer_size_add_clamp(struct persistent_ram_zone *prz,
+	size_t a)
+{
+	size_t old;
+	size_t new;
+
+	do {
+		old = atomic_read(&prz->buffer->size);
+		new = old + a;
+		if (new > prz->buffer_size)
+			return -ENOMEM;
+	} while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
+
+	return 0;
+}
+
+static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
+	uint8_t *data, size_t len, uint8_t *ecc)
+{
+	int i;
+	uint16_t par[prz->ecc_size];
+
+	/* Initialize the parity buffer */
+	memset(par, 0, sizeof(par));
+	encode_rs8(prz->rs_decoder, data, len, par, 0);
+	for (i = 0; i < prz->ecc_size; i++)
+		ecc[i] = par[i];
+}
+
+static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz,
+	void *data, size_t len, uint8_t *ecc)
+{
+	int i;
+	uint16_t par[prz->ecc_size];
+
+	for (i = 0; i < prz->ecc_size; i++)
+		par[i] = ecc[i];
+	return decode_rs8(prz->rs_decoder, data, par, len,
+				NULL, 0, NULL, 0, NULL);
+}
+
+static void notrace persistent_ram_update_ecc(struct persistent_ram_zone *prz,
+	unsigned int start, unsigned int count)
+{
+	struct persistent_ram_buffer *buffer = prz->buffer;
+	uint8_t *buffer_end = buffer->data + prz->buffer_size;
+	uint8_t *block;
+	uint8_t *par;
+	int ecc_block_size = prz->ecc_block_size;
+	int ecc_size = prz->ecc_size;
+	int size = prz->ecc_block_size;
+
+	if (!prz->ecc)
+		return;
+
+	block = buffer->data + (start & ~(ecc_block_size - 1));
+	par = prz->par_buffer + (start / ecc_block_size) * prz->ecc_size;
+
+	do {
+		if (block + ecc_block_size > buffer_end)
+			size = buffer_end - block;
+		persistent_ram_encode_rs8(prz, block, size, par);
+		block += ecc_block_size;
+		par += ecc_size;
+	} while (block < buffer->data + start + count);
+}
+
+static void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz)
+{
+	struct persistent_ram_buffer *buffer = prz->buffer;
+
+	if (!prz->ecc)
+		return;
+
+	persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer),
+				  prz->par_header);
+}
+
+static void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
+{
+	struct persistent_ram_buffer *buffer = prz->buffer;
+	uint8_t *block;
+	uint8_t *par;
+
+	if (!prz->ecc)
+		return;
+
+	block = buffer->data;
+	par = prz->par_buffer;
+	while (block < buffer->data + buffer_size(prz)) {
+		int numerr;
+		int size = prz->ecc_block_size;
+		if (block + size > buffer->data + prz->buffer_size)
+			size = buffer->data + prz->buffer_size - block;
+		numerr = persistent_ram_decode_rs8(prz, block, size, par);
+		if (numerr > 0) {
+			pr_devel("persistent_ram: error in block %p, %d\n",
+			       block, numerr);
+			prz->corrected_bytes += numerr;
+		} else if (numerr < 0) {
+			pr_devel("persistent_ram: uncorrectable error in block %p\n",
+				block);
+			prz->bad_blocks++;
+		}
+		block += prz->ecc_block_size;
+		par += prz->ecc_size;
+	}
+}
+
+static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
+	size_t buffer_size)
+{
+	int numerr;
+	struct persistent_ram_buffer *buffer = prz->buffer;
+	int ecc_blocks;
+
+	if (!prz->ecc)
+		return 0;
+
+	prz->ecc_block_size = 128;
+	prz->ecc_size = 16;
+	prz->ecc_symsize = 8;
+	prz->ecc_poly = 0x11d;
+
+	ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size);
+	prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size;
+
+	if (prz->buffer_size > buffer_size) {
+		pr_err("persistent_ram: invalid size %zu, non-ecc datasize %zu\n",
+		       buffer_size, prz->buffer_size);
+		return -EINVAL;
+	}
+
+	prz->par_buffer = buffer->data + prz->buffer_size;
+	prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size;
+
+	/*
+	 * first consecutive root is 0
+	 * primitive element to generate roots = 1
+	 */
+	prz->rs_decoder = init_rs(prz->ecc_symsize, prz->ecc_poly, 0, 1,
+				  prz->ecc_size);
+	if (prz->rs_decoder == NULL) {
+		pr_info("persistent_ram: init_rs failed\n");
+		return -EINVAL;
+	}
+
+	prz->corrected_bytes = 0;
+	prz->bad_blocks = 0;
+
+	numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer),
+					   prz->par_header);
+	if (numerr > 0) {
+		pr_info("persistent_ram: error in header, %d\n", numerr);
+		prz->corrected_bytes += numerr;
+	} else if (numerr < 0) {
+		pr_info("persistent_ram: uncorrectable error in header\n");
+		prz->bad_blocks++;
+	}
+
+	return 0;
+}
+
+ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
+	char *str, size_t len)
+{
+	ssize_t ret;
+
+	if (prz->corrected_bytes || prz->bad_blocks)
+		ret = snprintf(str, len, ""
+			"\n%d Corrected bytes, %d unrecoverable blocks\n",
+			prz->corrected_bytes, prz->bad_blocks);
+	else
+		ret = snprintf(str, len, "\nNo errors detected\n");
+
+	return ret;
+}
+
+static void notrace persistent_ram_update(struct persistent_ram_zone *prz,
+	const void *s, unsigned int start, unsigned int count)
+{
+	struct persistent_ram_buffer *buffer = prz->buffer;
+	memcpy(buffer->data + start, s, count);
+	persistent_ram_update_ecc(prz, start, count);
+}
+
+static void __init
+persistent_ram_save_old(struct persistent_ram_zone *prz)
+{
+	struct persistent_ram_buffer *buffer = prz->buffer;
+	size_t size = buffer_size(prz);
+	size_t start = buffer_start(prz);
+	char *dest;
+
+	persistent_ram_ecc_old(prz);
+
+	dest = kmalloc(size, GFP_KERNEL);
+	if (dest == NULL) {
+		pr_err("persistent_ram: failed to allocate buffer\n");
+		return;
+	}
+
+	prz->old_log = dest;
+	prz->old_log_size = size;
+	memcpy(prz->old_log, &buffer->data[start], size - start);
+	memcpy(prz->old_log + size - start, &buffer->data[0], start);
+}
+
+int notrace persistent_ram_write(struct persistent_ram_zone *prz,
+	const void *s, unsigned int count)
+{
+	int rem;
+	int c = count;
+	size_t start;
+
+	if (unlikely(c > prz->buffer_size)) {
+		s += c - prz->buffer_size;
+		c = prz->buffer_size;
+	}
+
+	buffer_size_add_clamp(prz, c);
+
+	start = buffer_start_add(prz, c);
+
+	rem = prz->buffer_size - start;
+	if (unlikely(rem < c)) {
+		persistent_ram_update(prz, s, start, rem);
+		s += rem;
+		c -= rem;
+		start = 0;
+	}
+	persistent_ram_update(prz, s, start, c);
+
+	persistent_ram_update_header_ecc(prz);
+
+	return count;
+}
+
+size_t persistent_ram_old_size(struct persistent_ram_zone *prz)
+{
+	return prz->old_log_size;
+}
+
+void *persistent_ram_old(struct persistent_ram_zone *prz)
+{
+	return prz->old_log;
+}
+
+void persistent_ram_free_old(struct persistent_ram_zone *prz)
+{
+	kfree(prz->old_log);
+	prz->old_log = NULL;
+	prz->old_log_size = 0;
+}
+
+static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
+		struct persistent_ram_zone *prz)
+{
+	struct page **pages;
+	phys_addr_t page_start;
+	unsigned int page_count;
+	pgprot_t prot;
+	unsigned int i;
+
+	page_start = start - offset_in_page(start);
+	page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
+
+	prot = pgprot_noncached(PAGE_KERNEL);
+
+	pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL);
+	if (!pages) {
+		pr_err("%s: Failed to allocate array for %u pages\n", __func__,
+			page_count);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < page_count; i++) {
+		phys_addr_t addr = page_start + i * PAGE_SIZE;
+		pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
+	}
+	prz->vaddr = vmap(pages, page_count, VM_MAP, prot);
+	kfree(pages);
+	if (!prz->vaddr) {
+		pr_err("%s: Failed to map %u pages\n", __func__, page_count);
+		return -ENOMEM;
+	}
+
+	prz->buffer = prz->vaddr + offset_in_page(start);
+	prz->buffer_size = size - sizeof(struct persistent_ram_buffer);
+
+	return 0;
+}
+
+static int __init persistent_ram_buffer_init(const char *name,
+		struct persistent_ram_zone *prz)
+{
+	int i;
+	struct persistent_ram *ram;
+	struct persistent_ram_descriptor *desc;
+	phys_addr_t start;
+
+	list_for_each_entry(ram, &persistent_ram_list, node) {
+		start = ram->start;
+		for (i = 0; i < ram->num_descs; i++) {
+			desc = &ram->descs[i];
+			if (!strcmp(desc->name, name))
+				return persistent_ram_buffer_map(start,
+						desc->size, prz);
+			start += desc->size;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static  __init
+struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc)
+{
+	struct persistent_ram_zone *prz;
+	int ret;
+
+	prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
+	if (!prz) {
+		pr_err("persistent_ram: failed to allocate persistent ram zone\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	INIT_LIST_HEAD(&prz->node);
+
+	ret = persistent_ram_buffer_init(dev_name(dev), prz);
+	if (ret) {
+		pr_err("persistent_ram: failed to initialize buffer\n");
+		return ERR_PTR(ret);
+	}
+
+	prz->ecc = ecc;
+	ret = persistent_ram_init_ecc(prz, prz->buffer_size);
+	if (ret)
+		return ERR_PTR(ret);
+
+	if (prz->buffer->sig == PERSISTENT_RAM_SIG) {
+		if (buffer_size(prz) > prz->buffer_size ||
+		    buffer_start(prz) > buffer_size(prz))
+			pr_info("persistent_ram: found existing invalid buffer,"
+				" size %ld, start %ld\n",
+			       buffer_size(prz), buffer_start(prz));
+		else {
+			pr_info("persistent_ram: found existing buffer,"
+				" size %ld, start %ld\n",
+			       buffer_size(prz), buffer_start(prz));
+			persistent_ram_save_old(prz);
+		}
+	} else {
+		pr_info("persistent_ram: no valid data in buffer"
+			" (sig = 0x%08x)\n", prz->buffer->sig);
+	}
+
+	prz->buffer->sig = PERSISTENT_RAM_SIG;
+	atomic_set(&prz->buffer->start, 0);
+	atomic_set(&prz->buffer->size, 0);
+
+	return prz;
+}
+
+struct persistent_ram_zone * __init
+persistent_ram_init_ringbuffer(struct device *dev, bool ecc)
+{
+	return __persistent_ram_init(dev, ecc);
+}
+
+int __init persistent_ram_early_init(struct persistent_ram *ram)
+{
+	int ret;
+
+	ret = memblock_reserve(ram->start, ram->size);
+	if (ret) {
+		pr_err("Failed to reserve persistent memory from %08lx-%08lx\n",
+			(long)ram->start, (long)(ram->start + ram->size - 1));
+		return ret;
+	}
+
+	list_add_tail(&ram->node, &persistent_ram_list);
+
+	pr_info("Initialized persistent memory from %08lx-%08lx\n",
+		(long)ram->start, (long)(ram->start + ram->size - 1));
+
+	return 0;
+}
diff --git a/drivers/staging/android/persistent_ram.h b/drivers/staging/android/persistent_ram.h
new file mode 100644
index 0000000..f41e208
--- /dev/null
+++ b/drivers/staging/android/persistent_ram.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __LINUX_PERSISTENT_RAM_H__
+#define __LINUX_PERSISTENT_RAM_H__
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/types.h>
+
+struct persistent_ram_buffer;
+
+struct persistent_ram_descriptor {
+	const char	*name;
+	phys_addr_t	size;
+};
+
+struct persistent_ram {
+	phys_addr_t	start;
+	phys_addr_t	size;
+
+	int					num_descs;
+	struct persistent_ram_descriptor	*descs;
+
+	struct list_head node;
+};
+
+struct persistent_ram_zone {
+	struct list_head node;
+	void *vaddr;
+	struct persistent_ram_buffer *buffer;
+	size_t buffer_size;
+
+	/* ECC correction */
+	bool ecc;
+	char *par_buffer;
+	char *par_header;
+	struct rs_control *rs_decoder;
+	int corrected_bytes;
+	int bad_blocks;
+	int ecc_block_size;
+	int ecc_size;
+	int ecc_symsize;
+	int ecc_poly;
+
+	char *old_log;
+	size_t old_log_size;
+	size_t old_log_footer_size;
+	bool early;
+};
+
+int persistent_ram_early_init(struct persistent_ram *ram);
+
+struct persistent_ram_zone *persistent_ram_init_ringbuffer(struct device *dev,
+		bool ecc);
+
+int persistent_ram_write(struct persistent_ram_zone *prz, const void *s,
+	unsigned int count);
+
+size_t persistent_ram_old_size(struct persistent_ram_zone *prz);
+void *persistent_ram_old(struct persistent_ram_zone *prz);
+void persistent_ram_free_old(struct persistent_ram_zone *prz);
+ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
+	char *str, size_t len);
+
+#endif
diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c
index 6d4d679..ce140ff 100644
--- a/drivers/staging/android/ram_console.c
+++ b/drivers/staging/android/ram_console.c
@@ -21,129 +21,24 @@
 #include <linux/string.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
+#include "persistent_ram.h"
 #include "ram_console.h"
 
-#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
-#include <linux/rslib.h>
-#endif
-
-struct ram_console_buffer {
-	uint32_t    sig;
-	uint32_t    start;
-	uint32_t    size;
-	uint8_t     data[0];
-};
-
-#define RAM_CONSOLE_SIG (0x43474244) /* DBGC */
-
-#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT
-static char __initdata
-	ram_console_old_log_init_buffer[CONFIG_ANDROID_RAM_CONSOLE_EARLY_SIZE];
-#endif
-static char *ram_console_old_log;
-static size_t ram_console_old_log_size;
-
-static struct ram_console_buffer *ram_console_buffer;
-static size_t ram_console_buffer_size;
-#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
-static char *ram_console_par_buffer;
-static struct rs_control *ram_console_rs_decoder;
-static int ram_console_corrected_bytes;
-static int ram_console_bad_blocks;
-#define ECC_BLOCK_SIZE CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE
-#define ECC_SIZE CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE
-#define ECC_SYMSIZE CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE
-#define ECC_POLY CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL
-#endif
-
-#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
-static void ram_console_encode_rs8(uint8_t *data, size_t len, uint8_t *ecc)
-{
-	int i;
-	uint16_t par[ECC_SIZE];
-	/* Initialize the parity buffer */
-	memset(par, 0, sizeof(par));
-	encode_rs8(ram_console_rs_decoder, data, len, par, 0);
-	for (i = 0; i < ECC_SIZE; i++)
-		ecc[i] = par[i];
-}
-
-static int ram_console_decode_rs8(void *data, size_t len, uint8_t *ecc)
-{
-	int i;
-	uint16_t par[ECC_SIZE];
-	for (i = 0; i < ECC_SIZE; i++)
-		par[i] = ecc[i];
-	return decode_rs8(ram_console_rs_decoder, data, par, len,
-				NULL, 0, NULL, 0, NULL);
-}
-#endif
-
-static void ram_console_update(const char *s, unsigned int count)
-{
-	struct ram_console_buffer *buffer = ram_console_buffer;
-#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
-	uint8_t *buffer_end = buffer->data + ram_console_buffer_size;
-	uint8_t *block;
-	uint8_t *par;
-	int size = ECC_BLOCK_SIZE;
-#endif
-	memcpy(buffer->data + buffer->start, s, count);
-#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
-	block = buffer->data + (buffer->start & ~(ECC_BLOCK_SIZE - 1));
-	par = ram_console_par_buffer +
-	      (buffer->start / ECC_BLOCK_SIZE) * ECC_SIZE;
-	do {
-		if (block + ECC_BLOCK_SIZE > buffer_end)
-			size = buffer_end - block;
-		ram_console_encode_rs8(block, size, par);
-		block += ECC_BLOCK_SIZE;
-		par += ECC_SIZE;
-	} while (block < buffer->data + buffer->start + count);
-#endif
-}
-
-static void ram_console_update_header(void)
-{
-#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
-	struct ram_console_buffer *buffer = ram_console_buffer;
-	uint8_t *par;
-	par = ram_console_par_buffer +
-	      DIV_ROUND_UP(ram_console_buffer_size, ECC_BLOCK_SIZE) * ECC_SIZE;
-	ram_console_encode_rs8((uint8_t *)buffer, sizeof(*buffer), par);
-#endif
-}
+static struct persistent_ram_zone *ram_console_zone;
+static const char *bootinfo;
+static size_t bootinfo_size;
 
 static void
 ram_console_write(struct console *console, const char *s, unsigned int count)
 {
-	int rem;
-	struct ram_console_buffer *buffer = ram_console_buffer;
-
-	if (count > ram_console_buffer_size) {
-		s += count - ram_console_buffer_size;
-		count = ram_console_buffer_size;
-	}
-	rem = ram_console_buffer_size - buffer->start;
-	if (rem < count) {
-		ram_console_update(s, rem);
-		s += rem;
-		count -= rem;
-		buffer->start = 0;
-		buffer->size = ram_console_buffer_size;
-	}
-	ram_console_update(s, count);
-
-	buffer->start += count;
-	if (buffer->size < ram_console_buffer_size)
-		buffer->size += count;
-	ram_console_update_header();
+	struct persistent_ram_zone *prz = console->data;
+	persistent_ram_write(prz, s, count);
 }
 
 static struct console ram_console = {
 	.name	= "ram",
 	.write	= ram_console_write,
-	.flags	= CON_PRINTBUFFER | CON_ENABLED,
+	.flags	= CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME,
 	.index	= -1,
 };
 
@@ -155,220 +50,31 @@
 		ram_console.flags &= ~CON_ENABLED;
 }
 
-static void __init
-ram_console_save_old(struct ram_console_buffer *buffer, const char *bootinfo,
-	char *dest)
+static int __init ram_console_probe(struct platform_device *pdev)
 {
-	size_t old_log_size = buffer->size;
-	size_t bootinfo_size = 0;
-	size_t total_size = old_log_size;
-	char *ptr;
-	const char *bootinfo_label = "Boot info:\n";
+	struct ram_console_platform_data *pdata = pdev->dev.platform_data;
+	struct persistent_ram_zone *prz;
 
-#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
-	uint8_t *block;
-	uint8_t *par;
-	char strbuf[80];
-	int strbuf_len = 0;
+	prz = persistent_ram_init_ringbuffer(&pdev->dev, true);
+	if (IS_ERR(prz))
+		return PTR_ERR(prz);
 
-	block = buffer->data;
-	par = ram_console_par_buffer;
-	while (block < buffer->data + buffer->size) {
-		int numerr;
-		int size = ECC_BLOCK_SIZE;
-		if (block + size > buffer->data + ram_console_buffer_size)
-			size = buffer->data + ram_console_buffer_size - block;
-		numerr = ram_console_decode_rs8(block, size, par);
-		if (numerr > 0) {
-#if 0
-			printk(KERN_INFO "ram_console: error in block %p, %d\n",
-			       block, numerr);
-#endif
-			ram_console_corrected_bytes += numerr;
-		} else if (numerr < 0) {
-#if 0
-			printk(KERN_INFO "ram_console: uncorrectable error in "
-			       "block %p\n", block);
-#endif
-			ram_console_bad_blocks++;
-		}
-		block += ECC_BLOCK_SIZE;
-		par += ECC_SIZE;
-	}
-	if (ram_console_corrected_bytes || ram_console_bad_blocks)
-		strbuf_len = snprintf(strbuf, sizeof(strbuf),
-			"\n%d Corrected bytes, %d unrecoverable blocks\n",
-			ram_console_corrected_bytes, ram_console_bad_blocks);
-	else
-		strbuf_len = snprintf(strbuf, sizeof(strbuf),
-				      "\nNo errors detected\n");
-	if (strbuf_len >= sizeof(strbuf))
-		strbuf_len = sizeof(strbuf) - 1;
-	total_size += strbuf_len;
-#endif
 
-	if (bootinfo)
-		bootinfo_size = strlen(bootinfo) + strlen(bootinfo_label);
-	total_size += bootinfo_size;
-
-	if (dest == NULL) {
-		dest = kmalloc(total_size, GFP_KERNEL);
-		if (dest == NULL) {
-			printk(KERN_ERR
-			       "ram_console: failed to allocate buffer\n");
-			return;
-		}
+	if (pdata) {
+		bootinfo = kstrdup(pdata->bootinfo, GFP_KERNEL);
+		if (bootinfo)
+			bootinfo_size = strlen(bootinfo);
 	}
 
-	ram_console_old_log = dest;
-	ram_console_old_log_size = total_size;
-	memcpy(ram_console_old_log,
-	       &buffer->data[buffer->start], buffer->size - buffer->start);
-	memcpy(ram_console_old_log + buffer->size - buffer->start,
-	       &buffer->data[0], buffer->start);
-	ptr = ram_console_old_log + old_log_size;
-#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
-	memcpy(ptr, strbuf, strbuf_len);
-	ptr += strbuf_len;
-#endif
-	if (bootinfo) {
-		memcpy(ptr, bootinfo_label, strlen(bootinfo_label));
-		ptr += strlen(bootinfo_label);
-		memcpy(ptr, bootinfo, bootinfo_size);
-		ptr += bootinfo_size;
-	}
-}
-
-static int __init ram_console_init(struct ram_console_buffer *buffer,
-				   size_t buffer_size, const char *bootinfo,
-				   char *old_buf)
-{
-#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
-	int numerr;
-	uint8_t *par;
-#endif
-	ram_console_buffer = buffer;
-	ram_console_buffer_size =
-		buffer_size - sizeof(struct ram_console_buffer);
-
-	if (ram_console_buffer_size > buffer_size) {
-		pr_err("ram_console: buffer %p, invalid size %zu, "
-		       "datasize %zu\n", buffer, buffer_size,
-		       ram_console_buffer_size);
-		return 0;
-	}
-
-#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
-	ram_console_buffer_size -= (DIV_ROUND_UP(ram_console_buffer_size,
-						ECC_BLOCK_SIZE) + 1) * ECC_SIZE;
-
-	if (ram_console_buffer_size > buffer_size) {
-		pr_err("ram_console: buffer %p, invalid size %zu, "
-		       "non-ecc datasize %zu\n",
-		       buffer, buffer_size, ram_console_buffer_size);
-		return 0;
-	}
-
-	ram_console_par_buffer = buffer->data + ram_console_buffer_size;
-
-
-	/* first consecutive root is 0
-	 * primitive element to generate roots = 1
-	 */
-	ram_console_rs_decoder = init_rs(ECC_SYMSIZE, ECC_POLY, 0, 1, ECC_SIZE);
-	if (ram_console_rs_decoder == NULL) {
-		printk(KERN_INFO "ram_console: init_rs failed\n");
-		return 0;
-	}
-
-	ram_console_corrected_bytes = 0;
-	ram_console_bad_blocks = 0;
-
-	par = ram_console_par_buffer +
-	      DIV_ROUND_UP(ram_console_buffer_size, ECC_BLOCK_SIZE) * ECC_SIZE;
-
-	numerr = ram_console_decode_rs8(buffer, sizeof(*buffer), par);
-	if (numerr > 0) {
-		printk(KERN_INFO "ram_console: error in header, %d\n", numerr);
-		ram_console_corrected_bytes += numerr;
-	} else if (numerr < 0) {
-		printk(KERN_INFO
-		       "ram_console: uncorrectable error in header\n");
-		ram_console_bad_blocks++;
-	}
-#endif
-
-	if (buffer->sig == RAM_CONSOLE_SIG) {
-		if (buffer->size > ram_console_buffer_size
-		    || buffer->start > buffer->size)
-			printk(KERN_INFO "ram_console: found existing invalid "
-			       "buffer, size %d, start %d\n",
-			       buffer->size, buffer->start);
-		else {
-			printk(KERN_INFO "ram_console: found existing buffer, "
-			       "size %d, start %d\n",
-			       buffer->size, buffer->start);
-			ram_console_save_old(buffer, bootinfo, old_buf);
-		}
-	} else {
-		printk(KERN_INFO "ram_console: no valid data in buffer "
-		       "(sig = 0x%08x)\n", buffer->sig);
-	}
-
-	buffer->sig = RAM_CONSOLE_SIG;
-	buffer->start = 0;
-	buffer->size = 0;
+	ram_console_zone = prz;
+	ram_console.data = prz;
 
 	register_console(&ram_console);
-#ifdef CONFIG_ANDROID_RAM_CONSOLE_ENABLE_VERBOSE
-	console_verbose();
-#endif
+
 	return 0;
 }
 
-#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT
-static int __init ram_console_early_init(void)
-{
-	return ram_console_init((struct ram_console_buffer *)
-		CONFIG_ANDROID_RAM_CONSOLE_EARLY_ADDR,
-		CONFIG_ANDROID_RAM_CONSOLE_EARLY_SIZE,
-		NULL,
-		ram_console_old_log_init_buffer);
-}
-#else
-static int ram_console_driver_probe(struct platform_device *pdev)
-{
-	struct resource *res = pdev->resource;
-	size_t start;
-	size_t buffer_size;
-	void *buffer;
-	const char *bootinfo = NULL;
-	struct ram_console_platform_data *pdata = pdev->dev.platform_data;
-
-	if (res == NULL || pdev->num_resources != 1 ||
-	    !(res->flags & IORESOURCE_MEM)) {
-		printk(KERN_ERR "ram_console: invalid resource, %p %d flags "
-		       "%lx\n", res, pdev->num_resources, res ? res->flags : 0);
-		return -ENXIO;
-	}
-	buffer_size = res->end - res->start + 1;
-	start = res->start;
-	printk(KERN_INFO "ram_console: got buffer at %zx, size %zx\n",
-	       start, buffer_size);
-	buffer = ioremap(res->start, buffer_size);
-	if (buffer == NULL) {
-		printk(KERN_ERR "ram_console: failed to map memory\n");
-		return -ENOMEM;
-	}
-
-	if (pdata)
-		bootinfo = pdata->bootinfo;
-
-	return ram_console_init(buffer, buffer_size, bootinfo, NULL/* allocate */);
-}
-
 static struct platform_driver ram_console_driver = {
-	.probe = ram_console_driver_probe,
 	.driver		= {
 		.name	= "ram_console",
 	},
@@ -376,10 +82,11 @@
 
 static int __init ram_console_module_init(void)
 {
-	int err;
-	err = platform_driver_register(&ram_console_driver);
-	return err;
+	return platform_driver_probe(&ram_console_driver, ram_console_probe);
 }
+
+#ifndef CONFIG_PRINTK
+#define dmesg_restrict	0
 #endif
 
 static ssize_t ram_console_read_old(struct file *file, char __user *buf,
@@ -387,14 +94,52 @@
 {
 	loff_t pos = *offset;
 	ssize_t count;
+	struct persistent_ram_zone *prz = ram_console_zone;
+	size_t old_log_size = persistent_ram_old_size(prz);
+	const char *old_log = persistent_ram_old(prz);
+	char *str;
+	int ret;
 
-	if (pos >= ram_console_old_log_size)
-		return 0;
+	if (dmesg_restrict && !capable(CAP_SYSLOG))
+		return -EPERM;
 
-	count = min(len, (size_t)(ram_console_old_log_size - pos));
-	if (copy_to_user(buf, ram_console_old_log + pos, count))
-		return -EFAULT;
+	/* Main last_kmsg log */
+	if (pos < old_log_size) {
+		count = min(len, (size_t)(old_log_size - pos));
+		if (copy_to_user(buf, old_log + pos, count))
+			return -EFAULT;
+		goto out;
+	}
 
+	/* ECC correction notice */
+	pos -= old_log_size;
+	count = persistent_ram_ecc_string(prz, NULL, 0);
+	if (pos < count) {
+		str = kmalloc(count, GFP_KERNEL);
+		if (!str)
+			return -ENOMEM;
+		persistent_ram_ecc_string(prz, str, count + 1);
+		count = min(len, (size_t)(count - pos));
+		ret = copy_to_user(buf, str + pos, count);
+		kfree(str);
+		if (ret)
+			return -EFAULT;
+		goto out;
+	}
+
+	/* Boot info passed through pdata */
+	pos -= count;
+	if (pos < bootinfo_size) {
+		count = min(len, (size_t)(bootinfo_size - pos));
+		if (copy_to_user(buf, bootinfo + pos, count))
+			return -EFAULT;
+		goto out;
+	}
+
+	/* EOF */
+	return 0;
+
+out:
 	*offset += count;
 	return count;
 }
@@ -407,37 +152,28 @@
 static int __init ram_console_late_init(void)
 {
 	struct proc_dir_entry *entry;
+	struct persistent_ram_zone *prz = ram_console_zone;
 
-	if (ram_console_old_log == NULL)
+	if (!prz)
 		return 0;
-#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT
-	ram_console_old_log = kmalloc(ram_console_old_log_size, GFP_KERNEL);
-	if (ram_console_old_log == NULL) {
-		printk(KERN_ERR
-		       "ram_console: failed to allocate buffer for old log\n");
-		ram_console_old_log_size = 0;
+
+	if (persistent_ram_old_size(prz) == 0)
 		return 0;
-	}
-	memcpy(ram_console_old_log,
-	       ram_console_old_log_init_buffer, ram_console_old_log_size);
-#endif
+
 	entry = create_proc_entry("last_kmsg", S_IFREG | S_IRUGO, NULL);
 	if (!entry) {
 		printk(KERN_ERR "ram_console: failed to create proc entry\n");
-		kfree(ram_console_old_log);
-		ram_console_old_log = NULL;
+		persistent_ram_free_old(prz);
 		return 0;
 	}
 
 	entry->proc_fops = &ram_console_file_ops;
-	entry->size = ram_console_old_log_size;
+	entry->size = persistent_ram_old_size(prz) +
+		persistent_ram_ecc_string(prz, NULL, 0) +
+		bootinfo_size;
+
 	return 0;
 }
 
-#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT
-console_initcall(ram_console_early_init);
-#else
-postcore_initcall(ram_console_module_init);
-#endif
 late_initcall(ram_console_late_init);
-
+postcore_initcall(ram_console_module_init);
diff --git a/drivers/staging/android/timed_gpio.c b/drivers/staging/android/timed_gpio.c
index a64481c..bc723ef 100644
--- a/drivers/staging/android/timed_gpio.c
+++ b/drivers/staging/android/timed_gpio.c
@@ -29,9 +29,9 @@
 	struct timed_output_dev dev;
 	struct hrtimer timer;
 	spinlock_t lock;
-	unsigned 	gpio;
-	int 		max_timeout;
-	u8 		active_low;
+	unsigned gpio;
+	int max_timeout;
+	u8 active_low;
 };
 
 static enum hrtimer_restart gpio_timer_func(struct hrtimer *timer)
diff --git a/drivers/staging/android/timed_gpio.h b/drivers/staging/android/timed_gpio.h
index a0e15f8..d29e169 100644
--- a/drivers/staging/android/timed_gpio.h
+++ b/drivers/staging/android/timed_gpio.h
@@ -20,13 +20,13 @@
 
 struct timed_gpio {
 	const char *name;
-	unsigned 	gpio;
+	unsigned	gpio;
 	int		max_timeout;
-	u8 		active_low;
+	u8		active_low;
 };
 
 struct timed_gpio_platform_data {
-	int 		num_gpios;
+	int		num_gpios;
 	struct timed_gpio *gpios;
 };
 
diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c
index 1df9586..83549d9 100644
--- a/drivers/staging/asus_oled/asus_oled.c
+++ b/drivers/staging/asus_oled/asus_oled.c
@@ -159,7 +159,6 @@
 
 static void enable_oled(struct asus_oled_dev *odev, uint8_t enabl)
 {
-	int a;
 	int retval;
 	int act_len;
 	struct asus_oled_packet *packet;
@@ -178,17 +177,15 @@
 	else
 		packet->bitmap[0] = 0xae;
 
-	for (a = 0; a < 1; a++) {
-		retval = usb_bulk_msg(odev->udev,
-			usb_sndbulkpipe(odev->udev, 2),
-			packet,
-			sizeof(struct asus_oled_header) + 1,
-			&act_len,
-			-1);
+	retval = usb_bulk_msg(odev->udev,
+		usb_sndbulkpipe(odev->udev, 2),
+		packet,
+		sizeof(struct asus_oled_header) + 1,
+		&act_len,
+		-1);
 
-		if (retval)
-			dev_dbg(&odev->udev->dev, "retval = %d\n", retval);
-	}
+	if (retval)
+		dev_dbg(&odev->udev->dev, "retval = %d\n", retval);
 
 	odev->enabled = enabl;
 
diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c
index 179707b..cf30592 100644
--- a/drivers/staging/bcm/Bcmchar.c
+++ b/drivers/staging/bcm/Bcmchar.c
@@ -728,14 +728,10 @@
 		if (IoBuffer.InputLength > MAX_CNTL_PKT_SIZE)
 			return -EINVAL;
 
-		pvBuffer = kmalloc(IoBuffer.InputLength, GFP_KERNEL);
-		if (!pvBuffer)
-			return -ENOMEM;
-
-		if (copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) {
-			kfree(pvBuffer);
-			return -EFAULT;
-		}
+		pvBuffer = memdup_user(IoBuffer.InputBuffer,
+				       IoBuffer.InputLength);
+		if (IS_ERR(pvBuffer))
+			return PTR_ERR(pvBuffer);
 
 		down(&Adapter->LowPowerModeSync);
 		Status = wait_event_interruptible_timeout(Adapter->lowpower_mode_wait_queue,
@@ -1140,15 +1136,10 @@
 		if (IoBuffer.InputLength < sizeof(ULONG) * 2)
 			return -EINVAL;
 
-		pvBuffer = kmalloc(IoBuffer.InputLength, GFP_KERNEL);
-		if (!pvBuffer)
-			return -ENOMEM;
-
-		/* Get WrmBuffer structure */
-		if (copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) {
-			kfree(pvBuffer);
-			return -EFAULT;
-		}
+		pvBuffer = memdup_user(IoBuffer.InputBuffer,
+				       IoBuffer.InputLength);
+		if (IS_ERR(pvBuffer))
+			return PTR_ERR(pvBuffer);
 
 		pBulkBuffer = (PBULKWRM_BUFFER)pvBuffer;
 
@@ -1302,20 +1293,18 @@
 		/*
 		 * Deny the access if the offset crosses the cal area limit.
 		 */
+		if (stNVMReadWrite.uiNumBytes > Adapter->uiNVMDSDSize)
+			return STATUS_FAILURE;
 
-		if ((stNVMReadWrite.uiOffset + stNVMReadWrite.uiNumBytes) > Adapter->uiNVMDSDSize) {
+		if (stNVMReadWrite.uiOffset > Adapter->uiNVMDSDSize - stNVMReadWrite.uiNumBytes) {
 			/* BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Can't allow access beyond NVM Size: 0x%x 0x%x\n", stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes); */
 			return STATUS_FAILURE;
 		}
 
-		pReadData = kzalloc(stNVMReadWrite.uiNumBytes, GFP_KERNEL);
-		if (!pReadData)
-			return -ENOMEM;
-
-		if (copy_from_user(pReadData, stNVMReadWrite.pBuffer, stNVMReadWrite.uiNumBytes)) {
-			kfree(pReadData);
-			return -EFAULT;
-		}
+		pReadData = memdup_user(stNVMReadWrite.pBuffer,
+					stNVMReadWrite.uiNumBytes);
+		if (IS_ERR(pReadData))
+			return PTR_ERR(pReadData);
 
 		do_gettimeofday(&tv0);
 		if (IOCTL_BCM_NVM_READ == cmd) {
diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c
index c0ee95a..7e38af5 100644
--- a/drivers/staging/bcm/CmHost.c
+++ b/drivers/staging/bcm/CmHost.c
@@ -1,431 +1,359 @@
 /************************************************************
-*			CMHOST.C
-*	This file contains the routines for handling Connection
-*	Management.
-************************************************************/
+ * CMHOST.C
+ * This file contains the routines for handling Connection
+ * Management.
+ ************************************************************/
 
-//#define CONN_MSG
+/* #define CONN_MSG */
 #include "headers.h"
 
-typedef enum _E_CLASSIFIER_ACTION
-{
+enum E_CLASSIFIER_ACTION {
 	eInvalidClassifierAction,
 	eAddClassifier,
 	eReplaceClassifier,
 	eDeleteClassifier
-}E_CLASSIFIER_ACTION;
+};
 
-static ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter,B_UINT16 tid);
+static ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter, B_UINT16 tid);
 
 /************************************************************
-* Function	  -	SearchSfid
-*
-* Description -	This routinue would search QOS queues having
-*				specified SFID as input parameter.
-*
-* Parameters  -	Adapter: Pointer to the Adapter structure
-*			   	uiSfid : Given SFID for matching
-*
-* Returns	  - Queue index for this SFID(If matched)
-				Else Invalid Queue Index(If Not matched)
-************************************************************/
-INT SearchSfid(PMINI_ADAPTER Adapter,UINT uiSfid)
+ * Function - SearchSfid
+ *
+ * Description - This routinue would search QOS queues having
+ *  specified SFID as input parameter.
+ *
+ * Parameters -	Adapter: Pointer to the Adapter structure
+ *  uiSfid : Given SFID for matching
+ *
+ * Returns - Queue index for this SFID(If matched)
+ *  Else Invalid Queue Index(If Not matched)
+ ************************************************************/
+int SearchSfid(PMINI_ADAPTER Adapter, UINT uiSfid)
 {
-	INT 	iIndex=0;
-	for(iIndex=(NO_OF_QUEUES-1); iIndex>=0; iIndex--)
-		if(Adapter->PackInfo[iIndex].ulSFID==uiSfid)
-			return iIndex;
+	int i;
+
+	for (i = (NO_OF_QUEUES-1); i >= 0; i--)
+		if (Adapter->PackInfo[i].ulSFID == uiSfid)
+			return i;
+
 	return NO_OF_QUEUES+1;
 }
 
 /***************************************************************
-* Function	  -	SearchFreeSfid
-*
-* Description -	This routinue would search Free available SFID.
-*
-* Parameter   -	Adapter: Pointer to the Adapter structure
-*
-* Returns	  - Queue index for the free SFID
-*				Else returns Invalid Index.
-****************************************************************/
-static INT SearchFreeSfid(PMINI_ADAPTER Adapter)
+ * Function -SearchFreeSfid
+ *
+ * Description - This routinue would search Free available SFID.
+ *
+ * Parameter - Adapter: Pointer to the Adapter structure
+ *
+ * Returns - Queue index for the free SFID
+ *  Else returns Invalid Index.
+ ****************************************************************/
+static int SearchFreeSfid(PMINI_ADAPTER Adapter)
 {
-	UINT 	uiIndex=0;
+	int i;
 
-	for(uiIndex=0; uiIndex < (NO_OF_QUEUES-1); uiIndex++)
-		if(Adapter->PackInfo[uiIndex].ulSFID==0)
-			return uiIndex;
+	for (i = 0; i < (NO_OF_QUEUES-1); i++)
+		if (Adapter->PackInfo[i].ulSFID == 0)
+			return i;
+
 	return NO_OF_QUEUES+1;
 }
 
 /*
-Function:				SearchClsid
-Description:			This routinue would search Classifier  having specified ClassifierID as input parameter
-Input parameters:		PMINI_ADAPTER Adapter - Adapter Context
-                        unsigned int uiSfid   - The SF in which the classifier is to searched
-						B_UINT16  uiClassifierID - The classifier ID to be searched
-Return:					int :Classifier table index of matching entry
-*/
-
-static int SearchClsid(PMINI_ADAPTER Adapter,ULONG ulSFID,B_UINT16  uiClassifierID)
+ * Function: SearchClsid
+ * Description:	This routinue would search Classifier  having specified ClassifierID as input parameter
+ * Input parameters: PMINI_ADAPTER Adapter - Adapter Context
+ *  unsigned int uiSfid   - The SF in which the classifier is to searched
+ *  B_UINT16  uiClassifierID - The classifier ID to be searched
+ * Return: int :Classifier table index of matching entry
+ */
+static int SearchClsid(PMINI_ADAPTER Adapter, ULONG ulSFID, B_UINT16  uiClassifierID)
 {
-	unsigned int uiClassifierIndex = 0;
-	for(uiClassifierIndex=0;uiClassifierIndex<MAX_CLASSIFIERS;uiClassifierIndex++)
-	{
-		if((Adapter->astClassifierTable[uiClassifierIndex].bUsed) &&
-			(Adapter->astClassifierTable[uiClassifierIndex].uiClassifierRuleIndex == uiClassifierID)&&
-			(Adapter->astClassifierTable[uiClassifierIndex].ulSFID == ulSFID))
-			return uiClassifierIndex;
+	int i;
+
+	for (i = 0; i < MAX_CLASSIFIERS; i++) {
+		if ((Adapter->astClassifierTable[i].bUsed) &&
+			(Adapter->astClassifierTable[i].uiClassifierRuleIndex == uiClassifierID) &&
+			(Adapter->astClassifierTable[i].ulSFID == ulSFID))
+			return i;
 	}
+
 	return MAX_CLASSIFIERS+1;
 }
 
-/**
-@ingroup ctrl_pkt_functions
-This routinue would search Free available Classifier entry in classifier table.
-@return free Classifier Entry index in classifier table for specified SF
-*/
-static int SearchFreeClsid(PMINI_ADAPTER Adapter /**Adapter Context*/
-						)
+/*
+ * @ingroup ctrl_pkt_functions
+ * This routinue would search Free available Classifier entry in classifier table.
+ * @return free Classifier Entry index in classifier table for specified SF
+ */
+static int SearchFreeClsid(PMINI_ADAPTER Adapter /**Adapter Context*/)
 {
-	unsigned int uiClassifierIndex = 0;
-	for(uiClassifierIndex=0;uiClassifierIndex<MAX_CLASSIFIERS;uiClassifierIndex++)
-	{
-		if(!Adapter->astClassifierTable[uiClassifierIndex].bUsed)
-			return uiClassifierIndex;
+	int i;
+
+	for (i = 0; i < MAX_CLASSIFIERS; i++) {
+		if (!Adapter->astClassifierTable[i].bUsed)
+			return i;
 	}
+
 	return MAX_CLASSIFIERS+1;
 }
 
 static VOID deleteSFBySfid(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex)
 {
-	//deleting all the packet held in the SF
-	flush_queue(Adapter,uiSearchRuleIndex);
+	/* deleting all the packet held in the SF */
+	flush_queue(Adapter, uiSearchRuleIndex);
 
-	//Deleting the all classifiers for this SF
-	DeleteAllClassifiersForSF(Adapter,uiSearchRuleIndex);
+	/* Deleting the all classifiers for this SF */
+	DeleteAllClassifiersForSF(Adapter, uiSearchRuleIndex);
 
-	//Resetting only MIBS related entries in the SF
+	/* Resetting only MIBS related entries in the SF */
 	memset((PVOID)&Adapter->PackInfo[uiSearchRuleIndex], 0, sizeof(S_MIBS_SERVICEFLOW_TABLE));
 }
 
 static inline VOID
-CopyIpAddrToClassifier(S_CLASSIFIER_RULE *pstClassifierEntry ,
-			B_UINT8 u8IpAddressLen , B_UINT8 *pu8IpAddressMaskSrc ,
-			BOOLEAN bIpVersion6 , E_IPADDR_CONTEXT eIpAddrContext)
+CopyIpAddrToClassifier(S_CLASSIFIER_RULE *pstClassifierEntry,
+		B_UINT8 u8IpAddressLen, B_UINT8 *pu8IpAddressMaskSrc,
+		BOOLEAN bIpVersion6, E_IPADDR_CONTEXT eIpAddrContext)
 {
-	UINT	ucLoopIndex=0;
-	UINT    nSizeOfIPAddressInBytes = IP_LENGTH_OF_ADDRESS;
-	UCHAR   *ptrClassifierIpAddress = NULL;
-	UCHAR   *ptrClassifierIpMask = NULL;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	int i = 0;
+	UINT nSizeOfIPAddressInBytes = IP_LENGTH_OF_ADDRESS;
+	UCHAR *ptrClassifierIpAddress = NULL;
+	UCHAR *ptrClassifierIpMask = NULL;
+	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
-	if(bIpVersion6)
-	{
+	if (bIpVersion6)
 		nSizeOfIPAddressInBytes = IPV6_ADDRESS_SIZEINBYTES;
-	}
-	//Destination Ip Address
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Ip Address Range Length:0x%X ",
-				u8IpAddressLen);
-	if((bIpVersion6?(IPV6_ADDRESS_SIZEINBYTES * MAX_IP_RANGE_LENGTH * 2):
-			(TOTAL_MASKED_ADDRESS_IN_BYTES)) >= u8IpAddressLen)
-	{
+
+	/* Destination Ip Address */
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Ip Address Range Length:0x%X ", u8IpAddressLen);
+	if ((bIpVersion6 ? (IPV6_ADDRESS_SIZEINBYTES * MAX_IP_RANGE_LENGTH * 2) :
+			(TOTAL_MASKED_ADDRESS_IN_BYTES)) >= u8IpAddressLen) {
 		/*
-		//checking both the mask and address togethor in Classification.
-		//So length will be : TotalLengthInBytes/nSizeOfIPAddressInBytes * 2
-		//(nSizeOfIPAddressInBytes for address and nSizeOfIPAddressInBytes for mask)
-		*/
-		if(eIpAddrContext == eDestIpAddress)
-		{
-			pstClassifierEntry->ucIPDestinationAddressLength =
-					u8IpAddressLen/(nSizeOfIPAddressInBytes * 2);
-			if(bIpVersion6)
-			{
-				ptrClassifierIpAddress =
-					pstClassifierEntry->stDestIpAddress.ucIpv6Address;
-				ptrClassifierIpMask =
-					pstClassifierEntry->stDestIpAddress.ucIpv6Mask;
+		 * checking both the mask and address togethor in Classification.
+		 * So length will be : TotalLengthInBytes/nSizeOfIPAddressInBytes * 2
+		 * (nSizeOfIPAddressInBytes for address and nSizeOfIPAddressInBytes for mask)
+		 */
+		if (eIpAddrContext == eDestIpAddress) {
+			pstClassifierEntry->ucIPDestinationAddressLength = u8IpAddressLen/(nSizeOfIPAddressInBytes * 2);
+			if (bIpVersion6) {
+				ptrClassifierIpAddress = pstClassifierEntry->stDestIpAddress.ucIpv6Address;
+				ptrClassifierIpMask = pstClassifierEntry->stDestIpAddress.ucIpv6Mask;
+			} else {
+				ptrClassifierIpAddress = pstClassifierEntry->stDestIpAddress.ucIpv4Address;
+				ptrClassifierIpMask = pstClassifierEntry->stDestIpAddress.ucIpv4Mask;
 			}
-			else
-			{
-				ptrClassifierIpAddress =
-					pstClassifierEntry->stDestIpAddress.ucIpv4Address;
-				ptrClassifierIpMask =
-					pstClassifierEntry->stDestIpAddress.ucIpv4Mask;
+		} else if (eIpAddrContext == eSrcIpAddress) {
+			pstClassifierEntry->ucIPSourceAddressLength = u8IpAddressLen/(nSizeOfIPAddressInBytes * 2);
+			if (bIpVersion6) {
+				ptrClassifierIpAddress = pstClassifierEntry->stSrcIpAddress.ucIpv6Address;
+				ptrClassifierIpMask = pstClassifierEntry->stSrcIpAddress.ucIpv6Mask;
+			} else {
+				ptrClassifierIpAddress = pstClassifierEntry->stSrcIpAddress.ucIpv4Address;
+				ptrClassifierIpMask = pstClassifierEntry->stSrcIpAddress.ucIpv4Mask;
 			}
 		}
-		else if(eIpAddrContext == eSrcIpAddress)
-		{
-			pstClassifierEntry->ucIPSourceAddressLength =
-					u8IpAddressLen/(nSizeOfIPAddressInBytes * 2);
-			if(bIpVersion6)
-			{
-				ptrClassifierIpAddress =
-					pstClassifierEntry->stSrcIpAddress.ucIpv6Address;
-				ptrClassifierIpMask =
-					pstClassifierEntry->stSrcIpAddress.ucIpv6Mask;
-			}
-			else
-			{
-				ptrClassifierIpAddress =
-					pstClassifierEntry->stSrcIpAddress.ucIpv4Address;
-				ptrClassifierIpMask =
-					pstClassifierEntry->stSrcIpAddress.ucIpv4Mask;
-			}
-		}
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Address Length:0x%X \n",
-				pstClassifierEntry->ucIPDestinationAddressLength);
-		while((u8IpAddressLen>= nSizeOfIPAddressInBytes) &&
-				(ucLoopIndex < MAX_IP_RANGE_LENGTH))
-		{
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Address Length:0x%X\n", pstClassifierEntry->ucIPDestinationAddressLength);
+		while ((u8IpAddressLen >= nSizeOfIPAddressInBytes) && (i < MAX_IP_RANGE_LENGTH)) {
 			memcpy(ptrClassifierIpAddress +
-				(ucLoopIndex * nSizeOfIPAddressInBytes),
-				(pu8IpAddressMaskSrc+(ucLoopIndex*nSizeOfIPAddressInBytes*2)),
+				(i * nSizeOfIPAddressInBytes),
+				(pu8IpAddressMaskSrc+(i*nSizeOfIPAddressInBytes*2)),
 				nSizeOfIPAddressInBytes);
-			if(!bIpVersion6)
-			{
-				if(eIpAddrContext == eSrcIpAddress)
-				{
-					pstClassifierEntry->stSrcIpAddress.ulIpv4Addr[ucLoopIndex]=
-						ntohl(pstClassifierEntry->stSrcIpAddress.
-								ulIpv4Addr[ucLoopIndex]);
-					BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Src Ip Address:0x%luX ",pstClassifierEntry->stSrcIpAddress.ulIpv4Addr[ucLoopIndex]);
-				}
-				else if(eIpAddrContext == eDestIpAddress)
-				{
-					pstClassifierEntry->stDestIpAddress.ulIpv4Addr[ucLoopIndex]=						ntohl(pstClassifierEntry->stDestIpAddress.
-								ulIpv4Addr[ucLoopIndex]);
-					BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Dest Ip Address:0x%luX ",pstClassifierEntry->stDestIpAddress.ulIpv4Addr[ucLoopIndex]);
+
+			if (!bIpVersion6) {
+				if (eIpAddrContext == eSrcIpAddress) {
+					pstClassifierEntry->stSrcIpAddress.ulIpv4Addr[i] = ntohl(pstClassifierEntry->stSrcIpAddress.ulIpv4Addr[i]);
+					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Src Ip Address:0x%luX ",
+							pstClassifierEntry->stSrcIpAddress.ulIpv4Addr[i]);
+				} else if (eIpAddrContext == eDestIpAddress) {
+					pstClassifierEntry->stDestIpAddress.ulIpv4Addr[i] = ntohl(pstClassifierEntry->stDestIpAddress.ulIpv4Addr[i]);
+					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Dest Ip Address:0x%luX ",
+							pstClassifierEntry->stDestIpAddress.ulIpv4Addr[i]);
 				}
 			}
-			u8IpAddressLen-=nSizeOfIPAddressInBytes;
-			if(u8IpAddressLen >= nSizeOfIPAddressInBytes)
-			{
+			u8IpAddressLen -= nSizeOfIPAddressInBytes;
+			if (u8IpAddressLen >= nSizeOfIPAddressInBytes) {
 				memcpy(ptrClassifierIpMask +
-					(ucLoopIndex * nSizeOfIPAddressInBytes),
+					(i * nSizeOfIPAddressInBytes),
 					(pu8IpAddressMaskSrc+nSizeOfIPAddressInBytes +
-					(ucLoopIndex*nSizeOfIPAddressInBytes*2)),
+						(i*nSizeOfIPAddressInBytes*2)),
 					nSizeOfIPAddressInBytes);
-				if(!bIpVersion6)
-				{
-					if(eIpAddrContext == eSrcIpAddress)
-					{
-						pstClassifierEntry->stSrcIpAddress.
-											ulIpv4Mask[ucLoopIndex]=
-								ntohl(pstClassifierEntry->stSrcIpAddress.
-											ulIpv4Mask[ucLoopIndex]);
-						BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Src Ip Mask Address:0x%luX ",pstClassifierEntry->stSrcIpAddress.ulIpv4Mask[ucLoopIndex]);
-					}
-					else if(eIpAddrContext == eDestIpAddress)
-					{
-						pstClassifierEntry->stDestIpAddress.
-										ulIpv4Mask[ucLoopIndex] =
-									ntohl(pstClassifierEntry->stDestIpAddress.
-											ulIpv4Mask[ucLoopIndex]);
-						BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Dest Ip Mask Address:0x%luX ",pstClassifierEntry->stDestIpAddress.ulIpv4Mask[ucLoopIndex]);
+
+				if (!bIpVersion6) {
+					if (eIpAddrContext == eSrcIpAddress) {
+						pstClassifierEntry->stSrcIpAddress.ulIpv4Mask[i] =
+							ntohl(pstClassifierEntry->stSrcIpAddress.ulIpv4Mask[i]);
+						BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Src Ip Mask Address:0x%luX ",
+								pstClassifierEntry->stSrcIpAddress.ulIpv4Mask[i]);
+					} else if (eIpAddrContext == eDestIpAddress) {
+						pstClassifierEntry->stDestIpAddress.ulIpv4Mask[i] =
+							ntohl(pstClassifierEntry->stDestIpAddress.ulIpv4Mask[i]);
+						BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Dest Ip Mask Address:0x%luX ",
+								pstClassifierEntry->stDestIpAddress.ulIpv4Mask[i]);
 					}
 				}
-				u8IpAddressLen-=nSizeOfIPAddressInBytes;
+				u8IpAddressLen -= nSizeOfIPAddressInBytes;
 			}
-			if(0==u8IpAddressLen)
-			{
-				pstClassifierEntry->bDestIpValid=TRUE;
-			}
-			ucLoopIndex++;
+			if (u8IpAddressLen == 0)
+				pstClassifierEntry->bDestIpValid = TRUE;
+
+			i++;
 		}
-		if(bIpVersion6)
-		{
-			//Restore EndianNess of Struct
-			for(ucLoopIndex =0 ; ucLoopIndex < MAX_IP_RANGE_LENGTH * 4 ;
-					ucLoopIndex++)
-			{
-				if(eIpAddrContext == eSrcIpAddress)
-				{
-					pstClassifierEntry->stSrcIpAddress.ulIpv6Addr[ucLoopIndex]=
-							ntohl(pstClassifierEntry->stSrcIpAddress.
-							ulIpv6Addr[ucLoopIndex]);
-					pstClassifierEntry->stSrcIpAddress.ulIpv6Mask[ucLoopIndex]= 							ntohl(pstClassifierEntry->stSrcIpAddress.
-							ulIpv6Mask[ucLoopIndex]);
-				}
-				else if(eIpAddrContext == eDestIpAddress)
-				{
-					pstClassifierEntry->stDestIpAddress.ulIpv6Addr[ucLoopIndex]= 							ntohl(pstClassifierEntry->stDestIpAddress.
-							ulIpv6Addr[ucLoopIndex]);
-					pstClassifierEntry->stDestIpAddress.ulIpv6Mask[ucLoopIndex]= 							ntohl(pstClassifierEntry->stDestIpAddress.
-							ulIpv6Mask[ucLoopIndex]);
+		if (bIpVersion6) {
+			/* Restore EndianNess of Struct */
+			for (i = 0; i < MAX_IP_RANGE_LENGTH * 4; i++) {
+				if (eIpAddrContext == eSrcIpAddress) {
+					pstClassifierEntry->stSrcIpAddress.ulIpv6Addr[i] = ntohl(pstClassifierEntry->stSrcIpAddress.ulIpv6Addr[i]);
+					pstClassifierEntry->stSrcIpAddress.ulIpv6Mask[i] = ntohl(pstClassifierEntry->stSrcIpAddress.ulIpv6Mask[i]);
+				} else if (eIpAddrContext == eDestIpAddress) {
+					pstClassifierEntry->stDestIpAddress.ulIpv6Addr[i] = ntohl(pstClassifierEntry->stDestIpAddress.ulIpv6Addr[i]);
+					pstClassifierEntry->stDestIpAddress.ulIpv6Mask[i] = ntohl(pstClassifierEntry->stDestIpAddress.ulIpv6Mask[i]);
 				}
 			}
 		}
 	}
 }
 
-
-void ClearTargetDSXBuffer(PMINI_ADAPTER Adapter,B_UINT16 TID,BOOLEAN bFreeAll)
+void ClearTargetDSXBuffer(PMINI_ADAPTER Adapter, B_UINT16 TID, BOOLEAN bFreeAll)
 {
-    ULONG ulIndex;
-	for(ulIndex=0; ulIndex < Adapter->ulTotalTargetBuffersAvailable; ulIndex++)
-	{
-		if(Adapter->astTargetDsxBuffer[ulIndex].valid)
+	int i;
+
+	for (i = 0; i < Adapter->ulTotalTargetBuffersAvailable; i++) {
+		if (Adapter->astTargetDsxBuffer[i].valid)
 			continue;
-        if ((bFreeAll) || (Adapter->astTargetDsxBuffer[ulIndex].tid == TID)){
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "ClearTargetDSXBuffer: found tid %d buffer cleared %lx\n",
-				TID, Adapter->astTargetDsxBuffer[ulIndex].ulTargetDsxBuffer);
-			Adapter->astTargetDsxBuffer[ulIndex].valid=1;
-			Adapter->astTargetDsxBuffer[ulIndex].tid=0;
+
+		if ((bFreeAll) || (Adapter->astTargetDsxBuffer[i].tid == TID)) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "ClearTargetDSXBuffer: found tid %d buffer cleared %lx\n",
+					TID, Adapter->astTargetDsxBuffer[i].ulTargetDsxBuffer);
+			Adapter->astTargetDsxBuffer[i].valid = 1;
+			Adapter->astTargetDsxBuffer[i].tid = 0;
 			Adapter->ulFreeTargetBufferCnt++;
-      	}
+		}
 	}
 }
 
-/**
-@ingroup ctrl_pkt_functions
-copy classifier rule into the specified SF index
-*/
-static inline VOID CopyClassifierRuleToSF(PMINI_ADAPTER Adapter,stConvergenceSLTypes  *psfCSType,UINT uiSearchRuleIndex,UINT nClassifierIndex)
+/*
+ * @ingroup ctrl_pkt_functions
+ * copy classifier rule into the specified SF index
+ */
+static inline VOID CopyClassifierRuleToSF(PMINI_ADAPTER Adapter, stConvergenceSLTypes  *psfCSType, UINT uiSearchRuleIndex, UINT nClassifierIndex)
 {
 	S_CLASSIFIER_RULE *pstClassifierEntry = NULL;
-	//VOID *pvPhsContext = NULL;
-	UINT	ucLoopIndex=0;
-	//UCHAR   ucProtocolLength=0;
-	//ULONG   ulPhsStatus;
+	/* VOID *pvPhsContext = NULL; */
+	int i;
+	/* UCHAR ucProtocolLength=0; */
+	/* ULONG ulPhsStatus; */
 
-
-	if(Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value == 0 ||
+	if (Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value == 0 ||
 		nClassifierIndex > (MAX_CLASSIFIERS-1))
 		return;
 
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Storing Classifier Rule Index : %X",
+			ntohs(psfCSType->cCPacketClassificationRule.u16PacketClassificationRuleIndex));
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Storing Classifier Rule Index : %X",ntohs(psfCSType->cCPacketClassificationRule.u16PacketClassificationRuleIndex));
-
-	if(nClassifierIndex > MAX_CLASSIFIERS-1)
+	if (nClassifierIndex > MAX_CLASSIFIERS-1)
 		return;
 
 	pstClassifierEntry = &Adapter->astClassifierTable[nClassifierIndex];
-	if(pstClassifierEntry)
-	{
-		//Store if Ipv6
-		pstClassifierEntry->bIpv6Protocol =
-		(Adapter->PackInfo[uiSearchRuleIndex].ucIpVersion == IPV6)?TRUE:FALSE;
+	if (pstClassifierEntry) {
+		/* Store if Ipv6 */
+		pstClassifierEntry->bIpv6Protocol = (Adapter->PackInfo[uiSearchRuleIndex].ucIpVersion == IPV6) ? TRUE : FALSE;
 
-		//Destinaiton Port
-		pstClassifierEntry->ucDestPortRangeLength=psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength/4;
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Destination Port Range Length:0x%X ",pstClassifierEntry->ucDestPortRangeLength);
-		if(	MAX_PORT_RANGE >= psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength)
-		{
-			for(ucLoopIndex=0;ucLoopIndex<(pstClassifierEntry->ucDestPortRangeLength);ucLoopIndex++)
-			{
-				pstClassifierEntry->usDestPortRangeLo[ucLoopIndex] =
-					*((PUSHORT)(psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange+ucLoopIndex));
-				pstClassifierEntry->usDestPortRangeHi[ucLoopIndex] =
-					*((PUSHORT)(psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange+2+ucLoopIndex));
-				pstClassifierEntry->usDestPortRangeLo[ucLoopIndex]=ntohs(pstClassifierEntry->usDestPortRangeLo[ucLoopIndex]);
-				BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Destination Port Range Lo:0x%X ",pstClassifierEntry->usDestPortRangeLo[ucLoopIndex]);
-				pstClassifierEntry->usDestPortRangeHi[ucLoopIndex]=ntohs(pstClassifierEntry->usDestPortRangeHi[ucLoopIndex]);
+		/* Destinaiton Port */
+		pstClassifierEntry->ucDestPortRangeLength = psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength / 4;
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Destination Port Range Length:0x%X ", pstClassifierEntry->ucDestPortRangeLength);
+
+		if (psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength <= MAX_PORT_RANGE) {
+			for (i = 0; i < (pstClassifierEntry->ucDestPortRangeLength); i++) {
+				pstClassifierEntry->usDestPortRangeLo[i] = *((PUSHORT)(psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange+i));
+				pstClassifierEntry->usDestPortRangeHi[i] =
+					*((PUSHORT)(psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange+2+i));
+				pstClassifierEntry->usDestPortRangeLo[i] = ntohs(pstClassifierEntry->usDestPortRangeLo[i]);
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Destination Port Range Lo:0x%X ",
+						pstClassifierEntry->usDestPortRangeLo[i]);
+				pstClassifierEntry->usDestPortRangeHi[i] = ntohs(pstClassifierEntry->usDestPortRangeHi[i]);
+			}
+		} else {
+			pstClassifierEntry->ucDestPortRangeLength = 0;
+		}
+
+		/* Source Port */
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Source Port Range Length:0x%X ",
+				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength);
+		if (psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength <= MAX_PORT_RANGE) {
+			pstClassifierEntry->ucSrcPortRangeLength = psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength/4;
+			for (i = 0; i < (pstClassifierEntry->ucSrcPortRangeLength); i++) {
+				pstClassifierEntry->usSrcPortRangeLo[i] =
+					*((PUSHORT)(psfCSType->cCPacketClassificationRule.
+							u8ProtocolSourcePortRange+i));
+				pstClassifierEntry->usSrcPortRangeHi[i] =
+					*((PUSHORT)(psfCSType->cCPacketClassificationRule.
+							u8ProtocolSourcePortRange+2+i));
+				pstClassifierEntry->usSrcPortRangeLo[i] =
+					ntohs(pstClassifierEntry->usSrcPortRangeLo[i]);
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Source Port Range Lo:0x%X ",
+						pstClassifierEntry->usSrcPortRangeLo[i]);
+				pstClassifierEntry->usSrcPortRangeHi[i] = ntohs(pstClassifierEntry->usSrcPortRangeHi[i]);
 			}
 		}
-		else
-		{
-			pstClassifierEntry->ucDestPortRangeLength=0;
-		}
-		//Source Port
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Source Port Range Length:0x%X ",psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength);
-		if(MAX_PORT_RANGE >=
-		psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength)
-		{
-			pstClassifierEntry->ucSrcPortRangeLength =
-				psfCSType->cCPacketClassificationRule.
-						u8ProtocolSourcePortRangeLength/4;
-			for(ucLoopIndex = 0; ucLoopIndex <
-				(pstClassifierEntry->ucSrcPortRangeLength); ucLoopIndex++)
-			{
-				pstClassifierEntry->usSrcPortRangeLo[ucLoopIndex] =
-						*((PUSHORT)(psfCSType->cCPacketClassificationRule.
-							u8ProtocolSourcePortRange+ucLoopIndex));
-				pstClassifierEntry->usSrcPortRangeHi[ucLoopIndex] =
-						*((PUSHORT)(psfCSType->cCPacketClassificationRule.
-							u8ProtocolSourcePortRange+2+ucLoopIndex));
-				pstClassifierEntry->usSrcPortRangeLo[ucLoopIndex] =
-					ntohs(pstClassifierEntry->usSrcPortRangeLo[ucLoopIndex]);
-				BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Source Port Range Lo:0x%X ",pstClassifierEntry->usSrcPortRangeLo[ucLoopIndex]);
-				pstClassifierEntry->usSrcPortRangeHi[ucLoopIndex]=ntohs(pstClassifierEntry->usSrcPortRangeHi[ucLoopIndex]);
-			}
-		}
-		//Destination Ip Address and Mask
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Ip Destination Parameters : ");
+		/* Destination Ip Address and Mask */
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Ip Destination Parameters : ");
+		CopyIpAddrToClassifier(pstClassifierEntry,
+				psfCSType->cCPacketClassificationRule.u8IPDestinationAddressLength,
+				psfCSType->cCPacketClassificationRule.u8IPDestinationAddress,
+				(Adapter->PackInfo[uiSearchRuleIndex].ucIpVersion == IPV6) ?
+			TRUE : FALSE, eDestIpAddress);
+
+		/* Source Ip Address and Mask */
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Ip Source Parameters : ");
 
 		CopyIpAddrToClassifier(pstClassifierEntry,
-		   psfCSType->cCPacketClassificationRule.u8IPDestinationAddressLength,
-		   psfCSType->cCPacketClassificationRule.u8IPDestinationAddress,
-		   (Adapter->PackInfo[uiSearchRuleIndex].ucIpVersion == IPV6)?
-			TRUE:FALSE, eDestIpAddress);
+				psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddressLength,
+				psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddress,
+				(Adapter->PackInfo[uiSearchRuleIndex].ucIpVersion == IPV6) ? TRUE : FALSE,
+				eSrcIpAddress);
 
-		//Source Ip Address and Mask
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Ip Source Parameters : ");
-
-		CopyIpAddrToClassifier(pstClassifierEntry,
-	   	psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddressLength,
-		psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddress,
-		(Adapter->PackInfo[uiSearchRuleIndex].ucIpVersion == IPV6)?TRUE:FALSE,
-		eSrcIpAddress);
-
-		//TOS
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"TOS Length:0x%X ",psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength);
-		if(3 == psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength)
-		{
-			pstClassifierEntry->ucIPTypeOfServiceLength =
-				psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength;
-			pstClassifierEntry->ucTosLow =
-				psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0];
-			pstClassifierEntry->ucTosHigh =
-				psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1];
-			pstClassifierEntry->ucTosMask =
-				psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2];
+		/* TOS */
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "TOS Length:0x%X ", psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength);
+		if (psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength == 3) {
+			pstClassifierEntry->ucIPTypeOfServiceLength = psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength;
+			pstClassifierEntry->ucTosLow = psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0];
+			pstClassifierEntry->ucTosHigh = psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1];
+			pstClassifierEntry->ucTosMask = psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2];
 			pstClassifierEntry->bTOSValid = TRUE;
 		}
-		if(psfCSType->cCPacketClassificationRule.u8Protocol == 0)
-		{
-			//we didn't get protocol field filled in by the BS
-			pstClassifierEntry->ucProtocolLength=0;
-		}
-		else
-		{
-			pstClassifierEntry->ucProtocolLength=1;// 1 valid protocol
+		if (psfCSType->cCPacketClassificationRule.u8Protocol == 0) {
+			/* we didn't get protocol field filled in by the BS */
+			pstClassifierEntry->ucProtocolLength = 0;
+		} else {
+			pstClassifierEntry->ucProtocolLength = 1; /* 1 valid protocol */
 		}
 
-		pstClassifierEntry->ucProtocol[0] =
-			psfCSType->cCPacketClassificationRule.u8Protocol;
+		pstClassifierEntry->ucProtocol[0] = psfCSType->cCPacketClassificationRule.u8Protocol;
+		pstClassifierEntry->u8ClassifierRulePriority = psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority;
 
-		pstClassifierEntry->u8ClassifierRulePriority =
-			psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority;
+		/* store the classifier rule ID and set this classifier entry as valid */
+		pstClassifierEntry->ucDirection = Adapter->PackInfo[uiSearchRuleIndex].ucDirection;
+		pstClassifierEntry->uiClassifierRuleIndex = ntohs(psfCSType->cCPacketClassificationRule.u16PacketClassificationRuleIndex);
+		pstClassifierEntry->usVCID_Value = Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value;
+		pstClassifierEntry->ulSFID = Adapter->PackInfo[uiSearchRuleIndex].ulSFID;
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Search Index %d Dir: %d, Index: %d, Vcid: %d\n",
+				uiSearchRuleIndex, pstClassifierEntry->ucDirection,
+				pstClassifierEntry->uiClassifierRuleIndex,
+				pstClassifierEntry->usVCID_Value);
 
-		//store the classifier rule ID and set this classifier entry as valid
-		pstClassifierEntry->ucDirection =
-			Adapter->PackInfo[uiSearchRuleIndex].ucDirection;
-		pstClassifierEntry->uiClassifierRuleIndex = ntohs(psfCSType->
-				cCPacketClassificationRule.u16PacketClassificationRuleIndex);
-		pstClassifierEntry->usVCID_Value =
-			Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value;
-		pstClassifierEntry->ulSFID =
-			Adapter->PackInfo[uiSearchRuleIndex].ulSFID;
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Search Index %d Dir: %d, Index: %d, Vcid: %d\n",
-			uiSearchRuleIndex, pstClassifierEntry->ucDirection,
-			pstClassifierEntry->uiClassifierRuleIndex,
-			pstClassifierEntry->usVCID_Value);
-
-		if(psfCSType->cCPacketClassificationRule.u8AssociatedPHSI)
-		{
+		if (psfCSType->cCPacketClassificationRule.u8AssociatedPHSI)
 			pstClassifierEntry->u8AssociatedPHSI = psfCSType->cCPacketClassificationRule.u8AssociatedPHSI;
-		}
 
-		//Copy ETH CS Parameters
+		/* Copy ETH CS Parameters */
 		pstClassifierEntry->ucEthCSSrcMACLen = (psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddressLength);
-		memcpy(pstClassifierEntry->au8EThCSSrcMAC,psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress,MAC_ADDRESS_SIZE);
-		memcpy(pstClassifierEntry->au8EThCSSrcMACMask,psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress+MAC_ADDRESS_SIZE,MAC_ADDRESS_SIZE);
+		memcpy(pstClassifierEntry->au8EThCSSrcMAC, psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress, MAC_ADDRESS_SIZE);
+		memcpy(pstClassifierEntry->au8EThCSSrcMACMask, psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress + MAC_ADDRESS_SIZE, MAC_ADDRESS_SIZE);
 		pstClassifierEntry->ucEthCSDestMACLen = (psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
-		memcpy(pstClassifierEntry->au8EThCSDestMAC,psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress,MAC_ADDRESS_SIZE);
-		memcpy(pstClassifierEntry->au8EThCSDestMACMask,psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress+MAC_ADDRESS_SIZE,MAC_ADDRESS_SIZE);
+		memcpy(pstClassifierEntry->au8EThCSDestMAC, psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress, MAC_ADDRESS_SIZE);
+		memcpy(pstClassifierEntry->au8EThCSDestMACMask, psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress + MAC_ADDRESS_SIZE, MAC_ADDRESS_SIZE);
 		pstClassifierEntry->ucEtherTypeLen = (psfCSType->cCPacketClassificationRule.u8EthertypeLength);
-		memcpy(pstClassifierEntry->au8EthCSEtherType,psfCSType->cCPacketClassificationRule.u8Ethertype,NUM_ETHERTYPE_BYTES);
+		memcpy(pstClassifierEntry->au8EthCSEtherType, psfCSType->cCPacketClassificationRule.u8Ethertype, NUM_ETHERTYPE_BYTES);
 		memcpy(pstClassifierEntry->usUserPriority, &psfCSType->cCPacketClassificationRule.u16UserPriority, 2);
 		pstClassifierEntry->usVLANID = ntohs(psfCSType->cCPacketClassificationRule.u16VLANID);
 		pstClassifierEntry->usValidityBitMap = ntohs(psfCSType->cCPacketClassificationRule.u16ValidityBitMap);
@@ -434,244 +362,199 @@
 	}
 }
 
-
-/**
-@ingroup ctrl_pkt_functions
-*/
-static inline VOID DeleteClassifierRuleFromSF(PMINI_ADAPTER Adapter,UINT uiSearchRuleIndex,UINT nClassifierIndex)
+/*
+ * @ingroup ctrl_pkt_functions
+ */
+static inline VOID DeleteClassifierRuleFromSF(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex, UINT nClassifierIndex)
 {
 	S_CLASSIFIER_RULE *pstClassifierEntry = NULL;
-	B_UINT16  u16PacketClassificationRuleIndex;
-	USHORT	  usVCID;
-	//VOID *pvPhsContext = NULL;
-	//ULONG ulPhsStatus;
+	B_UINT16 u16PacketClassificationRuleIndex;
+	USHORT usVCID;
+	/* VOID *pvPhsContext = NULL; */
+	/*ULONG ulPhsStatus; */
 
 	usVCID = Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value;
 
-	if(nClassifierIndex > MAX_CLASSIFIERS-1)
+	if (nClassifierIndex > MAX_CLASSIFIERS-1)
 		return;
 
-	if(usVCID == 0)
+	if (usVCID == 0)
 		return;
 
 	u16PacketClassificationRuleIndex = Adapter->astClassifierTable[nClassifierIndex].uiClassifierRuleIndex;
-
-
 	pstClassifierEntry = &Adapter->astClassifierTable[nClassifierIndex];
-	if(pstClassifierEntry)
-	{
+	if (pstClassifierEntry) {
 		pstClassifierEntry->bUsed = FALSE;
 		pstClassifierEntry->uiClassifierRuleIndex = 0;
-		memset(pstClassifierEntry,0,sizeof(S_CLASSIFIER_RULE));
+		memset(pstClassifierEntry, 0, sizeof(S_CLASSIFIER_RULE));
 
-		//Delete the PHS Rule for this classifier
-		PhsDeleteClassifierRule(
-				&Adapter->stBCMPhsContext,
-				usVCID,
-				u16PacketClassificationRuleIndex);
+		/* Delete the PHS Rule for this classifier */
+		PhsDeleteClassifierRule(&Adapter->stBCMPhsContext, usVCID, u16PacketClassificationRuleIndex);
 	}
 }
 
-/**
-@ingroup ctrl_pkt_functions
-*/
-VOID DeleteAllClassifiersForSF(PMINI_ADAPTER Adapter,UINT uiSearchRuleIndex)
+/*
+ * @ingroup ctrl_pkt_functions
+ */
+VOID DeleteAllClassifiersForSF(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex)
 {
 	S_CLASSIFIER_RULE *pstClassifierEntry = NULL;
-	UINT nClassifierIndex;
-	//B_UINT16  u16PacketClassificationRuleIndex;
-	USHORT	  ulVCID;
-	//VOID	  *pvPhsContext = NULL;
-	//ULONG	   ulPhsStatus;
+	int i;
+	/* B_UINT16  u16PacketClassificationRuleIndex; */
+	USHORT ulVCID;
+	/* VOID *pvPhsContext = NULL; */
+	/* ULONG ulPhsStatus; */
 
 	ulVCID = Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value;
 
-	if(ulVCID == 0)
+	if (ulVCID == 0)
 		return;
 
+	for (i = 0; i < MAX_CLASSIFIERS; i++) {
+		if (Adapter->astClassifierTable[i].usVCID_Value == ulVCID) {
+			pstClassifierEntry = &Adapter->astClassifierTable[i];
 
-	for(nClassifierIndex =0 ; nClassifierIndex < MAX_CLASSIFIERS ; nClassifierIndex++)
-	{
-		if(Adapter->astClassifierTable[nClassifierIndex].usVCID_Value == ulVCID)
-		{
-			pstClassifierEntry = &Adapter->astClassifierTable[nClassifierIndex];
-			if(pstClassifierEntry->bUsed)
-			{
-				DeleteClassifierRuleFromSF(Adapter,uiSearchRuleIndex,nClassifierIndex);
-			}
+			if (pstClassifierEntry->bUsed)
+				DeleteClassifierRuleFromSF(Adapter, uiSearchRuleIndex, i);
 		}
 	}
 
-	//Delete All Phs Rules Associated with this SF
-	PhsDeleteSFRules(
-			&Adapter->stBCMPhsContext,
-			ulVCID);
-
+	/* Delete All Phs Rules Associated with this SF */
+	PhsDeleteSFRules(&Adapter->stBCMPhsContext, ulVCID);
 }
 
+/*
+ * This routinue  copies the Connection Management
+ * related data into the Adapter structure.
+ * @ingroup ctrl_pkt_functions
+ */
+static VOID CopyToAdapter(register PMINI_ADAPTER Adapter, /* <Pointer to the Adapter structure */
+			register pstServiceFlowParamSI psfLocalSet, /* <Pointer to the ServiceFlowParamSI structure */
+			register UINT uiSearchRuleIndex, /* <Index of Queue, to which this data belongs */
+			register UCHAR ucDsxType,
+			stLocalSFAddIndicationAlt *pstAddIndication) {
 
-/**
-This routinue  copies the Connection Management
-related data into the Adapter structure.
-@ingroup ctrl_pkt_functions
-*/
-
-static VOID CopyToAdapter( register PMINI_ADAPTER Adapter,		/**<Pointer to the Adapter structure*/
-					register pstServiceFlowParamSI psfLocalSet,	/**<Pointer to the ServiceFlowParamSI structure*/
-					register UINT uiSearchRuleIndex,			/**<Index of Queue, to which this data belongs*/
-					register UCHAR ucDsxType,
-					stLocalSFAddIndicationAlt *pstAddIndication)
-{
-	//UCHAR   ucProtocolLength=0;
-	ULONG	ulSFID;
-	UINT    nClassifierIndex = 0;
-	E_CLASSIFIER_ACTION eClassifierAction = eInvalidClassifierAction;
-	B_UINT16  u16PacketClassificationRuleIndex=0;
-	UINT     nIndex=0;
+	/* UCHAR ucProtocolLength = 0; */
+	ULONG ulSFID;
+	UINT nClassifierIndex = 0;
+	enum E_CLASSIFIER_ACTION eClassifierAction = eInvalidClassifierAction;
+	B_UINT16 u16PacketClassificationRuleIndex = 0;
+	int i;
 	stConvergenceSLTypes *psfCSType = NULL;
 	S_PHS_RULE sPhsRule;
 	USHORT uVCID = Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value;
 	UINT UGIValue = 0;
 
-
-	Adapter->PackInfo[uiSearchRuleIndex].bValid=TRUE;
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Search Rule Index = %d\n", uiSearchRuleIndex);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"%s: SFID= %x ",__FUNCTION__, ntohl(psfLocalSet->u32SFID));
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Updating Queue %d",uiSearchRuleIndex);
+	Adapter->PackInfo[uiSearchRuleIndex].bValid = TRUE;
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Search Rule Index = %d\n", uiSearchRuleIndex);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "%s: SFID= %x ", __func__, ntohl(psfLocalSet->u32SFID));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Updating Queue %d", uiSearchRuleIndex);
 
 	ulSFID = ntohl(psfLocalSet->u32SFID);
-	//Store IP Version used
-	//Get The Version Of IP used (IPv6 or IPv4) from CSSpecification field of SF
+	/* Store IP Version used */
+	/* Get The Version Of IP used (IPv6 or IPv4) from CSSpecification field of SF */
 
 	Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport = 0;
 	Adapter->PackInfo[uiSearchRuleIndex].bEthCSSupport = 0;
 
-	/*Enable IP/ETh CS Support As Required*/
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"CopyToAdapter : u8CSSpecification : %X\n",psfLocalSet->u8CSSpecification);
-	switch(psfLocalSet->u8CSSpecification)
+	/* Enable IP/ETh CS Support As Required */
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "CopyToAdapter : u8CSSpecification : %X\n", psfLocalSet->u8CSSpecification);
+	switch (psfLocalSet->u8CSSpecification) {
+	case eCSPacketIPV4:
 	{
-		case eCSPacketIPV4:
-		{
-			Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport = IPV4_CS;
-			break;
-		}
-		case eCSPacketIPV6:
-		{
-			Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport = IPV6_CS;
-			break;
-		}
-
-		case eCS802_3PacketEthernet:
-		case eCS802_1QPacketVLAN:
-		{
-			Adapter->PackInfo[uiSearchRuleIndex].bEthCSSupport = ETH_CS_802_3;
-			break;
-		}
-
-		case eCSPacketIPV4Over802_1QVLAN:
-		case eCSPacketIPV4Over802_3Ethernet:
-		{
-			Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport = IPV4_CS;
-			Adapter->PackInfo[uiSearchRuleIndex].bEthCSSupport = ETH_CS_802_3;
-			break;
-		}
-
-		case eCSPacketIPV6Over802_1QVLAN:
-		case eCSPacketIPV6Over802_3Ethernet:
-		{
-			Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport = IPV6_CS;
-			Adapter->PackInfo[uiSearchRuleIndex].bEthCSSupport = ETH_CS_802_3;
-			break;
-		}
-
-		default:
-		{
-            BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Error in value of CS Classification.. setting default to IP CS\n");
-			Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport = IPV4_CS;
-			break;
-		}
+		Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport = IPV4_CS;
+		break;
+	}
+	case eCSPacketIPV6:
+	{
+		Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport = IPV6_CS;
+		break;
+	}
+	case eCS802_3PacketEthernet:
+	case eCS802_1QPacketVLAN:
+	{
+		Adapter->PackInfo[uiSearchRuleIndex].bEthCSSupport = ETH_CS_802_3;
+		break;
+	}
+	case eCSPacketIPV4Over802_1QVLAN:
+	case eCSPacketIPV4Over802_3Ethernet:
+	{
+		Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport = IPV4_CS;
+		Adapter->PackInfo[uiSearchRuleIndex].bEthCSSupport = ETH_CS_802_3;
+		break;
+	}
+	case eCSPacketIPV6Over802_1QVLAN:
+	case eCSPacketIPV6Over802_3Ethernet:
+	{
+		Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport = IPV6_CS;
+		Adapter->PackInfo[uiSearchRuleIndex].bEthCSSupport = ETH_CS_802_3;
+		break;
+	}
+	default:
+	{
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Error in value of CS Classification.. setting default to IP CS\n");
+		Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport = IPV4_CS;
+		break;
+	}
 	}
 
-    BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"CopyToAdapter : Queue No : %X ETH CS Support :  %X  , IP CS Support : %X   \n",
-		uiSearchRuleIndex,
-		Adapter->PackInfo[uiSearchRuleIndex].bEthCSSupport,
-		Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "CopyToAdapter : Queue No : %X ETH CS Support :  %X  , IP CS Support : %X\n",
+			uiSearchRuleIndex,
+			Adapter->PackInfo[uiSearchRuleIndex].bEthCSSupport,
+			Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport);
 
-	//Store IP Version used
-	//Get The Version Of IP used (IPv6 or IPv4) from CSSpecification field of SF
-	if(Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport == IPV6_CS)
-	{
+	/* Store IP Version used */
+	/* Get The Version Of IP used (IPv6 or IPv4) from CSSpecification field of SF */
+	if (Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport == IPV6_CS)
 		Adapter->PackInfo[uiSearchRuleIndex].ucIpVersion = IPV6;
-	}
 	else
-	{
 		Adapter->PackInfo[uiSearchRuleIndex].ucIpVersion = IPV4;
-	}
 
 	/* To ensure that the ETH CS code doesn't gets executed if the BS doesn't supports ETH CS */
-	if(!Adapter->bETHCSEnabled)
+	if (!Adapter->bETHCSEnabled)
 		Adapter->PackInfo[uiSearchRuleIndex].bEthCSSupport = 0;
 
-	if(psfLocalSet->u8ServiceClassNameLength > 0 &&
-			psfLocalSet->u8ServiceClassNameLength < 32)
-	{
-		memcpy(Adapter->PackInfo[uiSearchRuleIndex].ucServiceClassName,
-			psfLocalSet->u8ServiceClassName,
-			psfLocalSet->u8ServiceClassNameLength);
-	}
-	Adapter->PackInfo[uiSearchRuleIndex].u8QueueType =
-			psfLocalSet->u8ServiceFlowSchedulingType;
+	if (psfLocalSet->u8ServiceClassNameLength > 0 && psfLocalSet->u8ServiceClassNameLength < 32)
+		memcpy(Adapter->PackInfo[uiSearchRuleIndex].ucServiceClassName,	psfLocalSet->u8ServiceClassName, psfLocalSet->u8ServiceClassNameLength);
 
-	if(Adapter->PackInfo[uiSearchRuleIndex].u8QueueType==BE &&
-			Adapter->PackInfo[uiSearchRuleIndex].ucDirection)
-	{
-		Adapter->usBestEffortQueueIndex=uiSearchRuleIndex;
-	}
+	Adapter->PackInfo[uiSearchRuleIndex].u8QueueType = psfLocalSet->u8ServiceFlowSchedulingType;
+
+	if (Adapter->PackInfo[uiSearchRuleIndex].u8QueueType == BE && Adapter->PackInfo[uiSearchRuleIndex].ucDirection)
+		Adapter->usBestEffortQueueIndex = uiSearchRuleIndex;
 
 	Adapter->PackInfo[uiSearchRuleIndex].ulSFID = ntohl(psfLocalSet->u32SFID);
 
 	Adapter->PackInfo[uiSearchRuleIndex].u8TrafficPriority = psfLocalSet->u8TrafficPriority;
 
-	//copy all the classifier in the Service Flow param  structure
-	for(nIndex=0; nIndex<psfLocalSet->u8TotalClassifiers; nIndex++)
-	{
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Classifier index =%d",nIndex);
-		psfCSType =  &psfLocalSet->cConvergenceSLTypes[nIndex];
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Classifier index =%d",nIndex);
+	/* copy all the classifier in the Service Flow param  structure */
+	for (i = 0; i < psfLocalSet->u8TotalClassifiers; i++) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Classifier index =%d", i);
+		psfCSType = &psfLocalSet->cConvergenceSLTypes[i];
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Classifier index =%d", i);
 
-		if(psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority)
-		{
-			Adapter->PackInfo[uiSearchRuleIndex].bClassifierPriority=TRUE;
-		}
+		if (psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority)
+			Adapter->PackInfo[uiSearchRuleIndex].bClassifierPriority = TRUE;
 
-		if(psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority)
-		{
-			Adapter->PackInfo[uiSearchRuleIndex].bClassifierPriority=TRUE;
-		}
+		if (psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority)
+			Adapter->PackInfo[uiSearchRuleIndex].bClassifierPriority = TRUE;
 
-
-		if(ucDsxType== DSA_ACK)
-		{
+		if (ucDsxType == DSA_ACK) {
 			eClassifierAction = eAddClassifier;
-		}
-		else if(ucDsxType == DSC_ACK)
-		{
-			switch(psfCSType->u8ClassfierDSCAction)
-			{
-			case 0://DSC Add Classifier
+		} else if (ucDsxType == DSC_ACK) {
+			switch (psfCSType->u8ClassfierDSCAction) {
+			case 0: /* DSC Add Classifier */
 			{
 				eClassifierAction = eAddClassifier;
 			}
 			break;
-			case 1://DSC Replace Classifier
+			case 1: /* DSC Replace Classifier */
 			{
 				eClassifierAction = eReplaceClassifier;
 			}
 			break;
-			case 2://DSC Delete Classifier
+			case 2: /* DSC Delete Classifier */
 			{
 				eClassifierAction = eDeleteClassifier;
-
 			}
 			break;
 			default:
@@ -683,163 +566,133 @@
 
 		u16PacketClassificationRuleIndex = ntohs(psfCSType->cCPacketClassificationRule.u16PacketClassificationRuleIndex);
 
-		switch(eClassifierAction)
-		{
+		switch (eClassifierAction) {
 		case eAddClassifier:
 		{
-			//Get a Free Classifier Index From Classifier table for this SF to add the Classifier
-			//Contained in this message
-			nClassifierIndex = SearchClsid(Adapter,ulSFID,u16PacketClassificationRuleIndex);
+			/* Get a Free Classifier Index From Classifier table for this SF to add the Classifier */
+			/* Contained in this message */
+			nClassifierIndex = SearchClsid(Adapter, ulSFID, u16PacketClassificationRuleIndex);
 
-			if(nClassifierIndex > MAX_CLASSIFIERS)
-			{
+			if (nClassifierIndex > MAX_CLASSIFIERS) {
 				nClassifierIndex = SearchFreeClsid(Adapter);
-				if(nClassifierIndex > MAX_CLASSIFIERS)
-				{
-					//Failed To get a free Entry
-					BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Error Failed To get a free Classifier Entry");
+				if (nClassifierIndex > MAX_CLASSIFIERS) {
+					/* Failed To get a free Entry */
+					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Error Failed To get a free Classifier Entry");
 					break;
 				}
-				//Copy the Classifier Rule for this service flow into our Classifier table maintained per SF.
-				CopyClassifierRuleToSF(Adapter,psfCSType,uiSearchRuleIndex,nClassifierIndex);
-			}
-
-			else
-			{
-				//This Classifier Already Exists and it is invalid to Add Classifier with existing PCRI
-				BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"CopyToAdapter : Error The Specified Classifier Already Exists \
-						and attempted To Add Classifier with Same PCRI : 0x%x\n", u16PacketClassificationRuleIndex);
+				/* Copy the Classifier Rule for this service flow into our Classifier table maintained per SF. */
+				CopyClassifierRuleToSF(Adapter, psfCSType, uiSearchRuleIndex, nClassifierIndex);
+			} else {
+				/* This Classifier Already Exists and it is invalid to Add Classifier with existing PCRI */
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,
+						"CopyToAdapter: Error The Specified Classifier Already Exists and attempted To Add Classifier with Same PCRI : 0x%x\n",
+						u16PacketClassificationRuleIndex);
 			}
 		}
 		break;
-
 		case eReplaceClassifier:
 		{
-				//Get the Classifier Index From Classifier table for this SF and replace existing  Classifier
-				//with the new classifier Contained in this message
-			nClassifierIndex = SearchClsid(Adapter,ulSFID,u16PacketClassificationRuleIndex);
-			if(nClassifierIndex > MAX_CLASSIFIERS)
-			{
-				//Failed To search the classifier
-				BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Error Search for Classifier To be replaced failed");
+			/* Get the Classifier Index From Classifier table for this SF and replace existing  Classifier */
+			/* with the new classifier Contained in this message */
+			nClassifierIndex = SearchClsid(Adapter, ulSFID, u16PacketClassificationRuleIndex);
+			if (nClassifierIndex > MAX_CLASSIFIERS) {
+				/* Failed To search the classifier */
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Error Search for Classifier To be replaced failed");
 				break;
 			}
-			//Copy the Classifier Rule for this service flow into our Classifier table maintained per SF.
-			CopyClassifierRuleToSF(Adapter,psfCSType,uiSearchRuleIndex,nClassifierIndex);
+			/* Copy the Classifier Rule for this service flow into our Classifier table maintained per SF. */
+			CopyClassifierRuleToSF(Adapter, psfCSType, uiSearchRuleIndex, nClassifierIndex);
 		}
 		break;
-
 		case eDeleteClassifier:
 		{
-				//Get the Classifier Index From Classifier table for this SF and replace existing  Classifier
-				//with the new classifier Contained in this message
-			nClassifierIndex = SearchClsid(Adapter,ulSFID,u16PacketClassificationRuleIndex);
-			if(nClassifierIndex > MAX_CLASSIFIERS)
-			{
-				//Failed To search the classifier
-				BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Error Search for Classifier To be deleted failed");
+			/* Get the Classifier Index From Classifier table for this SF and replace existing  Classifier */
+			/* with the new classifier Contained in this message */
+			nClassifierIndex = SearchClsid(Adapter, ulSFID, u16PacketClassificationRuleIndex);
+			if (nClassifierIndex > MAX_CLASSIFIERS)	{
+				/* Failed To search the classifier */
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Error Search for Classifier To be deleted failed");
 				break;
 			}
 
-			//Delete This classifier
-			DeleteClassifierRuleFromSF(Adapter,uiSearchRuleIndex,nClassifierIndex);
+			/* Delete This classifier */
+			DeleteClassifierRuleFromSF(Adapter, uiSearchRuleIndex, nClassifierIndex);
 		}
 		break;
-
 		default:
 		{
-			//Invalid Action for classifier
+			/* Invalid Action for classifier */
 			break;
 		}
 		}
 	}
 
-	//Repeat parsing Classification Entries to process PHS Rules
-	for(nIndex=0; nIndex < psfLocalSet->u8TotalClassifiers; nIndex++)
-	{
-		psfCSType =  &psfLocalSet->cConvergenceSLTypes[nIndex];
+	/* Repeat parsing Classification Entries to process PHS Rules */
+	for (i = 0; i < psfLocalSet->u8TotalClassifiers; i++) {
+		psfCSType = &psfLocalSet->cConvergenceSLTypes[i];
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "psfCSType->u8PhsDSCAction : 0x%x\n", psfCSType->u8PhsDSCAction);
 
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "psfCSType->u8PhsDSCAction : 0x%x\n",
-				psfCSType->u8PhsDSCAction );
-
-		switch (psfCSType->u8PhsDSCAction)
-		{
+		switch (psfCSType->u8PhsDSCAction) {
 		case eDeleteAllPHSRules:
 		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Deleting All PHS Rules For VCID: 0x%X\n",uVCID);
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Deleting All PHS Rules For VCID: 0x%X\n", uVCID);
 
-			//Delete All the PHS rules for this Service flow
-
-			PhsDeleteSFRules(
-				&Adapter->stBCMPhsContext,
-				uVCID);
-
+			/* Delete All the PHS rules for this Service flow */
+			PhsDeleteSFRules(&Adapter->stBCMPhsContext, uVCID);
 			break;
 		}
 		case eDeletePHSRule:
 		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"PHS DSC Action = Delete PHS Rule \n");
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "PHS DSC Action = Delete PHS Rule\n");
 
-			if(psfCSType->cPhsRule.u8PHSI)
-			{
-				PhsDeletePHSRule(
-					&Adapter->stBCMPhsContext,
-					uVCID,
-					psfCSType->cCPacketClassificationRule.u8AssociatedPHSI);
-			}
-			else
-			{
-				//BCM_DEBUG_PRINT(CONN_MSG,("Error CPHSRule.PHSI is ZERO \n"));
-			}
+			if (psfCSType->cPhsRule.u8PHSI)
+				PhsDeletePHSRule(&Adapter->stBCMPhsContext, uVCID, psfCSType->cCPacketClassificationRule.u8AssociatedPHSI);
+
 			break;
 		}
-		default :
+		default:
 		{
-			if(ucDsxType == DSC_ACK)
-			{
-				//BCM_DEBUG_PRINT(CONN_MSG,("Invalid PHS DSC Action For DSC \n",psfCSType->cPhsRule.u8PHSI));
-				break; //FOr DSC ACK Case PHS DSC Action must be in valid set
+			if (ucDsxType == DSC_ACK) {
+				/* BCM_DEBUG_PRINT(CONN_MSG,("Invalid PHS DSC Action For DSC\n",psfCSType->cPhsRule.u8PHSI)); */
+				break; /* FOr DSC ACK Case PHS DSC Action must be in valid set */
 			}
 		}
-		//Proceed To Add PHS rule for DSA_ACK case even if PHS DSC action is unspecified
-		//No Break Here . Intentionally!
+		/* Proceed To Add PHS rule for DSA_ACK case even if PHS DSC action is unspecified */
+		/* No Break Here . Intentionally! */
 
 		case eAddPHSRule:
 		case eSetPHSRule:
 		{
-			if(psfCSType->cPhsRule.u8PHSI)
-			{
-				//Apply This PHS Rule to all classifiers whose Associated PHSI Match
+			if (psfCSType->cPhsRule.u8PHSI)	{
+				/* Apply This PHS Rule to all classifiers whose Associated PHSI Match */
 				unsigned int uiClassifierIndex = 0;
-				if(pstAddIndication->u8Direction == UPLINK_DIR )
-				{
-					for(uiClassifierIndex=0;uiClassifierIndex<MAX_CLASSIFIERS;uiClassifierIndex++)
-					{
-						if((Adapter->astClassifierTable[uiClassifierIndex].bUsed) &&
+				if (pstAddIndication->u8Direction == UPLINK_DIR) {
+					for (uiClassifierIndex = 0; uiClassifierIndex < MAX_CLASSIFIERS; uiClassifierIndex++) {
+						if ((Adapter->astClassifierTable[uiClassifierIndex].bUsed) &&
 							(Adapter->astClassifierTable[uiClassifierIndex].ulSFID == Adapter->PackInfo[uiSearchRuleIndex].ulSFID) &&
-							(Adapter->astClassifierTable[uiClassifierIndex].u8AssociatedPHSI == psfCSType->cPhsRule.u8PHSI))
-						{
-							BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Adding  PHS Rule For  Classifier : 0x%x cPhsRule.u8PHSI : 0x%x\n",
-								Adapter->astClassifierTable[uiClassifierIndex].uiClassifierRuleIndex,
-								psfCSType->cPhsRule.u8PHSI);
-							//Update The PHS Rule for this classifier as Associated PHSI id defined
+							(Adapter->astClassifierTable[uiClassifierIndex].u8AssociatedPHSI == psfCSType->cPhsRule.u8PHSI)) {
+							BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,
+									"Adding PHS Rule For Classifier: 0x%x cPhsRule.u8PHSI: 0x%x\n",
+									Adapter->astClassifierTable[uiClassifierIndex].uiClassifierRuleIndex,
+									psfCSType->cPhsRule.u8PHSI);
+							/* Update The PHS Rule for this classifier as Associated PHSI id defined */
 
-							//Copy the PHS Rule
-							sPhsRule.u8PHSI =  psfCSType->cPhsRule.u8PHSI;
-							sPhsRule.u8PHSFLength =  psfCSType->cPhsRule.u8PHSFLength;
+							/* Copy the PHS Rule */
+							sPhsRule.u8PHSI = psfCSType->cPhsRule.u8PHSI;
+							sPhsRule.u8PHSFLength = psfCSType->cPhsRule.u8PHSFLength;
 							sPhsRule.u8PHSMLength = psfCSType->cPhsRule.u8PHSMLength;
 							sPhsRule.u8PHSS = psfCSType->cPhsRule.u8PHSS;
 							sPhsRule.u8PHSV = psfCSType->cPhsRule.u8PHSV;
-							memcpy(sPhsRule.u8PHSF,psfCSType->cPhsRule.u8PHSF,MAX_PHS_LENGTHS);
-							memcpy(sPhsRule.u8PHSM,psfCSType->cPhsRule.u8PHSM,MAX_PHS_LENGTHS);
+							memcpy(sPhsRule.u8PHSF, psfCSType->cPhsRule.u8PHSF, MAX_PHS_LENGTHS);
+							memcpy(sPhsRule.u8PHSM, psfCSType->cPhsRule.u8PHSM, MAX_PHS_LENGTHS);
 							sPhsRule.u8RefCnt = 0;
 							sPhsRule.bUnclassifiedPHSRule = FALSE;
 							sPhsRule.PHSModifiedBytes = 0;
 							sPhsRule.PHSModifiedNumPackets = 0;
 							sPhsRule.PHSErrorNumPackets = 0;
 
-							//bPHSRuleAssociated = TRUE;
-							//Store The PHS Rule for this classifier
+							/* bPHSRuleAssociated = TRUE; */
+							/* Store The PHS Rule for this classifier */
 
 							PhsUpdateClassifierRule(
 								&Adapter->stBCMPhsContext,
@@ -848,184 +701,157 @@
 								&sPhsRule,
 								Adapter->astClassifierTable[uiClassifierIndex].u8AssociatedPHSI);
 
-							//Update PHS Rule For the Classifier
-							if(sPhsRule.u8PHSI)
-							{
+							/* Update PHS Rule For the Classifier */
+							if (sPhsRule.u8PHSI) {
 								Adapter->astClassifierTable[uiClassifierIndex].u32PHSRuleID = sPhsRule.u8PHSI;
-								memcpy(&Adapter->astClassifierTable[uiClassifierIndex].sPhsRule,&sPhsRule,sizeof(S_PHS_RULE));
+								memcpy(&Adapter->astClassifierTable[uiClassifierIndex].sPhsRule, &sPhsRule, sizeof(S_PHS_RULE));
 							}
-
 						}
 					}
+				} else {
+					/* Error PHS Rule specified in signaling could not be applied to any classifier */
+
+					/* Copy the PHS Rule */
+					sPhsRule.u8PHSI = psfCSType->cPhsRule.u8PHSI;
+					sPhsRule.u8PHSFLength = psfCSType->cPhsRule.u8PHSFLength;
+					sPhsRule.u8PHSMLength = psfCSType->cPhsRule.u8PHSMLength;
+					sPhsRule.u8PHSS = psfCSType->cPhsRule.u8PHSS;
+					sPhsRule.u8PHSV = psfCSType->cPhsRule.u8PHSV;
+					memcpy(sPhsRule.u8PHSF, psfCSType->cPhsRule.u8PHSF, MAX_PHS_LENGTHS);
+					memcpy(sPhsRule.u8PHSM, psfCSType->cPhsRule.u8PHSM, MAX_PHS_LENGTHS);
+					sPhsRule.u8RefCnt = 0;
+					sPhsRule.bUnclassifiedPHSRule = TRUE;
+					sPhsRule.PHSModifiedBytes = 0;
+					sPhsRule.PHSModifiedNumPackets = 0;
+					sPhsRule.PHSErrorNumPackets = 0;
+					/* Store The PHS Rule for this classifier */
+
+					/*
+					 * Passing the argument u8PHSI instead of clsid. Because for DL with no classifier rule,
+					 * clsid will be zero hence we can't have multiple PHS rules for the same SF.
+					 * To support multiple PHS rule, passing u8PHSI.
+					 */
+					PhsUpdateClassifierRule(
+						&Adapter->stBCMPhsContext,
+						uVCID,
+						sPhsRule.u8PHSI,
+						&sPhsRule,
+						sPhsRule.u8PHSI);
 				}
-				else
-				{
-					//Error PHS Rule specified in signaling could not be applied to any classifier
-
-						//Copy the PHS Rule
-						sPhsRule.u8PHSI =  psfCSType->cPhsRule.u8PHSI;
-						sPhsRule.u8PHSFLength =  psfCSType->cPhsRule.u8PHSFLength;
-						sPhsRule.u8PHSMLength = psfCSType->cPhsRule.u8PHSMLength;
-						sPhsRule.u8PHSS = psfCSType->cPhsRule.u8PHSS;
-						sPhsRule.u8PHSV = psfCSType->cPhsRule.u8PHSV;
-						memcpy(sPhsRule.u8PHSF,psfCSType->cPhsRule.u8PHSF,MAX_PHS_LENGTHS);
-						memcpy(sPhsRule.u8PHSM,psfCSType->cPhsRule.u8PHSM,MAX_PHS_LENGTHS);
-						sPhsRule.u8RefCnt = 0;
-						sPhsRule.bUnclassifiedPHSRule = TRUE;
-						sPhsRule.PHSModifiedBytes = 0;
-						sPhsRule.PHSModifiedNumPackets = 0;
-						sPhsRule.PHSErrorNumPackets = 0;
-						//Store The PHS Rule for this classifier
-
-						/*
-							Passing the argument u8PHSI instead of clsid. Because for DL with no classifier rule,
-							clsid will be zero hence we can't have multiple PHS rules for the same SF.
-							To support multiple PHS rule, passing u8PHSI.
-						*/
-
-						PhsUpdateClassifierRule(
-							&Adapter->stBCMPhsContext,
-							uVCID,
-							sPhsRule.u8PHSI,
-							&sPhsRule,
-							sPhsRule.u8PHSI);
-
-				}
-
 			}
 		}
 		break;
 		}
 	}
 
-	if(psfLocalSet->u32MaxSustainedTrafficRate == 0	)
-	{
-		//No Rate Limit . Set Max Sustained Traffic Rate to Maximum
-		Adapter->PackInfo[uiSearchRuleIndex].uiMaxAllowedRate =
-			WIMAX_MAX_ALLOWED_RATE;
-
-	}
-	else if (ntohl(psfLocalSet->u32MaxSustainedTrafficRate) >
-			WIMAX_MAX_ALLOWED_RATE)
-	{
-		//Too large Allowed Rate specified. Limiting to Wi Max  Allowed rate
-		Adapter->PackInfo[uiSearchRuleIndex].uiMaxAllowedRate =
-			WIMAX_MAX_ALLOWED_RATE;
-	}
-	else
-	{
-		Adapter->PackInfo[uiSearchRuleIndex].uiMaxAllowedRate =
-			ntohl(psfLocalSet->u32MaxSustainedTrafficRate);
+	if (psfLocalSet->u32MaxSustainedTrafficRate == 0) {
+		/* No Rate Limit . Set Max Sustained Traffic Rate to Maximum */
+		Adapter->PackInfo[uiSearchRuleIndex].uiMaxAllowedRate = WIMAX_MAX_ALLOWED_RATE;
+	} else if (ntohl(psfLocalSet->u32MaxSustainedTrafficRate) > WIMAX_MAX_ALLOWED_RATE) {
+		/* Too large Allowed Rate specified. Limiting to Wi Max  Allowed rate */
+		Adapter->PackInfo[uiSearchRuleIndex].uiMaxAllowedRate = WIMAX_MAX_ALLOWED_RATE;
+	} else {
+		Adapter->PackInfo[uiSearchRuleIndex].uiMaxAllowedRate =  ntohl(psfLocalSet->u32MaxSustainedTrafficRate);
 	}
 
 	Adapter->PackInfo[uiSearchRuleIndex].uiMaxLatency = ntohl(psfLocalSet->u32MaximumLatency);
-
-	if(Adapter->PackInfo[uiSearchRuleIndex].uiMaxLatency == 0) /* 0 should be treated as infinite */
+	if (Adapter->PackInfo[uiSearchRuleIndex].uiMaxLatency == 0) /* 0 should be treated as infinite */
 		Adapter->PackInfo[uiSearchRuleIndex].uiMaxLatency = MAX_LATENCY_ALLOWED;
 
+	if ((Adapter->PackInfo[uiSearchRuleIndex].u8QueueType == ERTPS ||
+			Adapter->PackInfo[uiSearchRuleIndex].u8QueueType == UGS))
+		UGIValue = ntohs(psfLocalSet->u16UnsolicitedGrantInterval);
 
-	if(( Adapter->PackInfo[uiSearchRuleIndex].u8QueueType == ERTPS ||
-			Adapter->PackInfo[uiSearchRuleIndex].u8QueueType == UGS ) )
-			UGIValue = ntohs(psfLocalSet->u16UnsolicitedGrantInterval);
-
-	if(UGIValue == 0)
+	if (UGIValue == 0)
 		UGIValue = DEFAULT_UG_INTERVAL;
 
 	/*
-	For UGI based connections...
-	DEFAULT_UGI_FACTOR*UGIInterval worth of data is the max token count at host...
-	The extra amount of token is to ensure that a large amount of jitter won't have loss in throughput...
-	In case of non-UGI based connection, 200 frames worth of data is the max token count at host...
-	*/
-
+	 * For UGI based connections...
+	 * DEFAULT_UGI_FACTOR*UGIInterval worth of data is the max token count at host...
+	 * The extra amount of token is to ensure that a large amount of jitter won't have loss in throughput...
+	 * In case of non-UGI based connection, 200 frames worth of data is the max token count at host...
+	 */
 	Adapter->PackInfo[uiSearchRuleIndex].uiMaxBucketSize =
-        (DEFAULT_UGI_FACTOR*Adapter->PackInfo[uiSearchRuleIndex].uiMaxAllowedRate*UGIValue)/1000;
+		(DEFAULT_UGI_FACTOR*Adapter->PackInfo[uiSearchRuleIndex].uiMaxAllowedRate*UGIValue)/1000;
 
-	if(Adapter->PackInfo[uiSearchRuleIndex].uiMaxBucketSize < WIMAX_MAX_MTU*8)
-	{
+	if (Adapter->PackInfo[uiSearchRuleIndex].uiMaxBucketSize < WIMAX_MAX_MTU*8) {
 		UINT UGIFactor = 0;
 		/* Special Handling to ensure the biggest size of packet can go out from host to FW as follows:
-		1. Any packet from Host to FW can go out in different packet size.
-		2. So in case the Bucket count is smaller than MTU, the packets of size (Size > TokenCount), will get dropped.
-		3. We can allow packets of MaxSize from Host->FW that can go out from FW in multiple SDUs by fragmentation at Wimax Layer
-		*/
+		 * 1. Any packet from Host to FW can go out in different packet size.
+		 * 2. So in case the Bucket count is smaller than MTU, the packets of size (Size > TokenCount), will get dropped.
+		 * 3. We can allow packets of MaxSize from Host->FW that can go out from FW in multiple SDUs by fragmentation at Wimax Layer
+		 */
 		UGIFactor = (Adapter->PackInfo[uiSearchRuleIndex].uiMaxLatency/UGIValue + 1);
 
-		if(UGIFactor > DEFAULT_UGI_FACTOR)
-    		Adapter->PackInfo[uiSearchRuleIndex].uiMaxBucketSize =
-    		(UGIFactor*Adapter->PackInfo[uiSearchRuleIndex].uiMaxAllowedRate*UGIValue)/1000;
+		if (UGIFactor > DEFAULT_UGI_FACTOR)
+			Adapter->PackInfo[uiSearchRuleIndex].uiMaxBucketSize =
+				(UGIFactor*Adapter->PackInfo[uiSearchRuleIndex].uiMaxAllowedRate*UGIValue)/1000;
 
-		if(Adapter->PackInfo[uiSearchRuleIndex].uiMaxBucketSize > WIMAX_MAX_MTU*8)
+		if (Adapter->PackInfo[uiSearchRuleIndex].uiMaxBucketSize > WIMAX_MAX_MTU*8)
 			Adapter->PackInfo[uiSearchRuleIndex].uiMaxBucketSize = WIMAX_MAX_MTU*8;
 	}
 
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "LAT: %d, UGI: %d\n", Adapter->PackInfo[uiSearchRuleIndex].uiMaxLatency, UGIValue);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "uiMaxAllowedRate: 0x%x, u32MaxSustainedTrafficRate: 0x%x ,uiMaxBucketSize: 0x%x",
+			Adapter->PackInfo[uiSearchRuleIndex].uiMaxAllowedRate,
+			ntohl(psfLocalSet->u32MaxSustainedTrafficRate),
+			Adapter->PackInfo[uiSearchRuleIndex].uiMaxBucketSize);
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"LAT: %d, UGI: %d \n", Adapter->PackInfo[uiSearchRuleIndex].uiMaxLatency, UGIValue);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"uiMaxAllowedRate: 0x%x, u32MaxSustainedTrafficRate: 0x%x ,uiMaxBucketSize: 0x%x",
-		Adapter->PackInfo[uiSearchRuleIndex].uiMaxAllowedRate,
-		ntohl(psfLocalSet->u32MaxSustainedTrafficRate),
-		Adapter->PackInfo[uiSearchRuleIndex].uiMaxBucketSize);
+	/* copy the extended SF Parameters to Support MIBS */
+	CopyMIBSExtendedSFParameters(Adapter, psfLocalSet, uiSearchRuleIndex);
 
-	//copy the extended SF Parameters to Support MIBS
-	CopyMIBSExtendedSFParameters(Adapter,psfLocalSet,uiSearchRuleIndex);
-
-	//store header suppression enabled flag per SF
+	/* store header suppression enabled flag per SF */
 	Adapter->PackInfo[uiSearchRuleIndex].bHeaderSuppressionEnabled =
-			!(psfLocalSet->u8RequesttransmissionPolicy &
-				MASK_DISABLE_HEADER_SUPPRESSION);
+		!(psfLocalSet->u8RequesttransmissionPolicy &
+			MASK_DISABLE_HEADER_SUPPRESSION);
 
 	kfree(Adapter->PackInfo[uiSearchRuleIndex].pstSFIndication);
 	Adapter->PackInfo[uiSearchRuleIndex].pstSFIndication = pstAddIndication;
 
-	//Re Sort the SF list in PackInfo according to Traffic Priority
+	/* Re Sort the SF list in PackInfo according to Traffic Priority */
 	SortPackInfo(Adapter);
 
 	/* Re Sort the Classifier Rules table and re - arrange
-		according to Classifier Rule Priority */
+	 * according to Classifier Rule Priority
+	 */
 	SortClassifiers(Adapter);
-
 	DumpPhsRules(&Adapter->stBCMPhsContext);
-
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"%s <=====", __FUNCTION__);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "%s <=====", __func__);
 }
 
-
 /***********************************************************************
-* Function	  -	DumpCmControlPacket
-*
-* Description -	This routinue Dumps the Contents of the AddIndication
-*				Structure in the Connection Management Control Packet
-*
-* Parameter   -	pvBuffer: Pointer to the buffer containing the
-*				AddIndication data.
-*
-* Returns	  - None
-*************************************************************************/
+ * Function - DumpCmControlPacket
+ *
+ * Description - This routinue Dumps the Contents of the AddIndication
+ *  Structure in the Connection Management Control Packet
+ *
+ * Parameter - pvBuffer: Pointer to the buffer containing the
+ *  AddIndication data.
+ *
+ * Returns - None
+ *************************************************************************/
 static VOID DumpCmControlPacket(PVOID pvBuffer)
 {
-	UINT 					uiLoopIndex;
-	UINT                    nIndex;
-	stLocalSFAddIndicationAlt  *pstAddIndication;
-	UINT                    nCurClassifierCnt;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	int uiLoopIndex;
+	int nIndex;
+	stLocalSFAddIndicationAlt *pstAddIndication;
+	UINT nCurClassifierCnt;
+	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
 	pstAddIndication = (stLocalSFAddIndicationAlt *)pvBuffer;
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "======>");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "======>");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Type: 0x%X", pstAddIndication->u8Type);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Direction: 0x%X", pstAddIndication->u8Direction);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16TID: 0x%X", ntohs(pstAddIndication->u16TID));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16CID: 0x%X", ntohs(pstAddIndication->u16CID));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16VCID: 0x%X", ntohs(pstAddIndication->u16VCID));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " AuthorizedSet--->");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32SFID: 0x%X", htonl(pstAddIndication->sfAuthorizedSet.u32SFID));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16CID: 0x%X", htons(pstAddIndication->sfAuthorizedSet.u16CID));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassNameLength: 0x%X",
+			pstAddIndication->sfAuthorizedSet.u8ServiceClassNameLength);
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8Type		: 0x%X",pstAddIndication->u8Type);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8Direction	: 0x%X",pstAddIndication->u8Direction);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16TID: 0x%X", ntohs(pstAddIndication->u16TID));
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16CID		: 0x%X",ntohs(pstAddIndication->u16CID));
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16VCID		: 0x%X",ntohs(pstAddIndication->u16VCID));
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " AuthorizedSet--->");
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32SFID		: 0x%X",htonl(pstAddIndication->sfAuthorizedSet.u32SFID));
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16CID		: 0x%X",htons(pstAddIndication->sfAuthorizedSet.u16CID));
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ServiceClassNameLength	: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u8ServiceClassNameLength);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassName		: 0x%X ,0x%X , 0x%X, 0x%X, 0x%X, 0x%X",
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassName: 0x%X ,0x%X , 0x%X, 0x%X, 0x%X, 0x%X",
 			pstAddIndication->sfAuthorizedSet.u8ServiceClassName[0],
 			pstAddIndication->sfAuthorizedSet.u8ServiceClassName[1],
 			pstAddIndication->sfAuthorizedSet.u8ServiceClassName[2],
@@ -1033,207 +859,170 @@
 			pstAddIndication->sfAuthorizedSet.u8ServiceClassName[4],
 			pstAddIndication->sfAuthorizedSet.u8ServiceClassName[5]);
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8MBSService		: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u8MBSService);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8QosParamSet		: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u8QosParamSet);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficPriority	: 0x%X, %p",
-		pstAddIndication->sfAuthorizedSet.u8TrafficPriority, &pstAddIndication->sfAuthorizedSet.u8TrafficPriority);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32MaxSustainedTrafficRate	: 0x%X 0x%p",
-		pstAddIndication->sfAuthorizedSet.u32MaxSustainedTrafficRate,
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8MBSService: 0x%X", pstAddIndication->sfAuthorizedSet.u8MBSService);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8QosParamSet: 0x%X", pstAddIndication->sfAuthorizedSet.u8QosParamSet);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficPriority: 0x%X, %p",
+			pstAddIndication->sfAuthorizedSet.u8TrafficPriority, &pstAddIndication->sfAuthorizedSet.u8TrafficPriority);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaxSustainedTrafficRate: 0x%X 0x%p",
+			pstAddIndication->sfAuthorizedSet.u32MaxSustainedTrafficRate,
 			&pstAddIndication->sfAuthorizedSet.u32MaxSustainedTrafficRate);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaxTrafficBurst: 0x%X", pstAddIndication->sfAuthorizedSet.u32MaxTrafficBurst);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MinReservedTrafficRate	: 0x%X",
+			pstAddIndication->sfAuthorizedSet.u32MinReservedTrafficRate);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParamLength: 0x%X",
+			pstAddIndication->sfAuthorizedSet.u8VendorSpecificQoSParamLength);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParam: 0x%X",
+			pstAddIndication->sfAuthorizedSet.u8VendorSpecificQoSParam[0]);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceFlowSchedulingType: 0x%X",
+			pstAddIndication->sfAuthorizedSet.u8ServiceFlowSchedulingType);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32ToleratedJitter: 0x%X", pstAddIndication->sfAuthorizedSet.u32ToleratedJitter);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaximumLatency: 0x%X", pstAddIndication->sfAuthorizedSet.u32MaximumLatency);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8FixedLengthVSVariableLengthSDUIndicator: 0x%X",
+			pstAddIndication->sfAuthorizedSet.u8FixedLengthVSVariableLengthSDUIndicator);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8SDUSize: 0x%X",	pstAddIndication->sfAuthorizedSet.u8SDUSize);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16TargetSAID: 0x%X", pstAddIndication->sfAuthorizedSet.u16TargetSAID);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ARQEnable: 0x%X", pstAddIndication->sfAuthorizedSet.u8ARQEnable);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQWindowSize: 0x%X", pstAddIndication->sfAuthorizedSet.u16ARQWindowSize);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQRetryTxTimeOut: 0x%X", pstAddIndication->sfAuthorizedSet.u16ARQRetryTxTimeOut);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQRetryRxTimeOut: 0x%X", pstAddIndication->sfAuthorizedSet.u16ARQRetryRxTimeOut);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQBlockLifeTime: 0x%X", pstAddIndication->sfAuthorizedSet.u16ARQBlockLifeTime);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQSyncLossTimeOut: 0x%X", pstAddIndication->sfAuthorizedSet.u16ARQSyncLossTimeOut);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ARQDeliverInOrder: 0x%X", pstAddIndication->sfAuthorizedSet.u8ARQDeliverInOrder);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQRxPurgeTimeOut: 0x%X", pstAddIndication->sfAuthorizedSet.u16ARQRxPurgeTimeOut);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQBlockSize: 0x%X", pstAddIndication->sfAuthorizedSet.u16ARQBlockSize);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8CSSpecification: 0x%X",	pstAddIndication->sfAuthorizedSet.u8CSSpecification);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TypeOfDataDeliveryService: 0x%X",
+			pstAddIndication->sfAuthorizedSet.u8TypeOfDataDeliveryService);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16SDUInterArrivalTime: 0x%X", pstAddIndication->sfAuthorizedSet.u16SDUInterArrivalTime);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16TimeBase: 0x%X", pstAddIndication->sfAuthorizedSet.u16TimeBase);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8PagingPreference: 0x%X", pstAddIndication->sfAuthorizedSet.u8PagingPreference);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16UnsolicitedPollingInterval: 0x%X",
+			pstAddIndication->sfAuthorizedSet.u16UnsolicitedPollingInterval);
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaxTrafficBurst			: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u32MaxTrafficBurst);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MinReservedTrafficRate	: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u32MinReservedTrafficRate);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParamLength	: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u8VendorSpecificQoSParamLength);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParam		: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u8VendorSpecificQoSParam[0]);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceFlowSchedulingType		: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u8ServiceFlowSchedulingType);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32ToleratedJitter				: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u32ToleratedJitter);
-    BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32MaximumLatency				: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u32MaximumLatency);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8FixedLengthVSVariableLengthSDUIndicator: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u8FixedLengthVSVariableLengthSDUIndicator);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8SDUSize				: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u8SDUSize);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16TargetSAID			: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u16TargetSAID);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ARQEnable				: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u8ARQEnable);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQWindowSize		: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u16ARQWindowSize);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQRetryTxTimeOut	: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u16ARQRetryTxTimeOut);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16ARQRetryRxTimeOut	: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u16ARQRetryRxTimeOut);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQBlockLifeTime		: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u16ARQBlockLifeTime);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16ARQSyncLossTimeOut	: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u16ARQSyncLossTimeOut);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ARQDeliverInOrder		: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u8ARQDeliverInOrder);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16ARQRxPurgeTimeOut	: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u16ARQRxPurgeTimeOut);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16ARQBlockSize			: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u16ARQBlockSize);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8CSSpecification		: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u8CSSpecification);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8TypeOfDataDeliveryService	: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u8TypeOfDataDeliveryService);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16SDUInterArrivalTime	: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u16SDUInterArrivalTime);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16TimeBase				: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u16TimeBase);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8PagingPreference		: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u8PagingPreference);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16UnsolicitedPollingInterval		: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u16UnsolicitedPollingInterval);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "sfAuthorizedSet.u8HARQChannelMapping %x  %x %x ",
-				*(unsigned int*)pstAddIndication->sfAuthorizedSet.u8HARQChannelMapping,
-				*(unsigned int*)&pstAddIndication->sfAuthorizedSet.u8HARQChannelMapping[4],
-			*(USHORT*) &pstAddIndication->sfAuthorizedSet.u8HARQChannelMapping[8]);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8TrafficIndicationPreference	: 0x%X",
-		pstAddIndication->sfAuthorizedSet.u8TrafficIndicationPreference);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " Total Classifiers Received		: 0x%X",pstAddIndication->sfAuthorizedSet.u8TotalClassifiers);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "sfAuthorizedSet.u8HARQChannelMapping %x  %x %x ",
+			*(unsigned int *)pstAddIndication->sfAuthorizedSet.u8HARQChannelMapping,
+			*(unsigned int *)&pstAddIndication->sfAuthorizedSet.u8HARQChannelMapping[4],
+			*(USHORT *)&pstAddIndication->sfAuthorizedSet.u8HARQChannelMapping[8]);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficIndicationPreference: 0x%X",
+			pstAddIndication->sfAuthorizedSet.u8TrafficIndicationPreference);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " Total Classifiers Received: 0x%X", pstAddIndication->sfAuthorizedSet.u8TotalClassifiers);
 
 	nCurClassifierCnt = pstAddIndication->sfAuthorizedSet.u8TotalClassifiers;
-
-	if(nCurClassifierCnt > MAX_CLASSIFIERS_IN_SF)
-	{
+	if (nCurClassifierCnt > MAX_CLASSIFIERS_IN_SF)
 		nCurClassifierCnt = MAX_CLASSIFIERS_IN_SF;
-	}
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "pstAddIndication->sfAuthorizedSet.bValid %d", pstAddIndication->sfAuthorizedSet.bValid);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "pstAddIndication->sfAuthorizedSet.u16MacOverhead %x", pstAddIndication->sfAuthorizedSet.u16MacOverhead);
-	if(!pstAddIndication->sfAuthorizedSet.bValid)
-		pstAddIndication->sfAuthorizedSet.bValid=1;
-	for(nIndex = 0 ; nIndex < nCurClassifierCnt ; nIndex++)
-	{
+
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "pstAddIndication->sfAuthorizedSet.bValid %d", pstAddIndication->sfAuthorizedSet.bValid);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "pstAddIndication->sfAuthorizedSet.u16MacOverhead %x", pstAddIndication->sfAuthorizedSet.u16MacOverhead);
+	if (!pstAddIndication->sfAuthorizedSet.bValid)
+		pstAddIndication->sfAuthorizedSet.bValid = 1;
+	for (nIndex = 0; nIndex < nCurClassifierCnt; nIndex++) {
 		stConvergenceSLTypes *psfCSType = NULL;
 		psfCSType =  &pstAddIndication->sfAuthorizedSet.cConvergenceSLTypes[nIndex];
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "psfCSType = %p", psfCSType);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "CCPacketClassificationRuleSI====>");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "psfCSType = %p", psfCSType);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "CCPacketClassificationRuleSI====>");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ClassifierRulePriority: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPTypeOfServiceLength: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPTypeOfService[3]: 0x%X ,0x%X ,0x%X ",
+				psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0],
+				psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1],
+				psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ClassifierRulePriority		:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPTypeOfServiceLength			:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength);
+		for (uiLoopIndex = 0; uiLoopIndex < 1; uiLoopIndex++)
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Protocol: 0x%02X ",
+					psfCSType->cCPacketClassificationRule.u8Protocol);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPTypeOfService[3]			:0x%X ,0x%X ,0x%X ",
-			psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0],
-			psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1],
-			psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPMaskedSourceAddressLength: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddressLength);
 
-		for(uiLoopIndex=0; uiLoopIndex < 1; uiLoopIndex++)
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8Protocol : 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8Protocol);
+		for (uiLoopIndex = 0; uiLoopIndex < 32; uiLoopIndex++)
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPMaskedSourceAddress[32]: 0x%02X ",
+					psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddress[uiLoopIndex]);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPMaskedSourceAddressLength	:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddressLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPDestinationAddressLength: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8IPDestinationAddressLength);
 
-		for(uiLoopIndex=0; uiLoopIndex < 32; uiLoopIndex++)
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPMaskedSourceAddress[32]	: 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddress[uiLoopIndex]);
+		for (uiLoopIndex = 0; uiLoopIndex < 32; uiLoopIndex++)
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPDestinationAddress[32]: 0x%02X ",
+					psfCSType->cCPacketClassificationRule.u8IPDestinationAddress[uiLoopIndex]);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPDestinationAddressLength : 0x%X ",
-			psfCSType->cCPacketClassificationRule.u8IPDestinationAddressLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolSourcePortRangeLength:0x%X ",
+				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolSourcePortRange[4]: 0x%02X ,0x%02X ,0x%02X ,0x%02X ",
+				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[0],
+				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[1],
+				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[2],
+				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[3]);
 
-		for(uiLoopIndex=0; uiLoopIndex < 32; uiLoopIndex++)
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPDestinationAddress[32] : 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8IPDestinationAddress[uiLoopIndex]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolDestPortRangeLength: 0x%02X ",
+				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolDestPortRange[4]: 0x%02X ,0x%02X ,0x%02X ,0x%02X ",
+				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[0],
+				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[1],
+				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[2],
+				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[3]);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ProtocolSourcePortRangeLength:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ProtocolSourcePortRange[4]: 0x%02X ,0x%02X ,0x%02X ,0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[0],
-			psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[1],
-			psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[2],
-			psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[3]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetDestMacAddressLength: 0x%02X ",
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ProtocolDestPortRangeLength : 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ProtocolDestPortRange[4]: 0x%02X ,0x%02X ,0x%02X ,0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[0],
-			psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[1],
-			psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[2],
-			psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[3]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetDestMacAddress[6]: 0x %02X %02X %02X %02X %02X %02X",
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[0],
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[1],
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[2],
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[3],
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[4],
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[5]);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8EthernetDestMacAddressLength : 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetSourceMACAddressLength: 0x%02X ",
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8EthernetDestMacAddress[6] : 0x %02X %02X %02X %02X %02X %02X",
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[0],
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[1],
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[2],
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[3],
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[4],
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[5]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetSourceMACAddress[6]: 0x %02X %02X %02X %02X %02X %02X",
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[0],
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[1],
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[2],
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[3],
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[4],
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[5]);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8EthernetSourceMACAddressLength : 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthertypeLength: 0x%02X ",
+				psfCSType->cCPacketClassificationRule.u8EthertypeLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Ethertype[3]: 0x%02X ,0x%02X ,0x%02X ",
+				psfCSType->cCPacketClassificationRule.u8Ethertype[0],
+				psfCSType->cCPacketClassificationRule.u8Ethertype[1],
+				psfCSType->cCPacketClassificationRule.u8Ethertype[2]);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8EthernetSourceMACAddress[6] : 0x %02X %02X %02X %02X %02X %02X",
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[0],
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[1],
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[2],
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[3],
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[4],
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[5]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16UserPriority: 0x%X ", psfCSType->cCPacketClassificationRule.u16UserPriority);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16VLANID: 0x%X ", psfCSType->cCPacketClassificationRule.u16VLANID);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8AssociatedPHSI: 0x%02X ", psfCSType->cCPacketClassificationRule.u8AssociatedPHSI);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16PacketClassificationRuleIndex: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u16PacketClassificationRuleIndex);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8EthertypeLength	: 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8EthertypeLength);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8Ethertype[3] : 0x%02X ,0x%02X ,0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8Ethertype[0],
-			psfCSType->cCPacketClassificationRule.u8Ethertype[1],
-			psfCSType->cCPacketClassificationRule.u8Ethertype[2]);
-
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16UserPriority		: 0x%X ",
-			psfCSType->cCPacketClassificationRule.u16UserPriority);
-
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16VLANID			: 0x%X ",
-			psfCSType->cCPacketClassificationRule.u16VLANID);
-
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8AssociatedPHSI	: 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8AssociatedPHSI);
-
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16PacketClassificationRuleIndex : 0x%X ",
-			psfCSType->cCPacketClassificationRule.u16PacketClassificationRuleIndex);
-
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8VendorSpecificClassifierParamLength	: 0x%X ",
-			psfCSType->cCPacketClassificationRule.u8VendorSpecificClassifierParamLength);
-
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8VendorSpecificClassifierParam[1]		: 0x%X ",
-			psfCSType->cCPacketClassificationRule.u8VendorSpecificClassifierParam[0]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificClassifierParamLength: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8VendorSpecificClassifierParamLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificClassifierParam[1]: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8VendorSpecificClassifierParam[0]);
 #ifdef VERSION_D5
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPv6FlowLableLength				:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLableLength);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPv6FlowLable[6] : 0x %02X %02X %02X %02X %02X %02X ",
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[0],
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[1],
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[2],
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[3],
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[4],
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[5]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLableLength: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLableLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLable[6]: 0x %02X %02X %02X %02X %02X %02X ",
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[0],
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[1],
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[2],
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[3],
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[4],
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[5]);
 #endif
 	}
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "bValid		: 0x%02X",pstAddIndication->sfAuthorizedSet.bValid);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "AdmittedSet--->");
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32SFID		: 0x%X",pstAddIndication->sfAdmittedSet.u32SFID);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16CID		: 0x%X",pstAddIndication->sfAdmittedSet.u16CID);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ServiceClassNameLength	: 0x%X",
-		pstAddIndication->sfAdmittedSet.u8ServiceClassNameLength);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ServiceClassName			: 0x %02X %02X %02X %02X %02X %02X",
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "bValid: 0x%02X", pstAddIndication->sfAuthorizedSet.bValid);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "AdmittedSet--->");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32SFID: 0x%X", pstAddIndication->sfAdmittedSet.u32SFID);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16CID: 0x%X", pstAddIndication->sfAdmittedSet.u16CID);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassNameLength: 0x%X",
+			pstAddIndication->sfAdmittedSet.u8ServiceClassNameLength);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassName: 0x %02X %02X %02X %02X %02X %02X",
 			pstAddIndication->sfAdmittedSet.u8ServiceClassName[0],
 			pstAddIndication->sfAdmittedSet.u8ServiceClassName[1],
 			pstAddIndication->sfAdmittedSet.u8ServiceClassName[2],
@@ -1241,429 +1030,338 @@
 			pstAddIndication->sfAdmittedSet.u8ServiceClassName[4],
 			pstAddIndication->sfAdmittedSet.u8ServiceClassName[5]);
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8MBSService				: 0x%02X",
-			pstAddIndication->sfAdmittedSet.u8MBSService);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8QosParamSet				: 0x%02X",
-			pstAddIndication->sfAdmittedSet.u8QosParamSet);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8TrafficPriority			: 0x%02X",
-			pstAddIndication->sfAdmittedSet.u8TrafficPriority);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32MaxTrafficBurst			: 0x%X",
-			pstAddIndication->sfAdmittedSet.u32MaxTrafficBurst);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32MinReservedTrafficRate	: 0x%X",
-		pstAddIndication->sfAdmittedSet.u32MinReservedTrafficRate);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8MBSService: 0x%02X", pstAddIndication->sfAdmittedSet.u8MBSService);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8QosParamSet: 0x%02X", pstAddIndication->sfAdmittedSet.u8QosParamSet);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficPriority: 0x%02X", pstAddIndication->sfAdmittedSet.u8TrafficPriority);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaxTrafficBurst: 0x%X", pstAddIndication->sfAdmittedSet.u32MaxTrafficBurst);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MinReservedTrafficRate: 0x%X",
+			pstAddIndication->sfAdmittedSet.u32MinReservedTrafficRate);
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8VendorSpecificQoSParamLength	: 0x%02X",
-		pstAddIndication->sfAdmittedSet.u8VendorSpecificQoSParamLength);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8VendorSpecificQoSParam		: 0x%02X",
-		pstAddIndication->sfAdmittedSet.u8VendorSpecificQoSParam[0]);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ServiceFlowSchedulingType		: 0x%02X",
-		pstAddIndication->sfAdmittedSet.u8ServiceFlowSchedulingType);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32ToleratedJitter				: 0x%X",
-		pstAddIndication->sfAdmittedSet.u32ToleratedJitter);
-    BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32MaximumLatency				: 0x%X",
-		pstAddIndication->sfAdmittedSet.u32MaximumLatency);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8FixedLengthVSVariableLengthSDUIndicator: 0x%02X",
-		pstAddIndication->sfAdmittedSet.u8FixedLengthVSVariableLengthSDUIndicator);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8SDUSize			: 0x%02X",
-		pstAddIndication->sfAdmittedSet.u8SDUSize);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16TargetSAID		: 0x%02X",
-		pstAddIndication->sfAdmittedSet.u16TargetSAID);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ARQEnable			: 0x%02X",
-		pstAddIndication->sfAdmittedSet.u8ARQEnable);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16ARQWindowSize		: 0x%X",
-		pstAddIndication->sfAdmittedSet.u16ARQWindowSize);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16ARQRetryTxTimeOut	: 0x%X",
-		pstAddIndication->sfAdmittedSet.u16ARQRetryTxTimeOut);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16ARQRetryRxTimeOut	: 0x%X",
-		pstAddIndication->sfAdmittedSet.u16ARQRetryRxTimeOut);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16ARQBlockLifeTime		: 0x%X",
-		pstAddIndication->sfAdmittedSet.u16ARQBlockLifeTime);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16ARQSyncLossTimeOut	: 0x%X",
-		pstAddIndication->sfAdmittedSet.u16ARQSyncLossTimeOut);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ARQDeliverInOrder		: 0x%02X",
-		pstAddIndication->sfAdmittedSet.u8ARQDeliverInOrder);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16ARQRxPurgeTimeOut	: 0x%X",
-		pstAddIndication->sfAdmittedSet.u16ARQRxPurgeTimeOut);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16ARQBlockSize			: 0x%X",
-		pstAddIndication->sfAdmittedSet.u16ARQBlockSize);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8CSSpecification		: 0x%02X",
-		pstAddIndication->sfAdmittedSet.u8CSSpecification);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8TypeOfDataDeliveryService	: 0x%02X",
-		pstAddIndication->sfAdmittedSet.u8TypeOfDataDeliveryService);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16SDUInterArrivalTime	: 0x%X",
-		pstAddIndication->sfAdmittedSet.u16SDUInterArrivalTime);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16TimeBase				: 0x%X",
-		pstAddIndication->sfAdmittedSet.u16TimeBase);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8PagingPreference		: 0x%X",
-		pstAddIndication->sfAdmittedSet.u8PagingPreference);
-
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8TrafficIndicationPreference	: 0x%02X",
-		pstAddIndication->sfAdmittedSet.u8TrafficIndicationPreference);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " Total Classifiers Received		: 0x%X",pstAddIndication->sfAdmittedSet.u8TotalClassifiers);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParamLength: 0x%02X",
+			pstAddIndication->sfAdmittedSet.u8VendorSpecificQoSParamLength);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParam: 0x%02X",
+			pstAddIndication->sfAdmittedSet.u8VendorSpecificQoSParam[0]);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceFlowSchedulingType: 0x%02X",
+			pstAddIndication->sfAdmittedSet.u8ServiceFlowSchedulingType);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32ToleratedJitter: 0x%X", pstAddIndication->sfAdmittedSet.u32ToleratedJitter);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaximumLatency: 0x%X", pstAddIndication->sfAdmittedSet.u32MaximumLatency);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8FixedLengthVSVariableLengthSDUIndicator: 0x%02X",
+			pstAddIndication->sfAdmittedSet.u8FixedLengthVSVariableLengthSDUIndicator);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8SDUSize: 0x%02X", pstAddIndication->sfAdmittedSet.u8SDUSize);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16TargetSAID: 0x%02X", pstAddIndication->sfAdmittedSet.u16TargetSAID);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ARQEnable: 0x%02X", pstAddIndication->sfAdmittedSet.u8ARQEnable);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQWindowSize: 0x%X", pstAddIndication->sfAdmittedSet.u16ARQWindowSize);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQRetryTxTimeOut: 0x%X", pstAddIndication->sfAdmittedSet.u16ARQRetryTxTimeOut);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQRetryRxTimeOut: 0x%X", pstAddIndication->sfAdmittedSet.u16ARQRetryRxTimeOut);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQBlockLifeTime: 0x%X", pstAddIndication->sfAdmittedSet.u16ARQBlockLifeTime);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQSyncLossTimeOut: 0x%X", pstAddIndication->sfAdmittedSet.u16ARQSyncLossTimeOut);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ARQDeliverInOrder: 0x%02X", pstAddIndication->sfAdmittedSet.u8ARQDeliverInOrder);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQRxPurgeTimeOut: 0x%X", pstAddIndication->sfAdmittedSet.u16ARQRxPurgeTimeOut);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQBlockSize: 0x%X", pstAddIndication->sfAdmittedSet.u16ARQBlockSize);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8CSSpecification: 0x%02X", pstAddIndication->sfAdmittedSet.u8CSSpecification);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TypeOfDataDeliveryService: 0x%02X",
+			pstAddIndication->sfAdmittedSet.u8TypeOfDataDeliveryService);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16SDUInterArrivalTime: 0x%X", pstAddIndication->sfAdmittedSet.u16SDUInterArrivalTime);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16TimeBase: 0x%X", pstAddIndication->sfAdmittedSet.u16TimeBase);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8PagingPreference: 0x%X", pstAddIndication->sfAdmittedSet.u8PagingPreference);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficIndicationPreference: 0x%02X",
+			pstAddIndication->sfAdmittedSet.u8TrafficIndicationPreference);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " Total Classifiers Received: 0x%X", pstAddIndication->sfAdmittedSet.u8TotalClassifiers);
 
 	nCurClassifierCnt = pstAddIndication->sfAdmittedSet.u8TotalClassifiers;
-
-	if(nCurClassifierCnt > MAX_CLASSIFIERS_IN_SF)
-	{
+	if (nCurClassifierCnt > MAX_CLASSIFIERS_IN_SF)
 		nCurClassifierCnt = MAX_CLASSIFIERS_IN_SF;
-	}
 
-
-	for(nIndex = 0 ; nIndex < nCurClassifierCnt ; nIndex++)
-	{
-
+	for (nIndex = 0; nIndex < nCurClassifierCnt; nIndex++) {
 		stConvergenceSLTypes *psfCSType = NULL;
+
 		psfCSType =  &pstAddIndication->sfAdmittedSet.cConvergenceSLTypes[nIndex];
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " CCPacketClassificationRuleSI====>");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ClassifierRulePriority: 0x%02X ",
+				psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPTypeOfServiceLength: 0x%02X",
+				psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPTypeOfService[3]: 0x%02X %02X %02X",
+				psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0],
+				psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1],
+				psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]);
+		for (uiLoopIndex = 0; uiLoopIndex < 1; uiLoopIndex++)
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Protocol: 0x%02X ", psfCSType->cCPacketClassificationRule.u8Protocol);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " CCPacketClassificationRuleSI====>");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPMaskedSourceAddressLength: 0x%02X ",
+				psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddressLength);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ClassifierRulePriority	:0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPTypeOfServiceLength		:0x%02X",
-			psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength);
+		for (uiLoopIndex = 0; uiLoopIndex < 32; uiLoopIndex++)
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPMaskedSourceAddress[32]: 0x%02X ",
+					psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddress[uiLoopIndex]);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPTypeOfService[3]		:0x%02X %02X %02X",
-			psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0],
-			psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1],
-			psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]);
-		for(uiLoopIndex=0; uiLoopIndex < 1; uiLoopIndex++)
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8Protocol: 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8Protocol);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPDestinationAddressLength: 0x%02X ",
+				psfCSType->cCPacketClassificationRule.u8IPDestinationAddressLength);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPMaskedSourceAddressLength	:0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddressLength);
+		for (uiLoopIndex = 0; uiLoopIndex < 32; uiLoopIndex++)
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPDestinationAddress[32]: 0x%02X ",
+					psfCSType->cCPacketClassificationRule.u8IPDestinationAddress[uiLoopIndex]);
 
-		for(uiLoopIndex=0; uiLoopIndex < 32; uiLoopIndex++)
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPMaskedSourceAddress[32] : 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddress[uiLoopIndex]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolSourcePortRangeLength: 0x%02X ",
+				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPDestinationAddressLength	: 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8IPDestinationAddressLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolSourcePortRange[4]: 0x %02X %02X %02X %02X ",
+				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[0],
+				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[1],
+				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[2],
+				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[3]);
 
-		for(uiLoopIndex=0; uiLoopIndex < 32; uiLoopIndex++)
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPDestinationAddress[32] : 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8IPDestinationAddress[uiLoopIndex]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolDestPortRangeLength: 0x%02X ",
+				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ProtocolSourcePortRangeLength	: 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolDestPortRange[4]: 0x %02X %02X %02X %02X ",
+				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[0],
+				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[1],
+				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[2],
+				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[3]);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ProtocolSourcePortRange[4] : 0x %02X %02X %02X %02X ",
-			psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[0],
-			psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[1],
-			psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[2],
-			psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[3]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetDestMacAddressLength: 0x%02X ",
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ProtocolDestPortRangeLength : 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetDestMacAddress[6]: 0x %02X %02X %02X %02X %02X %02X",
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[0],
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[1],
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[2],
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[3],
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[4],
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[5]);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ProtocolDestPortRange[4] : 0x %02X %02X %02X %02X ",
-			psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[0],
-			psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[1],
-			psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[2],
-			psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[3]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetSourceMACAddressLength: 0x%02X ",
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8EthernetDestMacAddressLength : 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetSourceMACAddress[6]: 0x %02X %02X %02X %02X %02X %02X",
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[0],
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[1],
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[2],
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[3],
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[4],
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[5]);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8EthernetDestMacAddress[6] : 0x %02X %02X %02X %02X %02X %02X",
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[0],
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[1],
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[2],
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[3],
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[4],
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[5]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthertypeLength: 0x%02X ", psfCSType->cCPacketClassificationRule.u8EthertypeLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Ethertype[3]: 0x%02X %02X %02X",
+				psfCSType->cCPacketClassificationRule.u8Ethertype[0],
+				psfCSType->cCPacketClassificationRule.u8Ethertype[1],
+				psfCSType->cCPacketClassificationRule.u8Ethertype[2]);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8EthernetSourceMACAddressLength : 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
-
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8EthernetSourceMACAddress[6] : 0x %02X %02X %02X %02X %02X %02X",
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[0],
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[1],
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[2],
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[3],
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[4],
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[5]);
-
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8EthertypeLength  	: 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8EthertypeLength);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8Ethertype[3]		: 0x%02X %02X %02X",
-			psfCSType->cCPacketClassificationRule.u8Ethertype[0],
-			psfCSType->cCPacketClassificationRule.u8Ethertype[1],
-			psfCSType->cCPacketClassificationRule.u8Ethertype[2]);
-
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16UserPriority 	: 0x%X ",
-			psfCSType->cCPacketClassificationRule.u16UserPriority);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16VLANID			: 0x%X ",
-			psfCSType->cCPacketClassificationRule.u16VLANID);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8AssociatedPHSI	: 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8AssociatedPHSI);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16PacketClassificationRuleIndex	: 0x%X ",
-			psfCSType->cCPacketClassificationRule.u16PacketClassificationRuleIndex);
-
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8VendorSpecificClassifierParamLength	: 0x%02X",
-			psfCSType->cCPacketClassificationRule.u8VendorSpecificClassifierParamLength);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8VendorSpecificClassifierParam[1] 	: 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8VendorSpecificClassifierParam[0]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16UserPriority: 0x%X ", psfCSType->cCPacketClassificationRule.u16UserPriority);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16VLANID: 0x%X ", psfCSType->cCPacketClassificationRule.u16VLANID);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8AssociatedPHSI: 0x%02X ", psfCSType->cCPacketClassificationRule.u8AssociatedPHSI);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16PacketClassificationRuleIndex: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u16PacketClassificationRuleIndex);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificClassifierParamLength: 0x%02X",
+				psfCSType->cCPacketClassificationRule.u8VendorSpecificClassifierParamLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificClassifierParam[1]: 0x%02X ",
+				psfCSType->cCPacketClassificationRule.u8VendorSpecificClassifierParam[0]);
 #ifdef VERSION_D5
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPv6FlowLableLength				: 0x%X ",
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLableLength);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPv6FlowLable[6]	: 0x %02X %02X %02X %02X %02X %02X ",
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[0],
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[1],
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[2],
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[3],
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[4],
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[5]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLableLength: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLableLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLable[6]: 0x %02X %02X %02X %02X %02X %02X ",
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[0],
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[1],
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[2],
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[3],
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[4],
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[5]);
 #endif
 	}
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "bValid		: 0x%X",pstAddIndication->sfAdmittedSet.bValid);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "bValid: 0x%X", pstAddIndication->sfAdmittedSet.bValid);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " ActiveSet--->");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32SFID: 0x%X", pstAddIndication->sfActiveSet.u32SFID);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16CID: 0x%X", pstAddIndication->sfActiveSet.u16CID);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassNameLength: 0x%X", pstAddIndication->sfActiveSet.u8ServiceClassNameLength);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassName: 0x %02X %02X %02X %02X %02X %02X",
+			pstAddIndication->sfActiveSet.u8ServiceClassName[0],
+			pstAddIndication->sfActiveSet.u8ServiceClassName[1],
+			pstAddIndication->sfActiveSet.u8ServiceClassName[2],
+			pstAddIndication->sfActiveSet.u8ServiceClassName[3],
+			pstAddIndication->sfActiveSet.u8ServiceClassName[4],
+			pstAddIndication->sfActiveSet.u8ServiceClassName[5]);
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " ActiveSet--->");
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32SFID		: 0x%X",pstAddIndication->sfActiveSet.u32SFID);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16CID		: 0x%X",pstAddIndication->sfActiveSet.u16CID);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ServiceClassNameLength	: 0x%X",
-		pstAddIndication->sfActiveSet.u8ServiceClassNameLength);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ServiceClassName		: 0x %02X %02X %02X %02X %02X %02X",
-		pstAddIndication->sfActiveSet.u8ServiceClassName[0],
-		pstAddIndication->sfActiveSet.u8ServiceClassName[1],
-		pstAddIndication->sfActiveSet.u8ServiceClassName[2],
-		pstAddIndication->sfActiveSet.u8ServiceClassName[3],
-		pstAddIndication->sfActiveSet.u8ServiceClassName[4],
-		pstAddIndication->sfActiveSet.u8ServiceClassName[5]);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8MBSService				: 0x%02X",
-		pstAddIndication->sfActiveSet.u8MBSService);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8QosParamSet				: 0x%02X",
-		pstAddIndication->sfActiveSet.u8QosParamSet);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8TrafficPriority			: 0x%02X",
-		pstAddIndication->sfActiveSet.u8TrafficPriority);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32MaxTrafficBurst			: 0x%X",
-		pstAddIndication->sfActiveSet.u32MaxTrafficBurst);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32MinReservedTrafficRate	: 0x%X",
-		pstAddIndication->sfActiveSet.u32MinReservedTrafficRate);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8VendorSpecificQoSParamLength	: 0x%02X",
-		pstAddIndication->sfActiveSet.u8VendorSpecificQoSParamLength);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8VendorSpecificQoSParam		: 0x%02X",
-		pstAddIndication->sfActiveSet.u8VendorSpecificQoSParam[0]);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ServiceFlowSchedulingType		: 0x%02X",
-		pstAddIndication->sfActiveSet.u8ServiceFlowSchedulingType);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32ToleratedJitter				: 0x%X",
-		pstAddIndication->sfActiveSet.u32ToleratedJitter);
-    BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32MaximumLatency				: 0x%X",
-		pstAddIndication->sfActiveSet.u32MaximumLatency);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8FixedLengthVSVariableLengthSDUIndicator: 0x%02X",
-	   pstAddIndication->sfActiveSet.u8FixedLengthVSVariableLengthSDUIndicator);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8SDUSize				: 0x%X",
-		pstAddIndication->sfActiveSet.u8SDUSize);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u16TargetSAID			: 0x%X",
-		pstAddIndication->sfActiveSet.u16TargetSAID);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8ARQEnable			: 0x%X",
-		pstAddIndication->sfActiveSet.u8ARQEnable);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u16ARQWindowSize		: 0x%X",
-		pstAddIndication->sfActiveSet.u16ARQWindowSize);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u16ARQRetryTxTimeOut	: 0x%X",
-		pstAddIndication->sfActiveSet.u16ARQRetryTxTimeOut);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u16ARQRetryRxTimeOut	: 0x%X",
-		pstAddIndication->sfActiveSet.u16ARQRetryRxTimeOut);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u16ARQBlockLifeTime	: 0x%X",
-		pstAddIndication->sfActiveSet.u16ARQBlockLifeTime);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u16ARQSyncLossTimeOut	: 0x%X",
-		pstAddIndication->sfActiveSet.u16ARQSyncLossTimeOut);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8ARQDeliverInOrder	: 0x%X",
-		pstAddIndication->sfActiveSet.u8ARQDeliverInOrder);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u16ARQRxPurgeTimeOut	: 0x%X",
-		pstAddIndication->sfActiveSet.u16ARQRxPurgeTimeOut);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u16ARQBlockSize		: 0x%X",
-		pstAddIndication->sfActiveSet.u16ARQBlockSize);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8CSSpecification		: 0x%X",
-		pstAddIndication->sfActiveSet.u8CSSpecification);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8TypeOfDataDeliveryService	: 0x%X",
-		pstAddIndication->sfActiveSet.u8TypeOfDataDeliveryService);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u16SDUInterArrivalTime	: 0x%X",
-		pstAddIndication->sfActiveSet.u16SDUInterArrivalTime);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u16TimeBase			: 0x%X",
-		pstAddIndication->sfActiveSet.u16TimeBase);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8PagingPreference		: 0x%X",
-		pstAddIndication->sfActiveSet.u8PagingPreference);
-
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8TrafficIndicationPreference	: 0x%X",
-		pstAddIndication->sfActiveSet.u8TrafficIndicationPreference);
-
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " Total Classifiers Received		: 0x%X",pstAddIndication->sfActiveSet.u8TotalClassifiers);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8MBSService: 0x%02X", pstAddIndication->sfActiveSet.u8MBSService);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8QosParamSet: 0x%02X", pstAddIndication->sfActiveSet.u8QosParamSet);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficPriority: 0x%02X", pstAddIndication->sfActiveSet.u8TrafficPriority);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaxTrafficBurst: 0x%X", pstAddIndication->sfActiveSet.u32MaxTrafficBurst);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MinReservedTrafficRate: 0x%X",
+			pstAddIndication->sfActiveSet.u32MinReservedTrafficRate);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParamLength: 0x%02X",
+			pstAddIndication->sfActiveSet.u8VendorSpecificQoSParamLength);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParam: 0x%02X",
+			pstAddIndication->sfActiveSet.u8VendorSpecificQoSParam[0]);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceFlowSchedulingType: 0x%02X",
+			pstAddIndication->sfActiveSet.u8ServiceFlowSchedulingType);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32ToleratedJitter: 0x%X", pstAddIndication->sfActiveSet.u32ToleratedJitter);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaximumLatency: 0x%X",	pstAddIndication->sfActiveSet.u32MaximumLatency);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8FixedLengthVSVariableLengthSDUIndicator: 0x%02X",
+			pstAddIndication->sfActiveSet.u8FixedLengthVSVariableLengthSDUIndicator);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8SDUSize: 0x%X",	pstAddIndication->sfActiveSet.u8SDUSize);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16TargetSAID: 0x%X", pstAddIndication->sfActiveSet.u16TargetSAID);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8ARQEnable: 0x%X", pstAddIndication->sfActiveSet.u8ARQEnable);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16ARQWindowSize: 0x%X", pstAddIndication->sfActiveSet.u16ARQWindowSize);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16ARQRetryTxTimeOut: 0x%X", pstAddIndication->sfActiveSet.u16ARQRetryTxTimeOut);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16ARQRetryRxTimeOut: 0x%X", pstAddIndication->sfActiveSet.u16ARQRetryRxTimeOut);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16ARQBlockLifeTime: 0x%X", pstAddIndication->sfActiveSet.u16ARQBlockLifeTime);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16ARQSyncLossTimeOut: 0x%X", pstAddIndication->sfActiveSet.u16ARQSyncLossTimeOut);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8ARQDeliverInOrder: 0x%X", pstAddIndication->sfActiveSet.u8ARQDeliverInOrder);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16ARQRxPurgeTimeOut: 0x%X", pstAddIndication->sfActiveSet.u16ARQRxPurgeTimeOut);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16ARQBlockSize: 0x%X", pstAddIndication->sfActiveSet.u16ARQBlockSize);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8CSSpecification: 0x%X", pstAddIndication->sfActiveSet.u8CSSpecification);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8TypeOfDataDeliveryService: 0x%X",
+			pstAddIndication->sfActiveSet.u8TypeOfDataDeliveryService);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16SDUInterArrivalTime: 0x%X", pstAddIndication->sfActiveSet.u16SDUInterArrivalTime);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16TimeBase: 0x%X", pstAddIndication->sfActiveSet.u16TimeBase);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8PagingPreference: 0x%X", pstAddIndication->sfActiveSet.u8PagingPreference);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8TrafficIndicationPreference: 0x%X",
+			pstAddIndication->sfActiveSet.u8TrafficIndicationPreference);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " Total Classifiers Received: 0x%X", pstAddIndication->sfActiveSet.u8TotalClassifiers);
 
 	nCurClassifierCnt = pstAddIndication->sfActiveSet.u8TotalClassifiers;
-
-	if(nCurClassifierCnt > MAX_CLASSIFIERS_IN_SF)
-	{
+	if (nCurClassifierCnt > MAX_CLASSIFIERS_IN_SF)
 		nCurClassifierCnt = MAX_CLASSIFIERS_IN_SF;
-	}
 
-	for(nIndex = 0 ; nIndex < nCurClassifierCnt ; nIndex++)
-	{
-
+	for (nIndex = 0; nIndex < nCurClassifierCnt; nIndex++)	{
 		stConvergenceSLTypes *psfCSType = NULL;
+
 		psfCSType =  &pstAddIndication->sfActiveSet.cConvergenceSLTypes[nIndex];
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " CCPacketClassificationRuleSI====>");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8ClassifierRulePriority: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8IPTypeOfServiceLength: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8IPTypeOfService[3]: 0x%X ,0x%X ,0x%X ",
+				psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0],
+				psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1],
+				psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]);
 
+		for (uiLoopIndex = 0; uiLoopIndex < 1; uiLoopIndex++)
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8Protocol: 0x%X ", psfCSType->cCPacketClassificationRule.u8Protocol);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " CCPacketClassificationRuleSI====>");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPMaskedSourceAddressLength: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddressLength);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8ClassifierRulePriority		:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8IPTypeOfServiceLength		:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength);
+		for (uiLoopIndex = 0; uiLoopIndex < 32; uiLoopIndex++)
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPMaskedSourceAddress[32]: 0x%X ",
+					psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddress[uiLoopIndex]);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8IPTypeOfService[3]			:0x%X ,0x%X ,0x%X ",
-			psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0],
-			psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1],
-			psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]);
-		for(uiLoopIndex=0; uiLoopIndex < 1; uiLoopIndex++)
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8Protocol	: 0x%X ",
-			psfCSType->cCPacketClassificationRule.u8Protocol);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPDestinationAddressLength: 0x%02X ",
+				psfCSType->cCPacketClassificationRule.u8IPDestinationAddressLength);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPMaskedSourceAddressLength	:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddressLength);
+		for (uiLoopIndex = 0; uiLoopIndex < 32; uiLoopIndex++)
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8IPDestinationAddress[32]:0x%X ",
+					psfCSType->cCPacketClassificationRule.u8IPDestinationAddress[uiLoopIndex]);
 
-		for(uiLoopIndex=0; uiLoopIndex < 32; uiLoopIndex++)
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPMaskedSourceAddress[32]:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddress[uiLoopIndex]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8ProtocolSourcePortRangeLength: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8IPDestinationAddressLength : 0x%02X ",
-			psfCSType->cCPacketClassificationRule.u8IPDestinationAddressLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8ProtocolSourcePortRange[4]: 0x%X ,0x%X ,0x%X ,0x%X ",
+				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[0],
+				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[1],
+				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[2],
+				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[3]);
 
-		for(uiLoopIndex=0;uiLoopIndex<32;uiLoopIndex++)
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8IPDestinationAddress[32]:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8IPDestinationAddress[uiLoopIndex]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8ProtocolDestPortRangeLength: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8ProtocolDestPortRange[4]: 0x%X ,0x%X ,0x%X ,0x%X ",
+				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[0],
+				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[1],
+				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[2],
+				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[3]);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8ProtocolSourcePortRangeLength:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8EthernetDestMacAddressLength: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8EthernetDestMacAddress[6]: 0x%X ,0x%X ,0x%X ,0x%X ,0x%X ,0x%X",
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[0],
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[1],
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[2],
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[3],
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[4],
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[5]);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8ProtocolSourcePortRange[4]:0x%X ,0x%X ,0x%X ,0x%X ",
-			psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[0],
-			psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[1],
-			psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[2],
-			psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[3]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8EthernetSourceMACAddressLength: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetSourceMACAddress[6]: 0x%X ,0x%X ,0x%X ,0x%X ,0x%X ,0x%X",
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[0],
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[1],
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[2],
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[3],
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[4],
+				psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[5]);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8ProtocolDestPortRangeLength:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8EthertypeLength: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8EthertypeLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8Ethertype[3]: 0x%X ,0x%X ,0x%X ",
+				psfCSType->cCPacketClassificationRule.u8Ethertype[0],
+				psfCSType->cCPacketClassificationRule.u8Ethertype[1],
+				psfCSType->cCPacketClassificationRule.u8Ethertype[2]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16UserPriority: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u16UserPriority);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16VLANID: 0x%X ", psfCSType->cCPacketClassificationRule.u16VLANID);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8AssociatedPHSI: 0x%X ", psfCSType->cCPacketClassificationRule.u8AssociatedPHSI);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16PacketClassificationRuleIndex:0x%X ",
+				psfCSType->cCPacketClassificationRule.u16PacketClassificationRuleIndex);
 
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8ProtocolDestPortRange[4]:0x%X ,0x%X ,0x%X ,0x%X ",
-			psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[0],
-			psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[1],
-			psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[2],
-			psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[3]);
-
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8EthernetDestMacAddressLength:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
-
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8EthernetDestMacAddress[6]:0x%X ,0x%X ,0x%X ,0x%X ,0x%X ,0x%X",
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[0],
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[1],
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[2],
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[3],
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[4],
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddress[5]);
-
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8EthernetSourceMACAddressLength:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
-
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8EthernetSourceMACAddress[6]:0x%X ,0x%X ,0x%X ,0x%X ,0x%X ,0x%X",
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[0],
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[1],
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[2],
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[3],
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[4],
-			psfCSType->cCPacketClassificationRule.u8EthernetSourceMACAddress[5]);
-
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8EthertypeLength              :0x%X ",
-			psfCSType->cCPacketClassificationRule.u8EthertypeLength);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8Ethertype[3]                 :0x%X ,0x%X ,0x%X ",
-			psfCSType->cCPacketClassificationRule.u8Ethertype[0],
-			psfCSType->cCPacketClassificationRule.u8Ethertype[1],
-			psfCSType->cCPacketClassificationRule.u8Ethertype[2]);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u16UserPriority                :0x%X ",
-			psfCSType->cCPacketClassificationRule.u16UserPriority);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u16VLANID                      :0x%X ",
-			psfCSType->cCPacketClassificationRule.u16VLANID);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8AssociatedPHSI               :0x%X ",
-			psfCSType->cCPacketClassificationRule.u8AssociatedPHSI);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u16PacketClassificationRuleIndex:0x%X ",
-			psfCSType->cCPacketClassificationRule.u16PacketClassificationRuleIndex);
-
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8VendorSpecificClassifierParamLength:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8VendorSpecificClassifierParamLength);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8VendorSpecificClassifierParam[1]:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8VendorSpecificClassifierParam[0]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8VendorSpecificClassifierParamLength:0x%X ",
+				psfCSType->cCPacketClassificationRule.u8VendorSpecificClassifierParamLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8VendorSpecificClassifierParam[1]:0x%X ",
+				psfCSType->cCPacketClassificationRule.u8VendorSpecificClassifierParam[0]);
 #ifdef VERSION_D5
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8IPv6FlowLableLength				:0x%X ",
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLableLength);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8IPv6FlowLable[6]	    :0x%X ,0x%X ,0x%X ,0x%X ,0x%X ,0x%X ",
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[0],
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[1],
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[2],
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[3],
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[4],
-			psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[5]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8IPv6FlowLableLength: 0x%X ",
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLableLength);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8IPv6FlowLable[6]: 0x%X ,0x%X ,0x%X ,0x%X ,0x%X ,0x%X ",
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[0],
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[1],
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[2],
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[3],
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[4],
+				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[5]);
 #endif
 	}
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " bValid			: 0x%X",pstAddIndication->sfActiveSet.bValid);
-
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " bValid: 0x%X", pstAddIndication->sfActiveSet.bValid);
 }
 
-static inline ULONG RestoreSFParam(PMINI_ADAPTER Adapter, ULONG ulAddrSFParamSet,PUCHAR pucDestBuffer)
+static inline ULONG RestoreSFParam(PMINI_ADAPTER Adapter, ULONG ulAddrSFParamSet, PUCHAR pucDestBuffer)
 {
 	UINT  nBytesToRead = sizeof(stServiceFlowParamSI);
 
-	if(ulAddrSFParamSet == 0 || NULL == pucDestBuffer)
-	{
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "Got Param address as 0!!");
+	if (ulAddrSFParamSet == 0 || NULL == pucDestBuffer) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Got Param address as 0!!");
 		return 0;
 	}
 	ulAddrSFParamSet = ntohl(ulAddrSFParamSet);
 
-	//Read out the SF Param Set At the indicated Location
-	if(rdm(Adapter, ulAddrSFParamSet, (PUCHAR)pucDestBuffer, nBytesToRead) < 0)
+	/* Read out the SF Param Set At the indicated Location */
+	if (rdm(Adapter, ulAddrSFParamSet, (PUCHAR)pucDestBuffer, nBytesToRead) < 0)
 		return STATUS_FAILURE;
 
 	return 1;
 }
 
-
-static ULONG StoreSFParam(PMINI_ADAPTER Adapter,PUCHAR pucSrcBuffer,ULONG  ulAddrSFParamSet)
+static ULONG StoreSFParam(PMINI_ADAPTER Adapter, PUCHAR pucSrcBuffer, ULONG ulAddrSFParamSet)
 {
-    UINT	nBytesToWrite = sizeof(stServiceFlowParamSI);
+	UINT nBytesToWrite = sizeof(stServiceFlowParamSI);
 	int ret = 0;
 
-	if(ulAddrSFParamSet == 0 || NULL == pucSrcBuffer)
-	{
+	if (ulAddrSFParamSet == 0 || NULL == pucSrcBuffer)
 		return 0;
-	}
 
 	ret = wrm(Adapter, ulAddrSFParamSet, (u8 *)pucSrcBuffer, nBytesToWrite);
 	if (ret < 0) {
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "%s:%d WRM failed",__FUNCTION__, __LINE__);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "%s:%d WRM failed", __func__, __LINE__);
 		return ret;
 	}
 	return 1;
 }
 
-ULONG StoreCmControlResponseMessage(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT *puBufferLength)
+ULONG StoreCmControlResponseMessage(PMINI_ADAPTER Adapter, PVOID pvBuffer, UINT *puBufferLength)
 {
 	stLocalSFAddIndicationAlt *pstAddIndicationAlt = NULL;
-	stLocalSFAddIndication *  pstAddIndication = NULL;
+	stLocalSFAddIndication *pstAddIndication = NULL;
 	stLocalSFDeleteRequest *pstDeletionRequest;
 	UINT uiSearchRuleIndex;
 	ULONG ulSFID;
@@ -1671,52 +1369,51 @@
 	pstAddIndicationAlt = (stLocalSFAddIndicationAlt *)(pvBuffer);
 
 	/*
-	*	In case of DSD Req By MS, we should immediately delete this SF so that
-	*	we can stop the further classifying the pkt for this SF.
-	*/
-	if(pstAddIndicationAlt->u8Type == DSD_REQ)
-	{
+	 * In case of DSD Req By MS, we should immediately delete this SF so that
+	 * we can stop the further classifying the pkt for this SF.
+	 */
+	if (pstAddIndicationAlt->u8Type == DSD_REQ) {
 		pstDeletionRequest = (stLocalSFDeleteRequest *)pvBuffer;
 
 		ulSFID = ntohl(pstDeletionRequest->u32SFID);
-		uiSearchRuleIndex=SearchSfid(Adapter,ulSFID);
+		uiSearchRuleIndex = SearchSfid(Adapter, ulSFID);
 
-		if(uiSearchRuleIndex < NO_OF_QUEUES)
-		{
-			deleteSFBySfid(Adapter,uiSearchRuleIndex);
+		if (uiSearchRuleIndex < NO_OF_QUEUES) {
+			deleteSFBySfid(Adapter, uiSearchRuleIndex);
 			Adapter->u32TotalDSD++;
 		}
 		return 1;
 	}
 
-
-	if(	(pstAddIndicationAlt->u8Type == DSD_RSP) ||
-		(pstAddIndicationAlt->u8Type == DSD_ACK))
-	{
-		//No Special handling send the message as it is
+	if ((pstAddIndicationAlt->u8Type == DSD_RSP) ||
+		(pstAddIndicationAlt->u8Type == DSD_ACK)) {
+		/* No Special handling send the message as it is */
 		return 1;
 	}
-	// For DSA_REQ, only up to "psfAuthorizedSet" parameter should be accessed by driver!
+	/* For DSA_REQ, only up to "psfAuthorizedSet" parameter should be accessed by driver! */
 
-	pstAddIndication=kmalloc(sizeof(*pstAddIndication), GFP_KERNEL);
-	if(NULL==pstAddIndication)
+	pstAddIndication = kmalloc(sizeof(*pstAddIndication), GFP_KERNEL);
+	if (pstAddIndication == NULL)
 		return 0;
 
 	/* AUTHORIZED SET */
 	pstAddIndication->psfAuthorizedSet = (stServiceFlowParamSI *)
 			GetNextTargetBufferLocation(Adapter, pstAddIndicationAlt->u16TID);
-	if(!pstAddIndication->psfAuthorizedSet)
+	if (!pstAddIndication->psfAuthorizedSet) {
+		kfree(pstAddIndication);
 		return 0;
+	}
 
-	if(StoreSFParam(Adapter,(PUCHAR)&pstAddIndicationAlt->sfAuthorizedSet,
-				(ULONG)pstAddIndication->psfAuthorizedSet)!= 1)
+	if (StoreSFParam(Adapter, (PUCHAR)&pstAddIndicationAlt->sfAuthorizedSet,
+				(ULONG)pstAddIndication->psfAuthorizedSet) != 1) {
+		kfree(pstAddIndication);
 		return 0;
+	}
 
 	/* this can't possibly be right */
 	pstAddIndication->psfAuthorizedSet = (stServiceFlowParamSI *)ntohl((ULONG)pstAddIndication->psfAuthorizedSet);
 
-	if(pstAddIndicationAlt->u8Type == DSA_REQ)
-	{
+	if (pstAddIndicationAlt->u8Type == DSA_REQ) {
 		stLocalSFAddRequest AddRequest;
 
 		AddRequest.u8Type = pstAddIndicationAlt->u8Type;
@@ -1724,18 +1421,18 @@
 		AddRequest.u16TID = pstAddIndicationAlt->u16TID;
 		AddRequest.u16CID = pstAddIndicationAlt->u16CID;
 		AddRequest.u16VCID = pstAddIndicationAlt->u16VCID;
-		AddRequest.psfParameterSet =pstAddIndication->psfAuthorizedSet ;
+		AddRequest.psfParameterSet = pstAddIndication->psfAuthorizedSet;
 		(*puBufferLength) = sizeof(stLocalSFAddRequest);
-		memcpy(pvBuffer,&AddRequest,sizeof(stLocalSFAddRequest));
+		memcpy(pvBuffer, &AddRequest, sizeof(stLocalSFAddRequest));
+		kfree(pstAddIndication);
 		return 1;
 	}
 
-	// Since it's not DSA_REQ, we can access all field in pstAddIndicationAlt
-
-	//We need to extract the structure from the buffer and pack it differently
+	/* Since it's not DSA_REQ, we can access all field in pstAddIndicationAlt */
+	/* We need to extract the structure from the buffer and pack it differently */
 
 	pstAddIndication->u8Type = pstAddIndicationAlt->u8Type;
-	pstAddIndication->eConnectionDir= pstAddIndicationAlt->u8Direction ;
+	pstAddIndication->eConnectionDir = pstAddIndicationAlt->u8Direction;
 	pstAddIndication->u16TID = pstAddIndicationAlt->u16TID;
 	pstAddIndication->u16CID = pstAddIndicationAlt->u16CID;
 	pstAddIndication->u16VCID = pstAddIndicationAlt->u16VCID;
@@ -1744,21 +1441,28 @@
 	/* ADMITTED SET */
 	pstAddIndication->psfAdmittedSet = (stServiceFlowParamSI *)
 		GetNextTargetBufferLocation(Adapter, pstAddIndicationAlt->u16TID);
-	if(!pstAddIndication->psfAdmittedSet)
+	if (!pstAddIndication->psfAdmittedSet) {
+		kfree(pstAddIndication);
 		return 0;
-	if(StoreSFParam(Adapter,(PUCHAR)&pstAddIndicationAlt->sfAdmittedSet,(ULONG)pstAddIndication->psfAdmittedSet) != 1)
+	}
+	if (StoreSFParam(Adapter, (PUCHAR)&pstAddIndicationAlt->sfAdmittedSet, (ULONG)pstAddIndication->psfAdmittedSet) != 1) {
+		kfree(pstAddIndication);
 		return 0;
+	}
 
 	pstAddIndication->psfAdmittedSet = (stServiceFlowParamSI *)ntohl((ULONG)pstAddIndication->psfAdmittedSet);
 
-
 	/* ACTIVE SET */
 	pstAddIndication->psfActiveSet = (stServiceFlowParamSI *)
 		GetNextTargetBufferLocation(Adapter, pstAddIndicationAlt->u16TID);
-	if(!pstAddIndication->psfActiveSet)
+	if (!pstAddIndication->psfActiveSet) {
+		kfree(pstAddIndication);
 		return 0;
-	if(StoreSFParam(Adapter,(PUCHAR)&pstAddIndicationAlt->sfActiveSet,(ULONG)pstAddIndication->psfActiveSet) != 1)
+	}
+	if (StoreSFParam(Adapter, (PUCHAR)&pstAddIndicationAlt->sfActiveSet, (ULONG)pstAddIndication->psfActiveSet) != 1) {
+		kfree(pstAddIndication);
 		return 0;
+	}
 
 	pstAddIndication->psfActiveSet = (stServiceFlowParamSI *)ntohl((ULONG)pstAddIndication->psfActiveSet);
 
@@ -1768,47 +1472,41 @@
 	return 1;
 }
 
-
 static inline stLocalSFAddIndicationAlt
-*RestoreCmControlResponseMessage(register PMINI_ADAPTER Adapter,register PVOID pvBuffer)
+*RestoreCmControlResponseMessage(register PMINI_ADAPTER Adapter, register PVOID pvBuffer)
 {
-	ULONG ulStatus=0;
+	ULONG ulStatus = 0;
 	stLocalSFAddIndication *pstAddIndication = NULL;
 	stLocalSFAddIndicationAlt *pstAddIndicationDest = NULL;
-	pstAddIndication = (stLocalSFAddIndication *)(pvBuffer);
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "=====>" );
+	pstAddIndication = (stLocalSFAddIndication *)(pvBuffer);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "=====>");
 	if ((pstAddIndication->u8Type == DSD_REQ) ||
 		(pstAddIndication->u8Type == DSD_RSP) ||
 		(pstAddIndication->u8Type == DSD_ACK))
-	{
 		return (stLocalSFAddIndicationAlt *)pvBuffer;
-	}
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Inside RestoreCmControlResponseMessage ");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Inside RestoreCmControlResponseMessage ");
 	/*
-	//Need to Allocate memory to contain the SUPER Large structures
-	//Our driver can't create these structures on Stack :(
-	*/
-	pstAddIndicationDest=kmalloc(sizeof(stLocalSFAddIndicationAlt), GFP_KERNEL);
+	 * Need to Allocate memory to contain the SUPER Large structures
+	 * Our driver can't create these structures on Stack :(
+	 */
+	pstAddIndicationDest = kmalloc(sizeof(stLocalSFAddIndicationAlt), GFP_KERNEL);
 
-	if(pstAddIndicationDest)
-	{
-		memset(pstAddIndicationDest,0,sizeof(stLocalSFAddIndicationAlt));
-	}
-	else
-	{
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Failed to allocate memory for SF Add Indication Structure ");
+	if (pstAddIndicationDest) {
+		memset(pstAddIndicationDest, 0, sizeof(stLocalSFAddIndicationAlt));
+	} else {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Failed to allocate memory for SF Add Indication Structure ");
 		return NULL;
 	}
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "AddIndication-u8Type : 0x%X",pstAddIndication->u8Type);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "AddIndication-u8Direction : 0x%X",pstAddIndication->eConnectionDir);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "AddIndication-u8TID : 0x%X",ntohs(pstAddIndication->u16TID));
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "AddIndication-u8CID : 0x%X",ntohs(pstAddIndication->u16CID));
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "AddIndication-u16VCID : 0x%X",ntohs(pstAddIndication->u16VCID));
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "AddIndication-autorized set loc : %p",pstAddIndication->psfAuthorizedSet);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "AddIndication-admitted set loc : %p",pstAddIndication->psfAdmittedSet);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "AddIndication-Active set loc : %p",pstAddIndication->psfActiveSet);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "AddIndication-u8Type : 0x%X", pstAddIndication->u8Type);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "AddIndication-u8Direction : 0x%X", pstAddIndication->eConnectionDir);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "AddIndication-u8TID : 0x%X", ntohs(pstAddIndication->u16TID));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "AddIndication-u8CID : 0x%X", ntohs(pstAddIndication->u16CID));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "AddIndication-u16VCID : 0x%X", ntohs(pstAddIndication->u16VCID));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "AddIndication-autorized set loc : %p", pstAddIndication->psfAuthorizedSet);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "AddIndication-admitted set loc : %p", pstAddIndication->psfAdmittedSet);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "AddIndication-Active set loc : %p", pstAddIndication->psfActiveSet);
 
 	pstAddIndicationDest->u8Type = pstAddIndication->u8Type;
 	pstAddIndicationDest->u8Direction = pstAddIndication->eConnectionDir;
@@ -1817,42 +1515,39 @@
 	pstAddIndicationDest->u16VCID = pstAddIndication->u16VCID;
 	pstAddIndicationDest->u8CC = pstAddIndication->u8CC;
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "Restoring Active Set ");
-	ulStatus=RestoreSFParam(Adapter,(ULONG)pstAddIndication->psfActiveSet, (PUCHAR)&pstAddIndicationDest->sfActiveSet);
-	if(ulStatus != 1)
-	{
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "Restoring Active Set ");
+	ulStatus = RestoreSFParam(Adapter, (ULONG)pstAddIndication->psfActiveSet, (PUCHAR)&pstAddIndicationDest->sfActiveSet);
+	if (ulStatus != 1)
 		goto failed_restore_sf_param;
-	}
-	if(pstAddIndicationDest->sfActiveSet.u8TotalClassifiers > MAX_CLASSIFIERS_IN_SF)
+
+	if (pstAddIndicationDest->sfActiveSet.u8TotalClassifiers > MAX_CLASSIFIERS_IN_SF)
 		pstAddIndicationDest->sfActiveSet.u8TotalClassifiers = MAX_CLASSIFIERS_IN_SF;
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "Restoring Admitted Set ");
-	ulStatus=RestoreSFParam(Adapter,(ULONG)pstAddIndication->psfAdmittedSet,(PUCHAR)&pstAddIndicationDest->sfAdmittedSet);
-	if(ulStatus != 1)
-	{
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "Restoring Admitted Set ");
+	ulStatus = RestoreSFParam(Adapter, (ULONG)pstAddIndication->psfAdmittedSet, (PUCHAR)&pstAddIndicationDest->sfAdmittedSet);
+	if (ulStatus != 1)
 		goto failed_restore_sf_param;
-	}
-	if(pstAddIndicationDest->sfAdmittedSet.u8TotalClassifiers > MAX_CLASSIFIERS_IN_SF)
+
+	if (pstAddIndicationDest->sfAdmittedSet.u8TotalClassifiers > MAX_CLASSIFIERS_IN_SF)
 		pstAddIndicationDest->sfAdmittedSet.u8TotalClassifiers = MAX_CLASSIFIERS_IN_SF;
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "Restoring Authorized Set ");
-	ulStatus=RestoreSFParam(Adapter,(ULONG)pstAddIndication->psfAuthorizedSet,(PUCHAR)&pstAddIndicationDest->sfAuthorizedSet);
-	if(ulStatus != 1)
-	{
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "Restoring Authorized Set ");
+	ulStatus = RestoreSFParam(Adapter, (ULONG)pstAddIndication->psfAuthorizedSet, (PUCHAR)&pstAddIndicationDest->sfAuthorizedSet);
+	if (ulStatus != 1)
 		goto failed_restore_sf_param;
-	}
-	if(pstAddIndicationDest->sfAuthorizedSet.u8TotalClassifiers > MAX_CLASSIFIERS_IN_SF)
+
+	if (pstAddIndicationDest->sfAuthorizedSet.u8TotalClassifiers > MAX_CLASSIFIERS_IN_SF)
 		pstAddIndicationDest->sfAuthorizedSet.u8TotalClassifiers = MAX_CLASSIFIERS_IN_SF;
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Dumping the whole raw packet");
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "============================================================");
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, " pstAddIndicationDest->sfActiveSet size  %zx %p", sizeof(*pstAddIndicationDest), pstAddIndicationDest);
-	//BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, (unsigned char *)pstAddIndicationDest, sizeof(*pstAddIndicationDest));
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "============================================================");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Dumping the whole raw packet");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "============================================================");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, " pstAddIndicationDest->sfActiveSet size  %zx %p", sizeof(*pstAddIndicationDest), pstAddIndicationDest);
+	/* BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, (unsigned char *)pstAddIndicationDest, sizeof(*pstAddIndicationDest)); */
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "============================================================");
 	return pstAddIndicationDest;
 failed_restore_sf_param:
 	kfree(pstAddIndicationDest);
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "<=====" );
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "<=====");
 	return NULL;
 }
 
@@ -1860,7 +1555,7 @@
 {
 	ULONG ulTargetDsxBuffersBase = 0;
 	ULONG ulCntTargetBuffers;
-	ULONG ulIndex=0;
+	ULONG i;
 	int Status;
 
 	if (!Adapter) {
@@ -1868,411 +1563,354 @@
 		return 0;
 	}
 
-	if(Adapter->astTargetDsxBuffer[0].ulTargetDsxBuffer)
+	if (Adapter->astTargetDsxBuffer[0].ulTargetDsxBuffer)
 		return 1;
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Size of Each DSX Buffer(Also size of ServiceFlowParamSI): %zx ",sizeof(stServiceFlowParamSI));
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Reading DSX buffer From Target location %x ",DSX_MESSAGE_EXCHANGE_BUFFER);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Size of Each DSX Buffer(Also size of ServiceFlowParamSI): %zx ", sizeof(stServiceFlowParamSI));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Reading DSX buffer From Target location %x ", DSX_MESSAGE_EXCHANGE_BUFFER);
 
- 	Status = rdmalt(Adapter, DSX_MESSAGE_EXCHANGE_BUFFER,
-					(PUINT)&ulTargetDsxBuffersBase, sizeof(UINT));
-	if(Status < 0)
-	{
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "RDM failed!!");
+	Status = rdmalt(Adapter, DSX_MESSAGE_EXCHANGE_BUFFER, (PUINT)&ulTargetDsxBuffersBase, sizeof(UINT));
+	if (Status < 0) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "RDM failed!!");
 		return 0;
 	}
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Base Address Of DSX  Target Buffer : 0x%lx",ulTargetDsxBuffersBase);
-
-   	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "Tgt Buffer is Now %lx :",ulTargetDsxBuffersBase);
-
-	ulCntTargetBuffers = DSX_MESSAGE_EXCHANGE_BUFFER_SIZE/sizeof(stServiceFlowParamSI);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Base Address Of DSX  Target Buffer : 0x%lx", ulTargetDsxBuffersBase);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "Tgt Buffer is Now %lx :", ulTargetDsxBuffersBase);
+	ulCntTargetBuffers = DSX_MESSAGE_EXCHANGE_BUFFER_SIZE / sizeof(stServiceFlowParamSI);
 
 	Adapter->ulTotalTargetBuffersAvailable =
 		ulCntTargetBuffers > MAX_TARGET_DSX_BUFFERS ?
 		MAX_TARGET_DSX_BUFFERS : ulCntTargetBuffers;
 
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, " Total Target DSX Buffer setup %lx ",Adapter->ulTotalTargetBuffersAvailable);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, " Total Target DSX Buffer setup %lx ", Adapter->ulTotalTargetBuffersAvailable);
 
-	for(ulIndex=0; ulIndex < Adapter->ulTotalTargetBuffersAvailable ; ulIndex++)
-	{
-		Adapter->astTargetDsxBuffer[ulIndex].ulTargetDsxBuffer = ulTargetDsxBuffersBase;
-		Adapter->astTargetDsxBuffer[ulIndex].valid=1;
-		Adapter->astTargetDsxBuffer[ulIndex].tid=0;
-		ulTargetDsxBuffersBase+=sizeof(stServiceFlowParamSI);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "  Target DSX Buffer %lx setup at 0x%lx",
-			ulIndex, Adapter->astTargetDsxBuffer[ulIndex].ulTargetDsxBuffer);
+	for (i = 0; i < Adapter->ulTotalTargetBuffersAvailable; i++) {
+		Adapter->astTargetDsxBuffer[i].ulTargetDsxBuffer = ulTargetDsxBuffersBase;
+		Adapter->astTargetDsxBuffer[i].valid = 1;
+		Adapter->astTargetDsxBuffer[i].tid = 0;
+		ulTargetDsxBuffersBase += sizeof(stServiceFlowParamSI);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "  Target DSX Buffer %lx setup at 0x%lx",
+				i, Adapter->astTargetDsxBuffer[i].ulTargetDsxBuffer);
 	}
 	Adapter->ulCurrentTargetBuffer = 0;
 	Adapter->ulFreeTargetBufferCnt = Adapter->ulTotalTargetBuffersAvailable;
 	return 1;
 }
 
-static ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter,B_UINT16 tid)
+static ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter, B_UINT16 tid)
 {
-	ULONG  ulTargetDSXBufferAddress;
-	ULONG  ulTargetDsxBufferIndexToUse,ulMaxTry;
+	ULONG ulTargetDSXBufferAddress;
+	ULONG ulTargetDsxBufferIndexToUse, ulMaxTry;
 
-	if((Adapter->ulTotalTargetBuffersAvailable == 0)||
-			(Adapter->ulFreeTargetBufferCnt == 0))
-	{
-        ClearTargetDSXBuffer(Adapter,tid,FALSE);
+	if ((Adapter->ulTotalTargetBuffersAvailable == 0) || (Adapter->ulFreeTargetBufferCnt == 0)) {
+		ClearTargetDSXBuffer(Adapter, tid, FALSE);
 		return 0;
 	}
 
-    ulTargetDsxBufferIndexToUse = Adapter->ulCurrentTargetBuffer;
-    ulMaxTry = Adapter->ulTotalTargetBuffersAvailable;
-	while((ulMaxTry)&&(Adapter->astTargetDsxBuffer[ulTargetDsxBufferIndexToUse].valid != 1))
-	{
-		 ulTargetDsxBufferIndexToUse = (ulTargetDsxBufferIndexToUse+1)%
-					Adapter->ulTotalTargetBuffersAvailable;
-		 ulMaxTry--;
+	ulTargetDsxBufferIndexToUse = Adapter->ulCurrentTargetBuffer;
+	ulMaxTry = Adapter->ulTotalTargetBuffersAvailable;
+	while ((ulMaxTry) && (Adapter->astTargetDsxBuffer[ulTargetDsxBufferIndexToUse].valid != 1)) {
+		ulTargetDsxBufferIndexToUse = (ulTargetDsxBufferIndexToUse+1) % Adapter->ulTotalTargetBuffersAvailable;
+		ulMaxTry--;
 	}
 
-	if(ulMaxTry==0)
-	{
-		BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "\n GetNextTargetBufferLocation : Error No Free Target DSX Buffers FreeCnt : %lx ",Adapter->ulFreeTargetBufferCnt);
-		ClearTargetDSXBuffer(Adapter,tid,FALSE);
+	if (ulMaxTry == 0) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "\n GetNextTargetBufferLocation : Error No Free Target DSX Buffers FreeCnt : %lx ", Adapter->ulFreeTargetBufferCnt);
+		ClearTargetDSXBuffer(Adapter, tid, FALSE);
 		return 0;
 	}
 
-
-	ulTargetDSXBufferAddress =
-		Adapter->astTargetDsxBuffer[ulTargetDsxBufferIndexToUse].ulTargetDsxBuffer;
-	Adapter->astTargetDsxBuffer[ulTargetDsxBufferIndexToUse].valid=0;
-	Adapter->astTargetDsxBuffer[ulTargetDsxBufferIndexToUse].tid=tid;
+	ulTargetDSXBufferAddress = Adapter->astTargetDsxBuffer[ulTargetDsxBufferIndexToUse].ulTargetDsxBuffer;
+	Adapter->astTargetDsxBuffer[ulTargetDsxBufferIndexToUse].valid = 0;
+	Adapter->astTargetDsxBuffer[ulTargetDsxBufferIndexToUse].tid = tid;
 	Adapter->ulFreeTargetBufferCnt--;
-
-
-	ulTargetDsxBufferIndexToUse =
-		(ulTargetDsxBufferIndexToUse+1)%Adapter->ulTotalTargetBuffersAvailable;
+	ulTargetDsxBufferIndexToUse = (ulTargetDsxBufferIndexToUse+1)%Adapter->ulTotalTargetBuffersAvailable;
 	Adapter->ulCurrentTargetBuffer = ulTargetDsxBufferIndexToUse;
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "GetNextTargetBufferLocation :Returning address %lx tid %d\n",
-		ulTargetDSXBufferAddress,tid);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "GetNextTargetBufferLocation :Returning address %lx tid %d\n", ulTargetDSXBufferAddress, tid);
+
 	return ulTargetDSXBufferAddress;
 }
 
-
-INT AllocAdapterDsxBuffer(PMINI_ADAPTER Adapter)
+int AllocAdapterDsxBuffer(PMINI_ADAPTER Adapter)
 {
 	/*
-	//Need to Allocate memory to contain the SUPER Large structures
-	//Our driver can't create these structures on Stack
-	*/
-	Adapter->caDsxReqResp=kmalloc(sizeof(stLocalSFAddIndicationAlt)+LEADER_SIZE, GFP_KERNEL);
-	if(!Adapter->caDsxReqResp)
+	 * Need to Allocate memory to contain the SUPER Large structures
+	 * Our driver can't create these structures on Stack
+	 */
+	Adapter->caDsxReqResp = kmalloc(sizeof(stLocalSFAddIndicationAlt)+LEADER_SIZE, GFP_KERNEL);
+	if (!Adapter->caDsxReqResp)
 		return -ENOMEM;
+
 	return 0;
 }
 
-INT FreeAdapterDsxBuffer(PMINI_ADAPTER Adapter)
+int FreeAdapterDsxBuffer(PMINI_ADAPTER Adapter)
 {
 	kfree(Adapter->caDsxReqResp);
 	return 0;
-
 }
-/**
-@ingroup ctrl_pkt_functions
-This routinue would process the Control responses
-for the Connection Management.
-@return	  - Queue index for the free SFID else returns Invalid Index.
-*/
-BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,  /**<Pointer to the Adapter structure*/
-											PVOID pvBuffer /**Starting Address of the Buffer, that contains the AddIndication Data*/
-											)
+
+/*
+ * @ingroup ctrl_pkt_functions
+ * This routinue would process the Control responses
+ * for the Connection Management.
+ * @return - Queue index for the free SFID else returns Invalid Index.
+ */
+BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,  /* <Pointer to the Adapter structure */
+				PVOID pvBuffer /* Starting Address of the Buffer, that contains the AddIndication Data */)
 {
-	stServiceFlowParamSI			*psfLocalSet=NULL;
-	stLocalSFAddIndicationAlt 	 	*pstAddIndication = NULL;
-	stLocalSFChangeIndicationAlt 	*pstChangeIndication = NULL;
-	PLEADER							pLeader=NULL;
+	stServiceFlowParamSI *psfLocalSet = NULL;
+	stLocalSFAddIndicationAlt *pstAddIndication = NULL;
+	stLocalSFChangeIndicationAlt *pstChangeIndication = NULL;
+	PLEADER pLeader = NULL;
+
 	/*
-	//Otherwise the message contains a target address from where we need to
-	//read out the rest of the service flow param structure
-	*/
-	if((pstAddIndication = RestoreCmControlResponseMessage(Adapter,pvBuffer))
-			== NULL)
-	{
-		ClearTargetDSXBuffer(Adapter,((stLocalSFAddIndication *)pvBuffer)->u16TID, FALSE);
-		BCM_DEBUG_PRINT( Adapter,DBG_TYPE_PRINTK, 0, 0, "Error in restoring Service Flow param structure from DSx message");
+	 * Otherwise the message contains a target address from where we need to
+	 * read out the rest of the service flow param structure
+	 */
+	pstAddIndication = RestoreCmControlResponseMessage(Adapter, pvBuffer);
+	if (pstAddIndication == NULL) {
+		ClearTargetDSXBuffer(Adapter, ((stLocalSFAddIndication *)pvBuffer)->u16TID, FALSE);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Error in restoring Service Flow param structure from DSx message");
 		return FALSE;
 	}
 
 	DumpCmControlPacket(pstAddIndication);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "====>");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "====>");
 	pLeader = (PLEADER)Adapter->caDsxReqResp;
 
-	pLeader->Status =CM_CONTROL_NEWDSX_MULTICLASSIFIER_REQ;
+	pLeader->Status = CM_CONTROL_NEWDSX_MULTICLASSIFIER_REQ;
 	pLeader->Vcid = 0;
 
-	ClearTargetDSXBuffer(Adapter,pstAddIndication->u16TID,FALSE);
-    BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "### TID RECEIVED %d\n",pstAddIndication->u16TID);
-	switch(pstAddIndication->u8Type)
+	ClearTargetDSXBuffer(Adapter, pstAddIndication->u16TID, FALSE);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "### TID RECEIVED %d\n", pstAddIndication->u16TID);
+	switch (pstAddIndication->u8Type) {
+	case DSA_REQ:
 	{
-		case DSA_REQ:
-		{
-			pLeader->PLength = sizeof(stLocalSFAddIndicationAlt);
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Sending DSA Response....\n");
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "SENDING DSA RESPONSE TO MAC %d", pLeader->PLength );
-			*((stLocalSFAddIndicationAlt*)&(Adapter->caDsxReqResp[LEADER_SIZE]))
-						= *pstAddIndication;
-			((stLocalSFAddIndicationAlt*)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSA_RSP;
+		pLeader->PLength = sizeof(stLocalSFAddIndicationAlt);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Sending DSA Response....\n");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSA RESPONSE TO MAC %d", pLeader->PLength);
+		*((stLocalSFAddIndicationAlt *)&(Adapter->caDsxReqResp[LEADER_SIZE]))
+			= *pstAddIndication;
+		((stLocalSFAddIndicationAlt *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSA_RSP;
 
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  " VCID = %x", ntohs(pstAddIndication->u16VCID));
-			CopyBufferToControlPacket(Adapter,(PVOID)Adapter->caDsxReqResp);
-			kfree(pstAddIndication);
-		}
-		break;
-		case DSA_RSP:
-		{
-			pLeader->PLength = sizeof(stLocalSFAddIndicationAlt);
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSA ACK TO MAC %d",
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, " VCID = %x", ntohs(pstAddIndication->u16VCID));
+		CopyBufferToControlPacket(Adapter, (PVOID)Adapter->caDsxReqResp);
+		kfree(pstAddIndication);
+	}
+	break;
+	case DSA_RSP:
+	{
+		pLeader->PLength = sizeof(stLocalSFAddIndicationAlt);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSA ACK TO MAC %d",
 				pLeader->PLength);
-			*((stLocalSFAddIndicationAlt*)&(Adapter->caDsxReqResp[LEADER_SIZE]))
-						= *pstAddIndication;
-			((stLocalSFAddIndicationAlt*)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSA_ACK;
+		*((stLocalSFAddIndicationAlt *)&(Adapter->caDsxReqResp[LEADER_SIZE]))
+			= *pstAddIndication;
+		((stLocalSFAddIndicationAlt *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSA_ACK;
 
-		}//no break here..we should go down.
-		case DSA_ACK:
-		{
-			UINT uiSearchRuleIndex=0;
+	} /* no break here..we should go down. */
+	case DSA_ACK:
+	{
+		UINT uiSearchRuleIndex = 0;
 
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "VCID:0x%X",
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "VCID:0x%X",
 				ntohs(pstAddIndication->u16VCID));
-            uiSearchRuleIndex=SearchFreeSfid(Adapter);
-            BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"uiSearchRuleIndex:0x%X ",
+		uiSearchRuleIndex = SearchFreeSfid(Adapter);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "uiSearchRuleIndex:0x%X ",
 				uiSearchRuleIndex);
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Direction:0x%X ",
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Direction:0x%X ",
 				pstAddIndication->u8Direction);
-			if((uiSearchRuleIndex< NO_OF_QUEUES) )
-			{
-				Adapter->PackInfo[uiSearchRuleIndex].ucDirection =
-					pstAddIndication->u8Direction;
-                BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "bValid:0x%X ",
+		if ((uiSearchRuleIndex < NO_OF_QUEUES)) {
+			Adapter->PackInfo[uiSearchRuleIndex].ucDirection =
+				pstAddIndication->u8Direction;
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "bValid:0x%X ",
 					pstAddIndication->sfActiveSet.bValid);
-				if(pstAddIndication->sfActiveSet.bValid==TRUE)
-				{
-					Adapter->PackInfo[uiSearchRuleIndex].bActiveSet=TRUE;
-				}
-				if(pstAddIndication->sfAuthorizedSet.bValid==TRUE)
-				{
-					Adapter->PackInfo[uiSearchRuleIndex].bAuthorizedSet=TRUE;
-				}
-				if(pstAddIndication->sfAdmittedSet.bValid==TRUE)
-				{
-					Adapter->PackInfo[uiSearchRuleIndex].bAdmittedSet=TRUE;
-				}
-				if(FALSE == pstAddIndication->sfActiveSet.bValid)
-				{
-					Adapter->PackInfo[uiSearchRuleIndex].bActive = FALSE;
-					Adapter->PackInfo[uiSearchRuleIndex].bActivateRequestSent = FALSE;
-					if(pstAddIndication->sfAdmittedSet.bValid)
-					{
-						psfLocalSet = &pstAddIndication->sfAdmittedSet;
-					}
-					else if(pstAddIndication->sfAuthorizedSet.bValid)
-					{
-						psfLocalSet = &pstAddIndication->sfAuthorizedSet;
-					}
-				}
-				else
-				{
-					psfLocalSet = &pstAddIndication->sfActiveSet;
-					Adapter->PackInfo[uiSearchRuleIndex].bActive=TRUE;
-				}
+			if (pstAddIndication->sfActiveSet.bValid == TRUE)
+				Adapter->PackInfo[uiSearchRuleIndex].bActiveSet = TRUE;
 
-				if(!psfLocalSet)
-				{
-					BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "No set is valid\n");
-					Adapter->PackInfo[uiSearchRuleIndex].bActive=FALSE;
-                    Adapter->PackInfo[uiSearchRuleIndex].bValid=FALSE;
-					Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value=0;
-					kfree(pstAddIndication);
-				}
+			if (pstAddIndication->sfAuthorizedSet.bValid == TRUE)
+				Adapter->PackInfo[uiSearchRuleIndex].bAuthorizedSet = TRUE;
 
-				else if(psfLocalSet->bValid && (pstAddIndication->u8CC == 0))
-				{
-					BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "DSA ACK");
-					Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value =
-						ntohs(pstAddIndication->u16VCID);
-					Adapter->PackInfo[uiSearchRuleIndex].usCID =
-						ntohs(pstAddIndication->u16CID);
+			if (pstAddIndication->sfAdmittedSet.bValid == TRUE)
+				Adapter->PackInfo[uiSearchRuleIndex].bAdmittedSet = TRUE;
 
-					if(UPLINK_DIR == pstAddIndication->u8Direction)
-						atomic_set(&Adapter->PackInfo[uiSearchRuleIndex].uiPerSFTxResourceCount, DEFAULT_PERSFCOUNT);
-					CopyToAdapter(Adapter,psfLocalSet,uiSearchRuleIndex,
-								DSA_ACK, pstAddIndication);
-					// don't free pstAddIndication
+			if (pstAddIndication->sfActiveSet.bValid == FALSE) {
+				Adapter->PackInfo[uiSearchRuleIndex].bActive = FALSE;
+				Adapter->PackInfo[uiSearchRuleIndex].bActivateRequestSent = FALSE;
+				if (pstAddIndication->sfAdmittedSet.bValid)
+					psfLocalSet = &pstAddIndication->sfAdmittedSet;
+				else if (pstAddIndication->sfAuthorizedSet.bValid)
+					psfLocalSet = &pstAddIndication->sfAuthorizedSet;
+			} else {
+				psfLocalSet = &pstAddIndication->sfActiveSet;
+				Adapter->PackInfo[uiSearchRuleIndex].bActive = TRUE;
+			}
 
-					/* Inside CopyToAdapter, Sorting of all the SFs take place.
-					    Hence any access to the newly added SF through uiSearchRuleIndex is invalid.
-					    SHOULD BE STRICTLY AVOIDED.
-					*/
-//					*(PULONG)(((PUCHAR)pvBuffer)+1)=psfLocalSet->u32SFID;
-					memcpy((((PUCHAR)pvBuffer)+1), &psfLocalSet->u32SFID, 4);
+			if (!psfLocalSet) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "No set is valid\n");
+				Adapter->PackInfo[uiSearchRuleIndex].bActive = FALSE;
+				Adapter->PackInfo[uiSearchRuleIndex].bValid = FALSE;
+				Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value = 0;
+				kfree(pstAddIndication);
+			} else if (psfLocalSet->bValid && (pstAddIndication->u8CC == 0)) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "DSA ACK");
+				Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value = ntohs(pstAddIndication->u16VCID);
+				Adapter->PackInfo[uiSearchRuleIndex].usCID = ntohs(pstAddIndication->u16CID);
 
-					if(pstAddIndication->sfActiveSet.bValid == TRUE)
-					{
-						if(UPLINK_DIR == pstAddIndication->u8Direction)
-						{
-							if(!Adapter->LinkUpStatus)
-							{
-								netif_carrier_on(Adapter->dev);
-								netif_start_queue(Adapter->dev);
-								Adapter->LinkUpStatus = 1;
-								if (netif_msg_link(Adapter))
-									pr_info(PFX "%s: link up\n", Adapter->dev->name);
-								atomic_set(&Adapter->TxPktAvail, 1);
-								wake_up(&Adapter->tx_packet_wait_queue);
-								Adapter->liTimeSinceLastNetEntry = get_seconds();
-							}
+				if (UPLINK_DIR == pstAddIndication->u8Direction)
+					atomic_set(&Adapter->PackInfo[uiSearchRuleIndex].uiPerSFTxResourceCount, DEFAULT_PERSFCOUNT);
+
+				CopyToAdapter(Adapter, psfLocalSet, uiSearchRuleIndex, DSA_ACK, pstAddIndication);
+				/* don't free pstAddIndication */
+
+				/* Inside CopyToAdapter, Sorting of all the SFs take place.
+				 * Hence any access to the newly added SF through uiSearchRuleIndex is invalid.
+				 * SHOULD BE STRICTLY AVOIDED.
+				 */
+				/* *(PULONG)(((PUCHAR)pvBuffer)+1)=psfLocalSet->u32SFID; */
+				memcpy((((PUCHAR)pvBuffer)+1), &psfLocalSet->u32SFID, 4);
+
+				if (pstAddIndication->sfActiveSet.bValid == TRUE) {
+					if (UPLINK_DIR == pstAddIndication->u8Direction) {
+						if (!Adapter->LinkUpStatus) {
+							netif_carrier_on(Adapter->dev);
+							netif_start_queue(Adapter->dev);
+							Adapter->LinkUpStatus = 1;
+							if (netif_msg_link(Adapter))
+								pr_info(PFX "%s: link up\n", Adapter->dev->name);
+							atomic_set(&Adapter->TxPktAvail, 1);
+							wake_up(&Adapter->tx_packet_wait_queue);
+							Adapter->liTimeSinceLastNetEntry = get_seconds();
 						}
 					}
 				}
-
-				else
-				{
-					Adapter->PackInfo[uiSearchRuleIndex].bActive=FALSE;
-                    Adapter->PackInfo[uiSearchRuleIndex].bValid=FALSE;
-					Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value=0;
-					kfree(pstAddIndication);
-				}
-			}
-			else
-			{
-				BCM_DEBUG_PRINT( Adapter,DBG_TYPE_PRINTK, 0, 0, "DSA ACK did not get valid SFID");
+			} else {
+				Adapter->PackInfo[uiSearchRuleIndex].bActive = FALSE;
+				Adapter->PackInfo[uiSearchRuleIndex].bValid = FALSE;
+				Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value = 0;
 				kfree(pstAddIndication);
-				return FALSE;
 			}
-		}
-		break;
-		case DSC_REQ:
-		{
-			pLeader->PLength = sizeof(stLocalSFChangeIndicationAlt);
-			pstChangeIndication	= (stLocalSFChangeIndicationAlt*)pstAddIndication;
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSC RESPONSE TO MAC %d", pLeader->PLength);
-
-			*((stLocalSFChangeIndicationAlt*)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *pstChangeIndication;
-			((stLocalSFChangeIndicationAlt*)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSC_RSP;
-
-			CopyBufferToControlPacket(Adapter,(PVOID)Adapter->caDsxReqResp);
+		} else {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "DSA ACK did not get valid SFID");
 			kfree(pstAddIndication);
+			return FALSE;
 		}
-		break;
-		case DSC_RSP:
-		{
-			pLeader->PLength = sizeof(stLocalSFChangeIndicationAlt);
-			pstChangeIndication	= (stLocalSFChangeIndicationAlt*)pstAddIndication;
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSC ACK TO MAC %d", pLeader->PLength);
-			*((stLocalSFChangeIndicationAlt*)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *pstChangeIndication;
-			((stLocalSFChangeIndicationAlt*)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSC_ACK;
-		}
-		case DSC_ACK:
-		{
-			UINT uiSearchRuleIndex=0;
+	}
+	break;
+	case DSC_REQ:
+	{
+		pLeader->PLength = sizeof(stLocalSFChangeIndicationAlt);
+		pstChangeIndication = (stLocalSFChangeIndicationAlt *)pstAddIndication;
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSC RESPONSE TO MAC %d", pLeader->PLength);
 
-			pstChangeIndication = (stLocalSFChangeIndicationAlt *)pstAddIndication;
-			uiSearchRuleIndex=SearchSfid(Adapter,ntohl(pstChangeIndication->sfActiveSet.u32SFID));
-			if(uiSearchRuleIndex > NO_OF_QUEUES-1)
-			{
-				BCM_DEBUG_PRINT( Adapter,DBG_TYPE_PRINTK, 0, 0, "SF doesn't exist for which DSC_ACK is received");
+		*((stLocalSFChangeIndicationAlt *)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *pstChangeIndication;
+		((stLocalSFChangeIndicationAlt *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSC_RSP;
+
+		CopyBufferToControlPacket(Adapter, (PVOID)Adapter->caDsxReqResp);
+		kfree(pstAddIndication);
+	}
+	break;
+	case DSC_RSP:
+	{
+		pLeader->PLength = sizeof(stLocalSFChangeIndicationAlt);
+		pstChangeIndication = (stLocalSFChangeIndicationAlt *)pstAddIndication;
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSC ACK TO MAC %d", pLeader->PLength);
+		*((stLocalSFChangeIndicationAlt *)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *pstChangeIndication;
+		((stLocalSFChangeIndicationAlt *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSC_ACK;
+	}
+	case DSC_ACK:
+	{
+		UINT uiSearchRuleIndex = 0;
+
+		pstChangeIndication = (stLocalSFChangeIndicationAlt *)pstAddIndication;
+		uiSearchRuleIndex = SearchSfid(Adapter, ntohl(pstChangeIndication->sfActiveSet.u32SFID));
+		if (uiSearchRuleIndex > NO_OF_QUEUES-1)
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "SF doesn't exist for which DSC_ACK is received");
+
+		if ((uiSearchRuleIndex < NO_OF_QUEUES)) {
+			Adapter->PackInfo[uiSearchRuleIndex].ucDirection = pstChangeIndication->u8Direction;
+			if (pstChangeIndication->sfActiveSet.bValid == TRUE)
+				Adapter->PackInfo[uiSearchRuleIndex].bActiveSet = TRUE;
+
+			if (pstChangeIndication->sfAuthorizedSet.bValid == TRUE)
+				Adapter->PackInfo[uiSearchRuleIndex].bAuthorizedSet = TRUE;
+
+			if (pstChangeIndication->sfAdmittedSet.bValid == TRUE)
+				Adapter->PackInfo[uiSearchRuleIndex].bAdmittedSet = TRUE;
+
+			if (pstChangeIndication->sfActiveSet.bValid == FALSE) {
+				Adapter->PackInfo[uiSearchRuleIndex].bActive = FALSE;
+				Adapter->PackInfo[uiSearchRuleIndex].bActivateRequestSent = FALSE;
+
+				if (pstChangeIndication->sfAdmittedSet.bValid)
+					psfLocalSet = &pstChangeIndication->sfAdmittedSet;
+				else if (pstChangeIndication->sfAuthorizedSet.bValid)
+					psfLocalSet = &pstChangeIndication->sfAuthorizedSet;
+			} else {
+				psfLocalSet = &pstChangeIndication->sfActiveSet;
+				Adapter->PackInfo[uiSearchRuleIndex].bActive = TRUE;
 			}
-			if((uiSearchRuleIndex < NO_OF_QUEUES))
-			{
-				Adapter->PackInfo[uiSearchRuleIndex].ucDirection = pstChangeIndication->u8Direction;
-				if(pstChangeIndication->sfActiveSet.bValid==TRUE)
-				{
-					Adapter->PackInfo[uiSearchRuleIndex].bActiveSet=TRUE;
-				}
-				if(pstChangeIndication->sfAuthorizedSet.bValid==TRUE)
-				{
-					Adapter->PackInfo[uiSearchRuleIndex].bAuthorizedSet=TRUE;
-				}
-				if(pstChangeIndication->sfAdmittedSet.bValid==TRUE)
-				{
-					Adapter->PackInfo[uiSearchRuleIndex].bAdmittedSet=TRUE;
-				}
 
-				if(FALSE==pstChangeIndication->sfActiveSet.bValid)
-				{
-					Adapter->PackInfo[uiSearchRuleIndex].bActive = FALSE;
-					Adapter->PackInfo[uiSearchRuleIndex].bActivateRequestSent = FALSE;
-					if(pstChangeIndication->sfAdmittedSet.bValid)
-					{
-						psfLocalSet = &pstChangeIndication->sfAdmittedSet;
-					}
-					else if(pstChangeIndication->sfAuthorizedSet.bValid)
-					{
-						psfLocalSet = &pstChangeIndication->sfAuthorizedSet;
-					}
-				}
-
-				else
-				{
-					psfLocalSet = &pstChangeIndication->sfActiveSet;
-					Adapter->PackInfo[uiSearchRuleIndex].bActive=TRUE;
-				}
-				if(psfLocalSet->bValid && (pstChangeIndication->u8CC == 0))
-				{
-					Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value =
-						ntohs(pstChangeIndication->u16VCID);
-					BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "CC field is %d bvalid = %d\n",
-							pstChangeIndication->u8CC, psfLocalSet->bValid);
-					BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "VCID= %d\n", ntohs(pstChangeIndication->u16VCID));
-					Adapter->PackInfo[uiSearchRuleIndex].usCID =
-						ntohs(pstChangeIndication->u16CID);
-					CopyToAdapter(Adapter,psfLocalSet,uiSearchRuleIndex,
-								DSC_ACK, pstAddIndication);
-
-					*(PULONG)(((PUCHAR)pvBuffer)+1)=psfLocalSet->u32SFID;
-				}
-				else if(pstChangeIndication->u8CC == 6)
-				{
-					deleteSFBySfid(Adapter,uiSearchRuleIndex);
-					kfree(pstAddIndication);
-				}
-			}
-			else
-			{
-				BCM_DEBUG_PRINT( Adapter,DBG_TYPE_PRINTK, 0, 0, "DSC ACK did not get valid SFID");
+			if (!psfLocalSet) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "No set is valid\n");
+				Adapter->PackInfo[uiSearchRuleIndex].bActive = FALSE;
+				Adapter->PackInfo[uiSearchRuleIndex].bValid = FALSE;
+				Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value = 0;
 				kfree(pstAddIndication);
-				return FALSE;
+			} else if (psfLocalSet->bValid && (pstChangeIndication->u8CC == 0)) {
+				Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value = ntohs(pstChangeIndication->u16VCID);
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "CC field is %d bvalid = %d\n",
+						pstChangeIndication->u8CC, psfLocalSet->bValid);
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "VCID= %d\n", ntohs(pstChangeIndication->u16VCID));
+				Adapter->PackInfo[uiSearchRuleIndex].usCID = ntohs(pstChangeIndication->u16CID);
+				CopyToAdapter(Adapter, psfLocalSet, uiSearchRuleIndex, DSC_ACK, pstAddIndication);
+
+				*(PULONG)(((PUCHAR)pvBuffer)+1) = psfLocalSet->u32SFID;
+			} else if (pstChangeIndication->u8CC == 6) {
+				deleteSFBySfid(Adapter, uiSearchRuleIndex);
+				kfree(pstAddIndication);
 			}
+		} else {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "DSC ACK did not get valid SFID");
+			kfree(pstAddIndication);
+			return FALSE;
 		}
-		break;
-		case DSD_REQ:
-		{
-			UINT uiSearchRuleIndex;
-			ULONG ulSFID;
+	}
+	break;
+	case DSD_REQ:
+	{
+		UINT uiSearchRuleIndex;
+		ULONG ulSFID;
 
-			pLeader->PLength = sizeof(stLocalSFDeleteIndication);
-			*((stLocalSFDeleteIndication*)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *((stLocalSFDeleteIndication*)pstAddIndication);
+		pLeader->PLength = sizeof(stLocalSFDeleteIndication);
+		*((stLocalSFDeleteIndication *)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *((stLocalSFDeleteIndication *)pstAddIndication);
 
-			ulSFID = ntohl(((stLocalSFDeleteIndication*)pstAddIndication)->u32SFID);
-			uiSearchRuleIndex=SearchSfid(Adapter,ulSFID);
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "DSD - Removing connection %x",uiSearchRuleIndex);
+		ulSFID = ntohl(((stLocalSFDeleteIndication *)pstAddIndication)->u32SFID);
+		uiSearchRuleIndex = SearchSfid(Adapter, ulSFID);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "DSD - Removing connection %x", uiSearchRuleIndex);
 
-			if(uiSearchRuleIndex < NO_OF_QUEUES)
-			{
-				//Delete All Classifiers Associated with this SFID
-				deleteSFBySfid(Adapter,uiSearchRuleIndex);
-				Adapter->u32TotalDSD++;
-			}
-
-			BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSD RESPONSE TO MAC");
-			((stLocalSFDeleteIndication*)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSD_RSP;
-			CopyBufferToControlPacket(Adapter,(PVOID)Adapter->caDsxReqResp);
+		if (uiSearchRuleIndex < NO_OF_QUEUES) {
+			/* Delete All Classifiers Associated with this SFID */
+			deleteSFBySfid(Adapter, uiSearchRuleIndex);
+			Adapter->u32TotalDSD++;
 		}
-		case DSD_RSP:
-		{
-			//Do nothing as SF has already got Deleted
-		}
-		break;
+
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSD RESPONSE TO MAC");
+		((stLocalSFDeleteIndication *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSD_RSP;
+		CopyBufferToControlPacket(Adapter, (PVOID)Adapter->caDsxReqResp);
+	}
+	case DSD_RSP:
+	{
+		/* Do nothing as SF has already got Deleted */
+	}
+	break;
 	case DSD_ACK:
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "DSD ACK Rcd, let App handle it\n");
-			break;
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "DSD ACK Rcd, let App handle it\n");
+		break;
 	default:
 		kfree(pstAddIndication);
-		return FALSE ;
+		return FALSE;
 	}
 	return TRUE;
 }
@@ -2280,78 +1918,67 @@
 int get_dsx_sf_data_to_application(PMINI_ADAPTER Adapter, UINT uiSFId, void __user *user_buffer)
 {
 	int status = 0;
-	struct _packet_info *psSfInfo=NULL;
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "status =%d",status);
+	struct _packet_info *psSfInfo = NULL;
+
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "status =%d", status);
 	status = SearchSfid(Adapter, uiSFId);
 	if (status >= NO_OF_QUEUES) {
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SFID %d not present in queue !!!", uiSFId );
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SFID %d not present in queue !!!", uiSFId);
 		return -EINVAL;
 	}
-	BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "status =%d",status);
-	psSfInfo=&Adapter->PackInfo[status];
-	if(psSfInfo->pstSFIndication && copy_to_user(user_buffer,
-		psSfInfo->pstSFIndication, sizeof(stLocalSFAddIndicationAlt)))
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "copy to user failed SFID %d, present in queue !!!", uiSFId );
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "status =%d", status);
+	psSfInfo = &Adapter->PackInfo[status];
+	if (psSfInfo->pstSFIndication && copy_to_user(user_buffer,
+							psSfInfo->pstSFIndication, sizeof(stLocalSFAddIndicationAlt))) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "copy to user failed SFID %d, present in queue !!!", uiSFId);
 		status = -EFAULT;
 		return status;
 	}
 	return STATUS_SUCCESS;
 }
 
-VOID OverrideServiceFlowParams(PMINI_ADAPTER Adapter,PUINT puiBuffer)
+VOID OverrideServiceFlowParams(PMINI_ADAPTER Adapter, PUINT puiBuffer)
 {
-	B_UINT32 u32NumofSFsinMsg    = ntohl(*(puiBuffer + 1));
+	B_UINT32 u32NumofSFsinMsg = ntohl(*(puiBuffer + 1));
 	stIM_SFHostNotify *pHostInfo = NULL;
-	UINT uiSearchRuleIndex       = 0;
-	ULONG ulSFID                 = 0;
+	UINT uiSearchRuleIndex = 0;
+	ULONG ulSFID = 0;
 
-	puiBuffer+=2;
+	puiBuffer += 2;
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "u32NumofSFsinMsg: 0x%x\n", u32NumofSFsinMsg);
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "u32NumofSFsinMsg: 0x%x\n",u32NumofSFsinMsg);
-
-	while(u32NumofSFsinMsg != 0 && u32NumofSFsinMsg < NO_OF_QUEUES)
-	{
+	while (u32NumofSFsinMsg != 0 && u32NumofSFsinMsg < NO_OF_QUEUES) {
 		u32NumofSFsinMsg--;
 		pHostInfo = (stIM_SFHostNotify *)puiBuffer;
 		puiBuffer = (PUINT)(pHostInfo + 1);
 
 		ulSFID = ntohl(pHostInfo->SFID);
-		uiSearchRuleIndex=SearchSfid(Adapter,ulSFID);
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"SFID: 0x%lx\n",ulSFID);
+		uiSearchRuleIndex = SearchSfid(Adapter, ulSFID);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SFID: 0x%lx\n", ulSFID);
 
-		if(uiSearchRuleIndex >= NO_OF_QUEUES || uiSearchRuleIndex == HiPriority)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"The SFID <%lx> doesn't exist in host entry or is Invalid\n", ulSFID);
+		if (uiSearchRuleIndex >= NO_OF_QUEUES || uiSearchRuleIndex == HiPriority) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "The SFID <%lx> doesn't exist in host entry or is Invalid\n", ulSFID);
 			continue;
 		}
 
-		if(pHostInfo->RetainSF == FALSE)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"Going to Delete SF");
-			deleteSFBySfid(Adapter,uiSearchRuleIndex);
-		}
-		else
-		{
-
+		if (pHostInfo->RetainSF == FALSE) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Going to Delete SF");
+			deleteSFBySfid(Adapter, uiSearchRuleIndex);
+		} else {
 			Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value = ntohs(pHostInfo->VCID);
 			Adapter->PackInfo[uiSearchRuleIndex].usCID = ntohs(pHostInfo->newCID);
-			Adapter->PackInfo[uiSearchRuleIndex].bActive=FALSE;
+			Adapter->PackInfo[uiSearchRuleIndex].bActive = FALSE;
 
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,"pHostInfo->QoSParamSet: 0x%x\n",pHostInfo->QoSParamSet);
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "pHostInfo->QoSParamSet: 0x%x\n", pHostInfo->QoSParamSet);
 
-			if(pHostInfo->QoSParamSet & 0x1)
-				Adapter->PackInfo[uiSearchRuleIndex].bAuthorizedSet =TRUE;
-			if(pHostInfo->QoSParamSet & 0x2)
-				Adapter->PackInfo[uiSearchRuleIndex].bAdmittedSet =TRUE;
-			if(pHostInfo->QoSParamSet & 0x4)
-			{
-				Adapter->PackInfo[uiSearchRuleIndex].bActiveSet =TRUE;
-				Adapter->PackInfo[uiSearchRuleIndex].bActive=TRUE;
+			if (pHostInfo->QoSParamSet & 0x1)
+				Adapter->PackInfo[uiSearchRuleIndex].bAuthorizedSet = TRUE;
+			if (pHostInfo->QoSParamSet & 0x2)
+				Adapter->PackInfo[uiSearchRuleIndex].bAdmittedSet = TRUE;
+			if (pHostInfo->QoSParamSet & 0x4) {
+				Adapter->PackInfo[uiSearchRuleIndex].bActiveSet = TRUE;
+				Adapter->PackInfo[uiSearchRuleIndex].bActive = TRUE;
 			}
 		}
 	}
 }
-
-
-
diff --git a/drivers/staging/bcm/led_control.h b/drivers/staging/bcm/led_control.h
index 0711ac2..ed8fbc0 100644
--- a/drivers/staging/bcm/led_control.h
+++ b/drivers/staging/bcm/led_control.h
@@ -4,11 +4,11 @@
 /*************************TYPE DEF**********************/
 #define NUM_OF_LEDS 4
 
-#define DSD_START_OFFSET                     0x0200
-#define EEPROM_VERSION_OFFSET           	 0x020E
-#define EEPROM_HW_PARAM_POINTER_ADDRESS 	 0x0218
-#define EEPROM_HW_PARAM_POINTER_ADDRRES_MAP5 0x0220
-#define GPIO_SECTION_START_OFFSET        	 0x03
+#define DSD_START_OFFSET			0x0200
+#define EEPROM_VERSION_OFFSET			0x020E
+#define EEPROM_HW_PARAM_POINTER_ADDRESS		0x0218
+#define EEPROM_HW_PARAM_POINTER_ADDRRES_MAP5	0x0220
+#define GPIO_SECTION_START_OFFSET		0x03
 
 #define COMPATIBILITY_SECTION_LENGTH         42
 #define COMPATIBILITY_SECTION_LENGTH_MAP5    84
@@ -18,27 +18,27 @@
 #define EEPROM_MAP5_MINORVERSION             0
 
 
-#define MAX_NUM_OF_BLINKS 					10
-#define NUM_OF_GPIO_PINS 					16
+#define MAX_NUM_OF_BLINKS			10
+#define NUM_OF_GPIO_PINS			16
 
-#define DISABLE_GPIO_NUM 					0xFF
-#define EVENT_SIGNALED 						1
+#define DISABLE_GPIO_NUM			0xFF
+#define EVENT_SIGNALED				1
 
-#define MAX_FILE_NAME_BUFFER_SIZE 			100
+#define MAX_FILE_NAME_BUFFER_SIZE		100
 
-#define TURN_ON_LED(GPIO, index) do{ \
+#define TURN_ON_LED(GPIO, index) do { \
 							UINT gpio_val = GPIO; \
 							(Adapter->LEDInfo.LEDState[index].BitPolarity == 1) ? \
-							wrmaltWithLock(Adapter,BCM_GPIO_OUTPUT_SET_REG, &gpio_val ,sizeof(gpio_val)) : \
-							wrmaltWithLock(Adapter,BCM_GPIO_OUTPUT_CLR_REG, &gpio_val, sizeof(gpio_val)); \
-						}while(0);
+							wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_SET_REG, &gpio_val, sizeof(gpio_val)) : \
+							wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_CLR_REG, &gpio_val, sizeof(gpio_val)); \
+						} while (0);
 
 #define TURN_OFF_LED(GPIO, index)  do { \
 							UINT gpio_val = GPIO; \
 							(Adapter->LEDInfo.LEDState[index].BitPolarity == 1) ? \
-							wrmaltWithLock(Adapter,BCM_GPIO_OUTPUT_CLR_REG,&gpio_val ,sizeof(gpio_val)) : \
-							wrmaltWithLock(Adapter,BCM_GPIO_OUTPUT_SET_REG,&gpio_val ,sizeof(gpio_val));  \
-						}while(0);
+							wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_CLR_REG, &gpio_val, sizeof(gpio_val)) : \
+							wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_SET_REG, &gpio_val, sizeof(gpio_val));  \
+						} while (0);
 
 #define B_ULONG32 unsigned long
 
@@ -50,7 +50,7 @@
 	BLUE_LED = 2,
 	YELLOW_LED = 3,
 	GREEN_LED = 4
-} LEDColors; 				/*Enumerated values of different LED types*/
+} LEDColors;	/*Enumerated values of different LED types*/
 
 typedef enum LedEvents {
 	SHUTDOWN_EXIT = 0x00,
@@ -62,43 +62,39 @@
 	LOWPOWER_MODE_ENTER = 0x20,
 	IDLEMODE_CONTINUE = 0x40,
 	IDLEMODE_EXIT = 0x80,
-	LED_THREAD_INACTIVE = 0x100,  //Makes the LED thread Inactivce. It wil be equivallent to putting the thread on hold.
-	LED_THREAD_ACTIVE = 0x200    //Makes the LED Thread Active back.
-} LedEventInfo_t;			/*Enumerated values of different driver states*/
+	LED_THREAD_INACTIVE = 0x100,  /* Makes the LED thread Inactivce. It wil be equivallent to putting the thread on hold. */
+	LED_THREAD_ACTIVE = 0x200,    /* Makes the LED Thread Active back. */
+	DRIVER_HALT = 0xff
+} LedEventInfo_t;	/* Enumerated values of different driver states */
 
-#define DRIVER_HALT 0xff
-
-
-/*Structure which stores the information of different LED types
- *  and corresponding LED state information of driver states*/
-typedef struct LedStateInfo_t
-{
+/*
+ * Structure which stores the information of different LED types
+ * and corresponding LED state information of driver states
+ */
+typedef struct LedStateInfo_t {
 	UCHAR LED_Type; /* specify GPIO number - use 0xFF if not used */
 	UCHAR LED_On_State; /* Bits set or reset for different states */
 	UCHAR LED_Blink_State; /* Bits set or reset for blinking LEDs for different states */
 	UCHAR GPIO_Num;
-	UCHAR 			BitPolarity;				/*To represent whether H/W is normal polarity or reverse
-											  polarity*/
-}LEDStateInfo, *pLEDStateInfo;
+	UCHAR BitPolarity; /* To represent whether H/W is normal polarity or reverse polarity */
+} LEDStateInfo, *pLEDStateInfo;
 
 
-typedef struct _LED_INFO_STRUCT
-{
+typedef struct _LED_INFO_STRUCT {
 	LEDStateInfo	LEDState[NUM_OF_LEDS];
-	BOOLEAN 		bIdleMode_tx_from_host; /*Variable to notify whether driver came out
-											from idlemode due to Host or target*/
+	BOOLEAN		bIdleMode_tx_from_host; /* Variable to notify whether driver came out from idlemode due to Host or target*/
 	BOOLEAN			bIdle_led_off;
 	wait_queue_head_t   notify_led_event;
 	wait_queue_head_t	idleModeSyncEvent;
- 	struct task_struct  *led_cntrl_threadid;
-    int                 led_thread_running;
+	struct task_struct  *led_cntrl_threadid;
+	int                 led_thread_running;
 	BOOLEAN			bLedInitDone;
 
 } LED_INFO_STRUCT, *PLED_INFO_STRUCT;
-//LED Thread state.
-#define BCM_LED_THREAD_DISABLED			 	 0 //LED Thread is not running.
-#define BCM_LED_THREAD_RUNNING_ACTIVELY  	 1 //LED thread is running.
-#define BCM_LED_THREAD_RUNNING_INACTIVELY	 2 //LED thread has been put on hold
+/* LED Thread state. */
+#define BCM_LED_THREAD_DISABLED		0 /* LED Thread is not running. */
+#define BCM_LED_THREAD_RUNNING_ACTIVELY	1 /* LED thread is running. */
+#define BCM_LED_THREAD_RUNNING_INACTIVELY 2 /*LED thread has been put on hold*/
 
 
 
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index 4c77e50..12c691d 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -765,8 +765,9 @@
 	default N
 	---help---
 	  Enable support for Advantech PCI DIO cards
-	  PCI-1730, PCI-1733, PCI-1734, PCI-1736UP, PCI-1750, PCI-1751,
-	  PCI-1752, PCI-1753/E, PCI-1754, PCI-1756 and PCI-1762
+	  PCI-1730, PCI-1733, PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U,
+	  PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, PCI-1754, PCI-1756,
+	  PCI-1760 and PCI-1762
 
 	  To compile this driver as a module, choose M here: the module will be
 	  called adv_pci_dio.
diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c
index 537e585..7af068f 100644
--- a/drivers/staging/comedi/drivers/adv_pci_dio.c
+++ b/drivers/staging/comedi/drivers/adv_pci_dio.c
@@ -8,16 +8,16 @@
 /*
 Driver: adv_pci_dio
 Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1735U,
-	PCI-1736UP, PCI-1750, PCI-1751, PCI-1752, PCI-1753/E,
-	PCI-1754, PCI-1756, PCI-1762
+	PCI-1736UP, PCI-1739U, PCI-1750, PCI-1751, PCI-1752,
+	PCI-1753/E, PCI-1754, PCI-1756, PCI-1760, PCI-1762
 Author: Michal Dobes <dobes@tesnet.cz>
 Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733,
-  PCI-1734, PCI-1735U, PCI-1736UP, PCI-1750,
+  PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U, PCI-1750,
   PCI-1751, PCI-1752, PCI-1753,
   PCI-1753+PCI-1753E, PCI-1754, PCI-1756,
   PCI-1760, PCI-1762
 Status: untested
-Updated: Tue, 04 May 2010 13:00:00 +0000
+Updated: Mon, 09 Jan 2012 12:40:46 +0000
 
 This driver supports now only insn interface for DI/DO/DIO.
 
@@ -51,6 +51,7 @@
 /* hardware types of the cards */
 enum hw_cards_id {
 	TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1735, TYPE_PCI1736,
+	TYPE_PCI1739,
 	TYPE_PCI1750,
 	TYPE_PCI1751,
 	TYPE_PCI1752,
@@ -109,6 +110,12 @@
 #define PCI1736_BOARDID    4	/* R:   Board I/D switch for 1736UP */
 #define PCI1736_MAINREG    0	/* Normal register (2) doesn't work */
 
+/* Advantech PCI-1739U */
+#define PCI1739_DIO	   0	/* R/W: begin of 8255 registers block */
+#define PCI1739_ICR	  32	/* W:   Interrupt control register */
+#define PCI1739_ISR	  32	/* R:   Interrupt status register */
+#define PCI1739_BOARDID	   8    /* R:   Board I/D switch for 1739U */
+
 /*  Advantech PCI-1750 */
 #define PCI1750_IDI	   0	/* R:   Isolated digital input  0-15 */
 #define PCI1750_IDO	   0	/* W:   Isolated digital output 0-15 */
@@ -262,6 +269,7 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1734) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1735) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1736) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1739) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1750) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1751) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1752) },
@@ -316,6 +324,14 @@
 	 {4, PCI1736_BOARDID, 1, SDF_INTERNAL},
 	 { {0, 0, 0, 0} },
 	 IO_8b},
+	{"pci1739", PCI_VENDOR_ID_ADVANTECH, 0x1739, PCIDIO_MAINREG,
+	 TYPE_PCI1739,
+	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
+	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
+	 { {48, PCI1739_DIO, 2, 0}, {0, 0, 0, 0} },
+	 {0, 0, 0, 0},
+	 { {0, 0, 0, 0} },
+	 IO_8b},
 	{"pci1750", PCI_VENDOR_ID_ADVANTECH, 0x1750, PCIDIO_MAINREG,
 	 TYPE_PCI1750,
 	 { {0, 0, 0, 0}, {16, PCI1750_IDI, 2, 0} },
@@ -883,6 +899,11 @@
 		outb(0, dev->iobase + PCI1736_3_INT_RF);
 		break;
 
+	case TYPE_PCI1739:
+		/* disable & clear interrupts */
+		outb(0x88, dev->iobase + PCI1739_ICR);
+		break;
+
 	case TYPE_PCI1750:
 	case TYPE_PCI1751:
 		/* disable & clear interrupts */
diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c
index 5cce1b5..b85c836 100644
--- a/drivers/staging/comedi/drivers/dt2801.c
+++ b/drivers/staging/comedi/drivers/dt2801.c
@@ -720,12 +720,20 @@
 		which = 1;
 
 	/* configure */
-	if (data[0]) {
+	switch (data[0]) {
+	case INSN_CONFIG_DIO_OUTPUT:
 		s->io_bits = 0xff;
 		dt2801_writecmd(dev, DT_C_SET_DIGOUT);
-	} else {
+		break;
+	case INSN_CONFIG_DIO_INPUT:
 		s->io_bits = 0;
 		dt2801_writecmd(dev, DT_C_SET_DIGIN);
+		break;
+	case INSN_CONFIG_DIO_QUERY:
+		data[1] = s->io_bits ? COMEDI_OUTPUT : COMEDI_INPUT;
+		return insn->n;
+	default:
+		return -EINVAL;
 	}
 	dt2801_writedata(dev, which);
 
diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c
index 32d9c42..e86ab58 100644
--- a/drivers/staging/comedi/drivers/dt9812.c
+++ b/drivers/staging/comedi/drivers/dt9812.c
@@ -527,7 +527,7 @@
 		 * 11x -> Gain =  0.5
 		 */
 	case DT9812_GAIN_0PT5:
-		rmw->or_value = F020_MASK_ADC0CF_AMP0GN2 ||
+		rmw->or_value = F020_MASK_ADC0CF_AMP0GN2 |
 		    F020_MASK_ADC0CF_AMP0GN1;
 		break;
 	case DT9812_GAIN_1:
@@ -540,7 +540,7 @@
 		rmw->or_value = F020_MASK_ADC0CF_AMP0GN1;
 		break;
 	case DT9812_GAIN_8:
-		rmw->or_value = F020_MASK_ADC0CF_AMP0GN1 ||
+		rmw->or_value = F020_MASK_ADC0CF_AMP0GN1 |
 		    F020_MASK_ADC0CF_AMP0GN0;
 		break;
 	case DT9812_GAIN_16:
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c
index b692fea..b0bc6bb 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -2098,23 +2098,29 @@
 
 	CALL_PDEBUG("In me4000_dio_insn_config()\n");
 
-	if (data[0] == INSN_CONFIG_DIO_QUERY) {
+	switch (data[0]) {
+	default:
+		return -EINVAL;
+	case INSN_CONFIG_DIO_QUERY:
 		data[1] =
 		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
 		return insn->n;
+	case INSN_CONFIG_DIO_INPUT:
+	case INSN_CONFIG_DIO_OUTPUT:
+		break;
 	}
 
 	/*
 	 * The input or output configuration of each digital line is
 	 * configured by a special insn_config instruction.  chanspec
 	 * contains the channel to be changed, and data[0] contains the
-	 * value COMEDI_INPUT or COMEDI_OUTPUT.
+	 * value INSN_CONFIG_DIO_INPUT or INSN_CONFIG_DIO_OUTPUT.
 	 * On the ME-4000 it is only possible to switch port wise (8 bit)
 	 */
 
 	tmp = me4000_inl(dev, info->dio_context.ctrl_reg);
 
-	if (data[0] == COMEDI_OUTPUT) {
+	if (data[0] == INSN_CONFIG_DIO_OUTPUT) {
 		if (chan < 8) {
 			s->io_bits |= 0xFF;
 			tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 |
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index 045a4c0..1df8fcb 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -30,7 +30,7 @@
 Devices: [National Instruments] PCI-DIO-32HS (ni_pcidio), PXI-6533,
   PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, PCI-6503B, PCI-6503X,
   PXI-6503, PCI-6533, PCI-6534
-Updated: Sun, 21 Apr 2002 21:03:38 -0700
+Updated: Mon, 09 Jan 2012 14:27:23 +0000
 
 The DIO-96 appears as four 8255 subdevices.  See the 8255
 driver notes for details.
@@ -42,6 +42,11 @@
 
 DMA mostly works for the PCI-DIO32HS, but only in timed input mode.
 
+The PCI-DIO-32HS/PCI-6533 has a configurable external trigger. Setting
+scan_begin_arg to 0 or CR_EDGE triggers on the leading edge. Setting
+scan_begin_arg to CR_INVERT or (CR_EDGE | CR_INVERT) triggers on the
+trailing edge.
+
 This driver could be easily modified to support AT-MIO32HS and
 AT-MIO96.
 
@@ -436,6 +441,7 @@
 		comedi_error(dev, "failed to reserve mite dma channel.");
 		return -EBUSY;
 	}
+	devpriv->di_mite_chan->dir = COMEDI_INPUT;
 	writeb(primary_DMAChannel_bits(devpriv->di_mite_chan->channel) |
 	       secondary_DMAChannel_bits(devpriv->di_mite_chan->channel),
 	       devpriv->mite->daq_io_addr + DMA_Line_Control_Group1);
@@ -482,6 +488,21 @@
 	comedi_event(dev, s);
 }
 
+static int ni_pcidio_poll(struct comedi_device *dev, struct comedi_subdevice *s)
+{
+	unsigned long irq_flags;
+	int count;
+
+	spin_lock_irqsave(&dev->spinlock, irq_flags);
+	spin_lock(&devpriv->mite_channel_lock);
+	if (devpriv->di_mite_chan)
+		mite_sync_input_dma(devpriv->di_mite_chan, s->async);
+	spin_unlock(&devpriv->mite_channel_lock);
+	count = s->async->buf_write_count - s->async->buf_read_count;
+	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
+	return count;
+}
+
 static irqreturn_t nidio_interrupt(int irq, void *d)
 {
 	struct comedi_device *dev = d;
@@ -497,7 +518,6 @@
 	int status;
 	int work = 0;
 	unsigned int m_status = 0;
-	unsigned long irq_flags;
 
 	/* interrupcions parasites */
 	if (dev->attached == 0) {
@@ -505,6 +525,9 @@
 		return IRQ_NONE;
 	}
 
+	/* Lock to avoid race with comedi_poll */
+	spin_lock(&dev->spinlock);
+
 	status = readb(devpriv->mite->daq_io_addr +
 		       Interrupt_And_Window_Status);
 	flags = readb(devpriv->mite->daq_io_addr + Group_1_Flags);
@@ -518,7 +541,7 @@
 	/* printk("buf[4096]=%08x\n",
 	       *(unsigned int *)(async->prealloc_buf+4096)); */
 
-	spin_lock_irqsave(&devpriv->mite_channel_lock, irq_flags);
+	spin_lock(&devpriv->mite_channel_lock);
 	if (devpriv->di_mite_chan)
 		m_status = mite_get_status(devpriv->di_mite_chan);
 #ifdef MITE_DEBUG
@@ -543,7 +566,7 @@
 			disable_irq(dev->irq);
 		}
 	}
-	spin_unlock_irqrestore(&devpriv->mite_channel_lock, irq_flags);
+	spin_unlock(&devpriv->mite_channel_lock);
 
 	while (status & DataLeft) {
 		work++;
@@ -645,6 +668,8 @@
 		       Master_DMA_And_Interrupt_Control);
 	}
 #endif
+
+	spin_unlock(&dev->spinlock);
 	return IRQ_HANDLED;
 }
 
@@ -825,8 +850,8 @@
 	} else {
 		/* TRIG_EXT */
 		/* should be level/edge, hi/lo specification here */
-		if (cmd->scan_begin_arg != 0) {
-			cmd->scan_begin_arg = 0;
+		if ((cmd->scan_begin_arg & ~(CR_EDGE | CR_INVERT)) != 0) {
+			cmd->scan_begin_arg &= (CR_EDGE | CR_INVERT);
 			err++;
 		}
 	}
@@ -941,7 +966,13 @@
 		writeb(0, devpriv->mite->daq_io_addr + Sequence);
 		writeb(0x00, devpriv->mite->daq_io_addr + ReqReg);
 		writeb(4, devpriv->mite->daq_io_addr + BlockMode);
-		writeb(0, devpriv->mite->daq_io_addr + LinePolarities);
+		if (!(cmd->scan_begin_arg & CR_INVERT)) {
+			/* Leading Edge pulse mode */
+			writeb(0, devpriv->mite->daq_io_addr + LinePolarities);
+		} else {
+			/* Trailing Edge pulse mode */
+			writeb(2, devpriv->mite->daq_io_addr + LinePolarities);
+		}
 		writeb(0x00, devpriv->mite->daq_io_addr + AckSer);
 		writel(1, devpriv->mite->daq_io_addr + StartDelay);
 		writeb(1, devpriv->mite->daq_io_addr + ReqDelay);
@@ -1005,17 +1036,24 @@
 static int setup_mite_dma(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	int retval;
+	unsigned long flags;
 
 	retval = ni_pcidio_request_di_mite_channel(dev);
 	if (retval)
 		return retval;
 
-	devpriv->di_mite_chan->dir = COMEDI_INPUT;
+	/* write alloc the entire buffer */
+	comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
 
-	mite_prep_dma(devpriv->di_mite_chan, 32, 32);
+	spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+	if (devpriv->di_mite_chan) {
+		mite_prep_dma(devpriv->di_mite_chan, 32, 32);
+		mite_dma_arm(devpriv->di_mite_chan);
+	} else
+		retval = -EIO;
+	spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
 
-	mite_dma_arm(devpriv->di_mite_chan);
-	return 0;
+	return retval;
 }
 
 static int ni_pcidio_inttrig(struct comedi_device *dev,
@@ -1244,6 +1282,7 @@
 		s->len_chanlist = 32;	/* XXX */
 		s->buf_change = &ni_pcidio_change;
 		s->async_dma_dir = DMA_BIDIRECTIONAL;
+		s->poll = &ni_pcidio_poll;
 
 		writel(0, devpriv->mite->daq_io_addr + Port_IO(0));
 		writel(0, devpriv->mite->daq_io_addr + Port_Pin_Directions(0));
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c
index 0f0d995..27baefa 100644
--- a/drivers/staging/comedi/drivers/ni_pcimio.c
+++ b/drivers/staging/comedi/drivers/ni_pcimio.c
@@ -29,14 +29,15 @@
   PCI-MIO-16XE-10, PXI-6030E, PCI-MIO-16E-1, PCI-MIO-16E-4, PCI-6014, PCI-6040E,
   PXI-6040E, PCI-6030E, PCI-6031E, PCI-6032E, PCI-6033E, PCI-6071E, PCI-6023E,
   PCI-6024E, PCI-6025E, PXI-6025E, PCI-6034E, PCI-6035E, PCI-6052E,
-  PCI-6110, PCI-6111, PCI-6220, PCI-6221, PCI-6224, PXI-6224, PCI-6225, PXI-6225,
-  PCI-6229, PCI-6250, PCI-6251, PCIe-6251, PCI-6254, PCI-6259, PCIe-6259,
+  PCI-6110, PCI-6111, PCI-6220, PCI-6221, PCI-6224, PXI-6224,
+  PCI-6225, PXI-6225, PCI-6229, PCI-6250, PCI-6251, PCIe-6251, PXIe-6251,
+  PCI-6254, PCI-6259, PCIe-6259,
   PCI-6280, PCI-6281, PXI-6281, PCI-6284, PCI-6289,
   PCI-6711, PXI-6711, PCI-6713, PXI-6713,
   PXI-6071E, PCI-6070E, PXI-6070E,
   PXI-6052E, PCI-6036E, PCI-6731, PCI-6733, PXI-6733,
   PCI-6143, PXI-6143
-Updated: Wed, 03 Dec 2008 10:51:47 +0000
+Updated: Mon, 09 Jan 2012 14:52:48 +0000
 
 These boards are almost identical to the AT-MIO E series, except that
 they use the PCI bus instead of ISA (i.e., AT).  See the notes for
@@ -182,6 +183,7 @@
 	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717f)},
 	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71bc)},
 	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717d)},
+	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x72e8)},
 	{0}
 };
 
@@ -1046,6 +1048,25 @@
 	 .has_8255 = 0,
 	 },
 	{
+	 .device_id = 0x72e8,
+	 .name = "pxie-6251",
+	 .n_adchan = 16,
+	 .adbits = 16,
+	 .ai_fifo_depth = 4095,
+	 .gainlkup = ai_gain_628x,
+	 .ai_speed = 800,
+	 .n_aochan = 2,
+	 .aobits = 16,
+	 .ao_fifo_depth = 8191,
+	 .ao_range_table = &range_ni_M_625x_ao,
+	 .reg_type = ni_reg_625x,
+	 .ao_unipolar = 0,
+	 .ao_speed = 357,
+	 .num_p0_dio_channels = 8,
+	 .caldac = {caldac_none},
+	 .has_8255 = 0,
+	 },
+	{
 	 .device_id = 0x70b7,
 	 .name = "pci-6254",
 	 .n_adchan = 32,
diff --git a/drivers/staging/comedi/drivers/unioxx5.c b/drivers/staging/comedi/drivers/unioxx5.c
index 89e62aa..f45824f 100644
--- a/drivers/staging/comedi/drivers/unioxx5.c
+++ b/drivers/staging/comedi/drivers/unioxx5.c
@@ -306,7 +306,7 @@
 	usp = kzalloc(sizeof(*usp), GFP_KERNEL);
 
 	if (usp == NULL) {
-		printk(KERN_ERR "comedi%d: erorr! --> out of memory!\n", minor);
+		printk(KERN_ERR "comedi%d: error! --> out of memory!\n", minor);
 		return -1;
 	}
 
diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c
index ca6bcf8..63c9b6d 100644
--- a/drivers/staging/comedi/drivers/usbduxsigma.c
+++ b/drivers/staging/comedi/drivers/usbduxsigma.c
@@ -39,7 +39,7 @@
  *
  *
  * Revision history:
- *   0.1: inital version
+ *   0.1: initial version
  *   0.2: all basic functions implemented, digital I/O only for one port
  *   0.3: proper vendor ID and driver name
  *   0.4: fixed D/A voltage range
@@ -235,16 +235,16 @@
 	short int ao_cmd_running;
 	/* pwm is running */
 	short int pwm_cmd_running;
-	/* continous aquisition */
-	short int ai_continous;
-	short int ao_continous;
+	/* continuous acquisition */
+	short int ai_continuous;
+	short int ao_continuous;
 	/* number of samples to acquire */
 	int ai_sample_count;
 	int ao_sample_count;
 	/* time between samples in units of the timer */
 	unsigned int ai_timer;
 	unsigned int ao_timer;
-	/* counter between aquisitions */
+	/* counter between acquisitions */
 	unsigned int ai_counter;
 	unsigned int ao_counter;
 	/* interval in frames/uframes */
@@ -455,8 +455,8 @@
 	this_usbduxsub->ai_counter = this_usbduxsub->ai_timer;
 
 	/* test, if we transmit only a fixed number of samples */
-	if (!(this_usbduxsub->ai_continous)) {
-		/* not continous, fixed number of samples */
+	if (!(this_usbduxsub->ai_continuous)) {
+		/* not continuous, fixed number of samples */
 		this_usbduxsub->ai_sample_count--;
 		/* all samples received? */
 		if (this_usbduxsub->ai_sample_count < 0) {
@@ -607,8 +607,8 @@
 		/* timer zero */
 		this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
 
-		/* handle non continous aquisition */
-		if (!(this_usbduxsub->ao_continous)) {
+		/* handle non continuous acquisition */
+		if (!(this_usbduxsub->ao_continuous)) {
 			/* fixed number of samples */
 			this_usbduxsub->ao_sample_count--;
 			if (this_usbduxsub->ao_sample_count < 0) {
@@ -925,7 +925,7 @@
 	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
 		err++;
 
-	/* scanning is continous */
+	/* scanning is continuous */
 	tmp = cmd->convert_src;
 	cmd->convert_src &= TRIG_NOW;
 	if (!cmd->convert_src || tmp != cmd->convert_src)
@@ -1193,7 +1193,7 @@
 		up(&this_usbduxsub->sem);
 		return -EBUSY;
 	}
-	/* set current channel of the running aquisition to zero */
+	/* set current channel of the running acquisition to zero */
 	s->async->cur_chan = 0;
 
 	/* first the number of channels per time step */
@@ -1261,10 +1261,10 @@
 	if (cmd->stop_src == TRIG_COUNT) {
 		/* data arrives as one packet */
 		this_usbduxsub->ai_sample_count = cmd->stop_arg;
-		this_usbduxsub->ai_continous = 0;
+		this_usbduxsub->ai_continuous = 0;
 	} else {
-		/* continous aquisition */
-		this_usbduxsub->ai_continous = 1;
+		/* continuous acquisition */
+		this_usbduxsub->ai_continuous = 1;
 		this_usbduxsub->ai_sample_count = 0;
 	}
 
@@ -1586,7 +1586,7 @@
 	/* just now we scan also in the high speed mode every frame */
 	/* this is due to ehci driver limitations */
 	if (0) {		/* (this_usbduxsub->high_speed) */
-		/* start immidiately a new scan */
+		/* start immediately a new scan */
 		/* the sampling rate is set by the coversion rate */
 		cmd->scan_begin_src &= TRIG_FOLLOW;
 	} else {
@@ -1596,7 +1596,7 @@
 	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
 		err++;
 
-	/* scanning is continous */
+	/* scanning is continuous */
 	tmp = cmd->convert_src;
 
 	/* all conversion events happen simultaneously */
@@ -1710,7 +1710,7 @@
 	dev_dbg(&this_usbduxsub->interface->dev,
 		"comedi%d: %s\n", dev->minor, __func__);
 
-	/* set current channel of the running aquisition to zero */
+	/* set current channel of the running acquisition to zero */
 	s->async->cur_chan = 0;
 	for (i = 0; i < cmd->chanlist_len; ++i) {
 		chan = CR_CHAN(cmd->chanlist[i]);
@@ -1759,7 +1759,7 @@
 	this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
 
 	if (cmd->stop_src == TRIG_COUNT) {
-		/* not continous */
+		/* not continuous */
 		/* counter */
 		/* high speed also scans everything at once */
 		if (0) {	/* (this_usbduxsub->high_speed) */
@@ -1771,10 +1771,10 @@
 			/* data arrives as one packet */
 			this_usbduxsub->ao_sample_count = cmd->stop_arg;
 		}
-		this_usbduxsub->ao_continous = 0;
+		this_usbduxsub->ao_continuous = 0;
 	} else {
-		/* continous aquisition */
-		this_usbduxsub->ao_continous = 1;
+		/* continuous acquisition */
+		this_usbduxsub->ao_continuous = 1;
 		this_usbduxsub->ao_sample_count = 0;
 	}
 
diff --git a/drivers/staging/crystalhd/bc_dts_glob_lnx.h b/drivers/staging/crystalhd/bc_dts_glob_lnx.h
index bbe5119..fd1a6e6 100644
--- a/drivers/staging/crystalhd/bc_dts_glob_lnx.h
+++ b/drivers/staging/crystalhd/bc_dts_glob_lnx.h
@@ -48,8 +48,7 @@
 
 #endif
 
-#include "bc_dts_defs.h"
-#include "bcm_70012_regs.h"	/* Link Register defs */
+#include "crystalhd.h"
 
 #define CRYSTALHD_API_NAME	"crystalhd"
 #define CRYSTALHD_API_DEV_NAME	"/dev/crystalhd"
diff --git a/drivers/staging/crystalhd/bc_dts_types.h b/drivers/staging/crystalhd/bc_dts_types.h
deleted file mode 100644
index 1085a91..0000000
--- a/drivers/staging/crystalhd/bc_dts_types.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/********************************************************************
- * Copyright(c) 2006-2009 Broadcom Corporation.
- *
- *  Name: bc_dts_types.h
- *
- *  Description: Data types
- *
- *  AU
- *
- *  HISTORY:
- *
- ********************************************************************
- * This header is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation, either version 2.1 of the License.
- *
- * This header 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 Lesser General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public License
- * along with this header.  If not, see <http://www.gnu.org/licenses/>.
- *******************************************************************/
-
-#ifndef _BC_DTS_TYPES_H_
-#define _BC_DTS_TYPES_H_
-
-#include <stdint.h>
-
-#ifndef TRUE
-	#define TRUE		1
-#endif
-
-#ifndef FALSE
-	#define FALSE		0
-#endif
-
-#define TEXT
-
-#endif
diff --git a/drivers/staging/crystalhd/crystalhd.h b/drivers/staging/crystalhd/crystalhd.h
new file mode 100644
index 0000000..3f4d795
--- /dev/null
+++ b/drivers/staging/crystalhd/crystalhd.h
@@ -0,0 +1,14 @@
+#ifndef _CRYSTALHD_H_
+#define _CRYSTALHD_H_
+
+#include <asm/system.h>
+#include "bc_dts_defs.h"
+#include "crystalhd_misc.h"
+#include "bc_dts_glob_lnx.h"
+#include "crystalhd_hw.h"
+#include "crystalhd_cmds.h"
+#include "crystalhd_lnx.h"
+#include "bcm_70012_regs.h"
+#include "crystalhd_fw_if.h"
+
+#endif
diff --git a/drivers/staging/crystalhd/crystalhd_cmds.c b/drivers/staging/crystalhd/crystalhd_cmds.c
index 3735ed3..05fe787 100644
--- a/drivers/staging/crystalhd/crystalhd_cmds.c
+++ b/drivers/staging/crystalhd/crystalhd_cmds.c
@@ -24,8 +24,7 @@
  * along with this driver.  If not, see <http://www.gnu.org/licenses/>.
  **********************************************************************/
 
-#include "crystalhd_cmds.h"
-#include "crystalhd_hw.h"
+#include "crystalhd.h"
 
 static struct crystalhd_user *bc_cproc_get_uid(struct crystalhd_cmd *ctx)
 {
diff --git a/drivers/staging/crystalhd/crystalhd_cmds.h b/drivers/staging/crystalhd/crystalhd_cmds.h
index f0a2796..4066ba3 100644
--- a/drivers/staging/crystalhd/crystalhd_cmds.h
+++ b/drivers/staging/crystalhd/crystalhd_cmds.h
@@ -33,8 +33,8 @@
  *        from _dts_glob and dts_defs etc.. which are defined for
  *        windows.
  */
-#include "crystalhd_misc.h"
-#include "crystalhd_hw.h"
+
+#include "crystalhd.h"
 
 enum crystalhd_state {
 	BC_LINK_INVALID		= 0x00,
diff --git a/drivers/staging/crystalhd/crystalhd_hw.c b/drivers/staging/crystalhd/crystalhd_hw.c
index 5acf39e..e617d2f 100644
--- a/drivers/staging/crystalhd/crystalhd_hw.c
+++ b/drivers/staging/crystalhd/crystalhd_hw.c
@@ -22,10 +22,11 @@
  * along with this driver.  If not, see <http://www.gnu.org/licenses/>.
  **********************************************************************/
 
+#include "crystalhd.h"
+
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
-#include "crystalhd_hw.h"
 
 /* Functions internal to this file */
 
@@ -766,7 +767,7 @@
 	crystalhd_hw_dump_desc(desc, last_desc_ix, 1);
 
 	if (count != xfr_sz) {
-		BCMLOG_ERR("interal error sz curr:%x exp:%x\n", count, xfr_sz);
+		BCMLOG_ERR("internal error sz curr:%x exp:%x\n", count, xfr_sz);
 		return BC_STS_ERROR;
 	}
 
@@ -868,8 +869,7 @@
 
 	BCMLOG(BCMLOG_DBG, "Stopping TX DMA Engine..\n");
 
-	/* FIXME: jarod: invert dma_ctrl and check bit? or are there missing parens? */
-	if (!dma_cntrl & DMA_START_BIT) {
+	if (!(dma_cntrl & DMA_START_BIT)) {
 		BCMLOG(BCMLOG_DBG, "Already Stopped\n");
 		return BC_STS_SUCCESS;
 	}
@@ -1628,7 +1628,6 @@
 	uint32_t fw_sig_len = 36;
 	uint32_t dram_offset = BC_FWIMG_ST_ADDR, sig_reg;
 
-	BCMLOG_ENTER;
 
 	if (!adp || !buffer || !sz) {
 		BCMLOG_ERR("Invalid Params.\n");
@@ -1725,8 +1724,6 @@
 
 	crystalhd_create_event(&fw_cmd_event);
 
-	BCMLOG_ENTER;
-
 	if (!hw || !fw_cmd) {
 		BCMLOG_ERR("Invalid Arguments\n");
 		return BC_STS_INV_ARG;
diff --git a/drivers/staging/crystalhd/crystalhd_hw.h b/drivers/staging/crystalhd/crystalhd_hw.h
index 3efbf9d..2d0e6c6 100644
--- a/drivers/staging/crystalhd/crystalhd_hw.h
+++ b/drivers/staging/crystalhd/crystalhd_hw.h
@@ -27,8 +27,7 @@
 #ifndef _CRYSTALHD_HW_H_
 #define _CRYSTALHD_HW_H_
 
-#include "crystalhd_misc.h"
-#include "crystalhd_fw_if.h"
+#include "crystalhd.h"
 
 /* HW constants..*/
 #define DMA_ENGINE_CNT		2
diff --git a/drivers/staging/crystalhd/crystalhd_lnx.c b/drivers/staging/crystalhd/crystalhd_lnx.c
index 7e0c199..d9e3d61 100644
--- a/drivers/staging/crystalhd/crystalhd_lnx.c
+++ b/drivers/staging/crystalhd/crystalhd_lnx.c
@@ -15,10 +15,11 @@
   along with this driver.  If not, see <http://www.gnu.org/licenses/>.
 ***************************************************************************/
 
+#include "crystalhd.h"
+
 #include <linux/mutex.h>
 #include <linux/slab.h>
 
-#include "crystalhd_lnx.h"
 
 static DEFINE_MUTEX(chd_dec_mutex);
 static struct class *crystalhd_class;
@@ -298,7 +299,6 @@
 	enum BC_STATUS sts = BC_STS_SUCCESS;
 	struct crystalhd_user *uc = NULL;
 
-	BCMLOG_ENTER;
 	if (!adp) {
 		BCMLOG_ERR("Invalid adp\n");
 		return -EINVAL;
@@ -327,7 +327,6 @@
 	struct crystalhd_adp *adp = chd_get_adp();
 	struct crystalhd_user *uc;
 
-	BCMLOG_ENTER;
 	if (!adp) {
 		BCMLOG_ERR("Invalid adp\n");
 		return -EINVAL;
@@ -513,8 +512,6 @@
 	struct crystalhd_adp *pinfo;
 	enum BC_STATUS sts = BC_STS_SUCCESS;
 
-	BCMLOG_ENTER;
-
 	pinfo = pci_get_drvdata(pdev);
 	if (!pinfo) {
 		BCMLOG_ERR("could not get adp\n");
diff --git a/drivers/staging/crystalhd/crystalhd_lnx.h b/drivers/staging/crystalhd/crystalhd_lnx.h
index a2b5a56..a81f929 100644
--- a/drivers/staging/crystalhd/crystalhd_lnx.h
+++ b/drivers/staging/crystalhd/crystalhd_lnx.h
@@ -1,7 +1,7 @@
 /***************************************************************************
  * Copyright (c) 2005-2009, Broadcom Corporation.
  *
- *  Name: crystalhd_lnx . c
+ *  Name: crystalhd_lnx . h
  *
  *  Description:
  *		BCM70012 Linux driver
@@ -48,11 +48,10 @@
 #include <asm/system.h>
 #include <linux/uaccess.h>
 
-#include "crystalhd_cmds.h"
+#include "crystalhd.h"
 
 #define CRYSTAL_HD_NAME		"Broadcom Crystal HD Decoder (BCM70012) Driver"
 
-
 /* OS specific PCI information structure and adapter information. */
 struct crystalhd_adp {
 	/* Hardware borad/PCI specifics */
diff --git a/drivers/staging/crystalhd/crystalhd_misc.c b/drivers/staging/crystalhd/crystalhd_misc.c
index 5fa0c6e..b3a6378 100644
--- a/drivers/staging/crystalhd/crystalhd_misc.c
+++ b/drivers/staging/crystalhd/crystalhd_misc.c
@@ -24,10 +24,9 @@
  * along with this driver.  If not, see <http://www.gnu.org/licenses/>.
  **********************************************************************/
 
-#include <linux/slab.h>
+#include "crystalhd.h"
 
-#include "crystalhd_misc.h"
-#include "crystalhd_lnx.h"
+#include <linux/slab.h>
 
 uint32_t g_linklog_level;
 
diff --git a/drivers/staging/crystalhd/crystalhd_misc.h b/drivers/staging/crystalhd/crystalhd_misc.h
index 4d61723..84c8793 100644
--- a/drivers/staging/crystalhd/crystalhd_misc.h
+++ b/drivers/staging/crystalhd/crystalhd_misc.h
@@ -28,6 +28,8 @@
 #ifndef _CRYSTALHD_MISC_H_
 #define _CRYSTALHD_MISC_H_
 
+#include "crystalhd.h"
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -35,8 +37,6 @@
 #include <linux/ioctl.h>
 #include <linux/dma-mapping.h>
 #include <linux/sched.h>
-#include <asm/system.h>
-#include "bc_dts_glob_lnx.h"
 
 /* Global log level variable defined in crystal_misc.c file */
 extern uint32_t g_linklog_level;
@@ -200,29 +200,21 @@
 	BCMLOG_INFO		= 0x00000001,	/* Generic informational */
 	BCMLOG_DBG		= 0x00000002,	/* First level Debug info */
 	BCMLOG_SSTEP		= 0x00000004,	/* Stepping information */
-	BCMLOG_ENTER_LEAVE	= 0x00000008,	/* stack tracking */
 };
 
-#define BCMLOG_ENTER				\
-if (g_linklog_level & BCMLOG_ENTER_LEAVE) {	\
-	printk(KERN_DEBUG "Entered %s\n", __func__);	\
-}
 
-#define BCMLOG_LEAVE				\
-if (g_linklog_level & BCMLOG_ENTER_LEAVE) {	\
-	printk(KERN_DEBUG "Leaving %s\n", __func__);	\
-}
+#define BCMLOG(trace, fmt, args...)	\
+do {					\
+	if (g_linklog_level & trace)	\
+		printk(fmt, ##args);	\
+} while (0)
 
-#define BCMLOG(trace, fmt, args...)		\
-if (g_linklog_level & trace) {			\
-	printk(fmt, ##args);			\
-}
 
-#define BCMLOG_ERR(fmt, args...)					\
-do {									\
-	if (g_linklog_level & BCMLOG_ERROR) {				\
-		printk(KERN_ERR "*ERR*:%s:%d: "fmt, __FILE__, __LINE__, ##args);	\
-	}								\
-} while (0);
+#define BCMLOG_ERR(fmt, args...)				\
+do {								\
+	if (g_linklog_level & BCMLOG_ERROR)			\
+		printk(KERN_ERR "*ERR*:%s:%d: "fmt,		\
+				__FILE__, __LINE__, ##args);	\
+} while (0)
 
 #endif
diff --git a/drivers/staging/et131x/README b/drivers/staging/et131x/README
index 3458aa7..8265723 100644
--- a/drivers/staging/et131x/README
+++ b/drivers/staging/et131x/README
@@ -11,6 +11,6 @@
 	- Use of kmem_cache seems a bit unusual
 
 Please send patches to:
-	Greg Kroah-Hartman <gregkh@suse.de>
+	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 	Mark Einon <mark.einon@gmail.com>
 
diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c
index 2c4069f..3f919ba 100644
--- a/drivers/staging/et131x/et131x.c
+++ b/drivers/staging/et131x/et131x.c
@@ -802,7 +802,7 @@
 	/* THIS IS A WORKAROUND:
 	 * I need to call this function twice to get my card in a
 	 * LG M1 Express Dual running. I tried also a msleep before this
-	 * function, because I thougth there could be some time condidions
+	 * function, because I thought there could be some time condidions
 	 * but it didn't work. Call the whole function twice also work.
 	 */
 	if (pci_read_config_byte(pdev, ET1310_PCI_EEPROM_STATUS, &eestatus)) {
@@ -987,7 +987,7 @@
 	writel(station1, &macregs->station_addr_1);
 	writel(station2, &macregs->station_addr_2);
 
-	/* Max ethernet packet in bytes that will passed by the mac without
+	/* Max ethernet packet in bytes that will be passed by the mac without
 	 * being truncated.  Allow the MAC to pass 4 more than our max packet
 	 * size.  This is 4 for the Ethernet CRC.
 	 *
@@ -3109,7 +3109,7 @@
 		skb->protocol = eth_type_trans(skb, adapter->netdev);
 		skb->ip_summed = CHECKSUM_NONE;
 
-		netif_rx(skb);
+		netif_rx_ni(skb);
 	} else {
 		rfd->len = 0;
 	}
@@ -4413,7 +4413,7 @@
 
 /**
  * et131x_down - Bring down the device
- * @netdev: device to be broght down
+ * @netdev: device to be brought down
  */
 static void et131x_down(struct net_device *netdev)
 {
@@ -5177,7 +5177,7 @@
 
 	/* Make sure the requested MAC is valid */
 	if (!is_valid_ether_addr(address->sa_data))
-		return -EINVAL;
+		return -EADDRNOTAVAIL;
 
 	et131x_disable_txrx(netdev);
 	et131x_handle_send_interrupt(adapter);
diff --git a/drivers/staging/et131x/et131x.h b/drivers/staging/et131x/et131x.h
index 7eed3c8..864379b 100644
--- a/drivers/staging/et131x/et131x.h
+++ b/drivers/staging/et131x/et131x.h
@@ -596,7 +596,7 @@
  * structure for tx test reg in txmac address map
  * located at address 0x3014
  * 31-17: unused
- * 16: reserved1
+ * 16: reserved
  * 15: txtest_en
  * 14-11: unused
  * 10-0: txq test pointer
@@ -1485,7 +1485,7 @@
  *	3:	reserved
  *	2:	ignore_10g_fr
  *	1:	reserved
- *	0:	preamble_supress_en
+ *	0:	preamble_suppress_en
  */
 
 /* MI Register 22: PHY Configuration Reg(0x16)
diff --git a/drivers/staging/frontier/alphatrack.c b/drivers/staging/frontier/alphatrack.c
index d8efed6..3bf0f40e 100644
--- a/drivers/staging/frontier/alphatrack.c
+++ b/drivers/staging/frontier/alphatrack.c
@@ -450,7 +450,7 @@
 /**
  *	usb_alphatrack_poll
  */
-static unsigned int usb_alphatrack_poll(struct file *file, poll_table * wait)
+static unsigned int usb_alphatrack_poll(struct file *file, poll_table *wait)
 {
 	struct usb_alphatrack *dev;
 	unsigned int mask = 0;
diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c
index cf47a5d..29e99bb 100644
--- a/drivers/staging/frontier/tranzport.c
+++ b/drivers/staging/frontier/tranzport.c
@@ -471,7 +471,7 @@
 /**
  *	usb_tranzport_poll
  */
-static unsigned int usb_tranzport_poll(struct file *file, poll_table * wait)
+static unsigned int usb_tranzport_poll(struct file *file, poll_table *wait)
 {
 	struct usb_tranzport *dev;
 	unsigned int mask = 0;
diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c
index 7faeada..71aaad3 100644
--- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c
+++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c
@@ -29,10 +29,10 @@
 #define FT1000_PROC "ft1000"
 #define MAX_FILE_LEN 255
 
-#define PUTM_TO_PAGE(len,page,args...) \
+#define PUTM_TO_PAGE(len, page, args...) \
 	len += snprintf(page+len, PAGE_SIZE - len, args)
 
-#define PUTX_TO_PAGE(len,page,message,size,var) \
+#define PUTX_TO_PAGE(len, page, message, size, var) \
 	len += snprintf(page+len, PAGE_SIZE - len, message); \
 	for(i = 0; i < (size - 1); i++) \
 	{ \
@@ -40,7 +40,7 @@
 	} \
 	len += snprintf(page+len, PAGE_SIZE - len, "%02x\n", var[i])
 
-#define PUTD_TO_PAGE(len,page,message,size,var) \
+#define PUTD_TO_PAGE(len, page, message, size, var) \
 	len += snprintf(page+len, PAGE_SIZE - len, message); \
 	for(i = 0; i < (size - 1); i++) \
 	{ \
diff --git a/drivers/staging/hv/Kconfig b/drivers/staging/hv/Kconfig
deleted file mode 100644
index 60ac479..0000000
--- a/drivers/staging/hv/Kconfig
+++ /dev/null
@@ -1,5 +0,0 @@
-config HYPERV_STORAGE
-	tristate "Microsoft Hyper-V virtual storage driver"
-	depends on HYPERV && SCSI
-	help
-	 Select this option to enable the Hyper-V virtual storage driver.
diff --git a/drivers/staging/hv/Makefile b/drivers/staging/hv/Makefile
deleted file mode 100644
index af95a6b..0000000
--- a/drivers/staging/hv/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_HYPERV_STORAGE)	+= hv_storvsc.o
-
-hv_storvsc-y := storvsc_drv.o
diff --git a/drivers/staging/hv/TODO b/drivers/staging/hv/TODO
deleted file mode 100644
index dea7d92..0000000
--- a/drivers/staging/hv/TODO
+++ /dev/null
@@ -1,5 +0,0 @@
-TODO:
-	- audit the scsi driver
-
-Please send patches for this code to Greg Kroah-Hartman <gregkh@suse.de>,
-Haiyang Zhang <haiyangz@microsoft.com>, and K. Y. Srinivasan <kys@microsoft.com>
diff --git a/drivers/staging/iio/Documentation/device.txt b/drivers/staging/iio/Documentation/device.txt
index 1abb80c..8926f24 100644
--- a/drivers/staging/iio/Documentation/device.txt
+++ b/drivers/staging/iio/Documentation/device.txt
@@ -62,7 +62,7 @@
 	An optional associated buffer.
 - indio_dev->pollfunc:
 	Poll function related elements. This controls what occurs when a trigger
-	to which this device is attached sends and event.
+	to which this device is attached sends an event.
 - indio_dev->channels:
 	Specification of device channels. Most attributes etc are built
 	form this spec.
diff --git a/drivers/staging/iio/Documentation/iio_event_monitor.c b/drivers/staging/iio/Documentation/iio_event_monitor.c
new file mode 100644
index 0000000..0d21a27
--- /dev/null
+++ b/drivers/staging/iio/Documentation/iio_event_monitor.c
@@ -0,0 +1,241 @@
+/* Industrialio event test code.
+ *
+ * Copyright (c) 2011-2012 Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * 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.
+ *
+ * This program is primarily intended as an example application.
+ * Reads the current buffer setup from sysfs and starts a short capture
+ * from the specified device, pretty printing the result after appropriate
+ * conversion.
+ *
+ * Usage:
+ *	iio_event_monitor <device_name>
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "iio_utils.h"
+#include "../events.h"
+
+static const char * const iio_chan_type_name_spec[] = {
+	[IIO_VOLTAGE] = "voltage",
+	[IIO_CURRENT] = "current",
+	[IIO_POWER] = "power",
+	[IIO_ACCEL] = "accel",
+	[IIO_ANGL_VEL] = "anglvel",
+	[IIO_MAGN] = "magn",
+	[IIO_LIGHT] = "illuminance",
+	[IIO_INTENSITY] = "intensity",
+	[IIO_PROXIMITY] = "proximity",
+	[IIO_TEMP] = "temp",
+	[IIO_INCLI] = "incli",
+	[IIO_ROT] = "rot",
+	[IIO_ANGL] = "angl",
+	[IIO_TIMESTAMP] = "timestamp",
+	[IIO_CAPACITANCE] = "capacitance",
+};
+
+static const char * const iio_ev_type_text[] = {
+	[IIO_EV_TYPE_THRESH] = "thresh",
+	[IIO_EV_TYPE_MAG] = "mag",
+	[IIO_EV_TYPE_ROC] = "roc",
+	[IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
+	[IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
+};
+
+static const char * const iio_ev_dir_text[] = {
+	[IIO_EV_DIR_EITHER] = "either",
+	[IIO_EV_DIR_RISING] = "rising",
+	[IIO_EV_DIR_FALLING] = "falling"
+};
+
+static const char * const iio_modifier_names[] = {
+	[IIO_MOD_X] = "x",
+	[IIO_MOD_Y] = "y",
+	[IIO_MOD_Z] = "z",
+	[IIO_MOD_LIGHT_BOTH] = "both",
+	[IIO_MOD_LIGHT_IR] = "ir",
+};
+
+static bool event_is_known(struct iio_event_data *event)
+{
+	enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id);
+	enum iio_modifier mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id);
+	enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id);
+	enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id);
+
+	switch (type) {
+	case IIO_VOLTAGE:
+	case IIO_CURRENT:
+	case IIO_POWER:
+	case IIO_ACCEL:
+	case IIO_ANGL_VEL:
+	case IIO_MAGN:
+	case IIO_LIGHT:
+	case IIO_INTENSITY:
+	case IIO_PROXIMITY:
+	case IIO_TEMP:
+	case IIO_INCLI:
+	case IIO_ROT:
+	case IIO_ANGL:
+	case IIO_TIMESTAMP:
+	case IIO_CAPACITANCE:
+		break;
+	default:
+		return false;
+	}
+
+	switch (mod) {
+	case IIO_NO_MOD:
+	case IIO_MOD_X:
+	case IIO_MOD_Y:
+	case IIO_MOD_Z:
+	case IIO_MOD_LIGHT_BOTH:
+	case IIO_MOD_LIGHT_IR:
+		break;
+	default:
+		return false;
+	}
+
+	switch (ev_type) {
+	case IIO_EV_TYPE_THRESH:
+	case IIO_EV_TYPE_MAG:
+	case IIO_EV_TYPE_ROC:
+	case IIO_EV_TYPE_THRESH_ADAPTIVE:
+	case IIO_EV_TYPE_MAG_ADAPTIVE:
+		break;
+	default:
+		return false;
+	}
+
+	switch (dir) {
+	case IIO_EV_DIR_EITHER:
+	case IIO_EV_DIR_RISING:
+	case IIO_EV_DIR_FALLING:
+		break;
+	default:
+		return false;
+	}
+
+	return true;
+}
+
+static void print_event(struct iio_event_data *event)
+{
+	enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id);
+	enum iio_modifier mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id);
+	enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id);
+	enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id);
+	int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event->id);
+	int chan2 = IIO_EVENT_CODE_EXTRACT_CHAN2(event->id);
+	bool diff = IIO_EVENT_CODE_EXTRACT_DIFF(event->id);
+
+	if (!event_is_known(event)) {
+		printf("Unknown event: time: %lld, id: %llx\n",
+				event->timestamp, event->id);
+		return;
+	}
+
+	printf("Event: time: %lld, ", event->timestamp);
+
+	if (mod != IIO_NO_MOD) {
+		printf("type: %s(%s), ",
+			iio_chan_type_name_spec[type],
+			iio_modifier_names[mod]);
+	} else {
+		printf("type: %s, ",
+			iio_chan_type_name_spec[type]);
+	}
+
+	if (diff && chan >= 0 && chan2 >= 0)
+		printf("channel: %d-%d, ", chan, chan2);
+	else if (chan >= 0)
+		printf("channel: %d, ", chan);
+
+	printf("evtype: %s, direction: %s\n",
+		iio_ev_type_text[ev_type],
+		iio_ev_dir_text[dir]);
+}
+
+int main(int argc, char **argv)
+{
+	struct iio_event_data event;
+	const char *device_name;
+	char *chrdev_name;
+	int ret;
+	int dev_num;
+	int fd, event_fd;
+
+	if (argc <= 1) {
+		printf("Usage: %s <device_name>\n", argv[0]);
+		return -1;
+	}
+
+	device_name = argv[1];
+
+	dev_num = find_type_by_name(device_name, "iio:device");
+	if (dev_num >= 0) {
+		printf("Found IIO device with name %s with device number %d\n",
+			device_name, dev_num);
+		ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num);
+		if (ret < 0) {
+			ret = -ENOMEM;
+			goto error_ret;
+		}
+	} else {
+		/* If we can't find a IIO device by name assume device_name is a
+		   IIO chrdev */
+		chrdev_name = strdup(device_name);
+	}
+
+	fd = open(chrdev_name, 0);
+	if (fd == -1) {
+		fprintf(stdout, "Failed to open %s\n", chrdev_name);
+		ret = -errno;
+		goto error_free_chrdev_name;
+	}
+
+	ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd);
+
+	close(fd);
+
+	if (ret == -1 || event_fd == -1) {
+		fprintf(stdout, "Failed to retrieve event fd\n");
+		ret = -errno;
+		goto error_free_chrdev_name;
+	}
+
+	while (true) {
+		ret = read(event_fd, &event, sizeof(event));
+		if (ret == -1) {
+			if (errno == EAGAIN) {
+				printf("nothing available\n");
+				continue;
+			} else {
+				perror("Failed to read event from device");
+				ret = -errno;
+				break;
+			}
+		}
+
+		print_event(&event);
+	}
+
+	close(event_fd);
+error_free_chrdev_name:
+	free(chrdev_name);
+error_ret:
+	return ret;
+}
diff --git a/drivers/staging/iio/Documentation/inkernel.txt b/drivers/staging/iio/Documentation/inkernel.txt
new file mode 100644
index 0000000..a05823e
--- /dev/null
+++ b/drivers/staging/iio/Documentation/inkernel.txt
@@ -0,0 +1,58 @@
+Industrial I/O Subsystem in kernel consumers.
+
+The IIO subsystem can act as a layer under other elements of the kernel
+providing a means of obtaining ADC type readings or of driving DAC type
+signals.  The functionality supported will grow as use cases arise.
+
+Describing the channel mapping (iio/machine.h)
+
+Channel associations are described using:
+
+struct iio_map {
+	const char *adc_channel_label;
+	const char *consumer_dev_name;
+	const char *consumer_channel;
+};
+
+adc_channel_label identifies the channel on the IIO device by being
+matched against the datasheet_name field of the iio_chan_spec.
+
+consumer_dev_name allows identification of the consumer device.
+This are then used to find the channel mapping from the consumer device (see
+below).
+
+Finally consumer_channel is a string identifying the channel to the consumer.
+(Perhaps 'battery_voltage' or similar).
+
+An array of these structures is then passed to the IIO driver.
+
+Supporting in kernel interfaces in the driver (driver.h)
+
+The driver must provide datasheet_name values for its channels and
+must pass the iio_map structures and a pointer to its own iio_dev structure
+ on to the core via a call to iio_map_array_register.  On removal,
+iio_map_array_unregister reverses this process.
+
+The result of this is that the IIO core now has all the information needed
+to associate a given channel with the consumer requesting it.
+
+Acting as an IIO consumer (consumer.h)
+
+The consumer first has to obtain an iio_channel structure from the core
+by calling iio_channel_get().  The correct channel is identified by:
+
+* matching dev or dev_name against consumer_dev and consumer_dev_name
+* matching consumer_channel against consumer_channel in the map
+
+There are then a number of functions that can be used to get information
+about this channel such as it's current reading.
+
+e.g.
+iio_st_read_channel_raw() - get a reading
+iio_st_read_channel_type() - get the type of channel
+
+There is also provision for retrieving all of the channels associated
+with a given consumer.  This is useful for generic drivers such as
+iio_hwmon where the number and naming of channels is not known by the
+consumer driver.  To do this, use iio_st_channel_get_all.
+
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index 90162aa..fe15867 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -11,6 +11,13 @@
 	  number of different physical interfaces (i2c, spi, etc). See
 	  drivers/staging/iio/Documentation for more information.
 if IIO
+config IIO_ST_HWMON
+	tristate "Hwmon driver that uses channels specified via iio maps"
+	depends on HWMON
+	help
+	  This is a platform driver that in combination with a suitable
+	  map allows IIO devices to provide  basic hwmon functionality
+	  for those channels specified in the map.
 
 config IIO_BUFFER
 	bool "Enable buffer support within IIO"
@@ -79,7 +86,7 @@
        help
 	 Driver intended mainly as documentation for how to write
 	 a driver. May also be useful for testing userspace code
-	 without hardward.
+	 without hardware.
 
 if IIO_SIMPLE_DUMMY
 
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index 1340aea..5075291 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -3,7 +3,7 @@
 #
 
 obj-$(CONFIG_IIO) += industrialio.o
-industrialio-y := industrialio-core.o
+industrialio-y := industrialio-core.o industrialio-event.o inkern.o
 industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
 industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
 
@@ -17,6 +17,8 @@
 
 obj-$(CONFIG_IIO_DUMMY_EVGEN) += iio_dummy_evgen.o
 
+obj-$(CONFIG_IIO_ST_HWMON) += iio_hwmon.o
+
 obj-y += accel/
 obj-y += adc/
 obj-y += addac/
diff --git a/drivers/staging/iio/accel/adis16201_ring.c b/drivers/staging/iio/accel/adis16201_ring.c
index 26c610f..97f9e6b 100644
--- a/drivers/staging/iio/accel/adis16201_ring.c
+++ b/drivers/staging/iio/accel/adis16201_ring.c
@@ -115,9 +115,7 @@
 		return ret;
 	}
 	indio_dev->buffer = ring;
-	/* Effectively select the ring buffer implementation */
 	ring->scan_timestamp = true;
-	ring->access = &ring_sw_access_funcs;
 	indio_dev->setup_ops = &adis16201_ring_setup_ops;
 
 	indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
diff --git a/drivers/staging/iio/accel/adis16203_ring.c b/drivers/staging/iio/accel/adis16203_ring.c
index 064640d..6a8963d 100644
--- a/drivers/staging/iio/accel/adis16203_ring.c
+++ b/drivers/staging/iio/accel/adis16203_ring.c
@@ -117,9 +117,7 @@
 		return ret;
 	}
 	indio_dev->buffer = ring;
-	/* Effectively select the ring buffer implementation */
 	ring->scan_timestamp = true;
-	ring->access = &ring_sw_access_funcs;
 	indio_dev->setup_ops = &adis16203_ring_setup_ops;
 
 	indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
diff --git a/drivers/staging/iio/accel/adis16204_ring.c b/drivers/staging/iio/accel/adis16204_ring.c
index 4081179..5c8ab73 100644
--- a/drivers/staging/iio/accel/adis16204_ring.c
+++ b/drivers/staging/iio/accel/adis16204_ring.c
@@ -112,8 +112,6 @@
 		return ret;
 	}
 	indio_dev->buffer = ring;
-	/* Effectively select the ring buffer implementation */
-	ring->access = &ring_sw_access_funcs;
 	ring->scan_timestamp = true;
 	indio_dev->setup_ops = &adis16204_ring_setup_ops;
 
diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c
index 2a6fd334..57254b6 100644
--- a/drivers/staging/iio/accel/adis16209_ring.c
+++ b/drivers/staging/iio/accel/adis16209_ring.c
@@ -113,8 +113,6 @@
 		return ret;
 	}
 	indio_dev->buffer = ring;
-	/* Effectively select the ring buffer implementation */
-	ring->access = &ring_sw_access_funcs;
 	ring->scan_timestamp = true;
 	indio_dev->setup_ops = &adis16209_ring_setup_ops;
 
diff --git a/drivers/staging/iio/accel/adis16240_ring.c b/drivers/staging/iio/accel/adis16240_ring.c
index e23622d..43ba84e 100644
--- a/drivers/staging/iio/accel/adis16240_ring.c
+++ b/drivers/staging/iio/accel/adis16240_ring.c
@@ -110,8 +110,6 @@
 		return ret;
 	}
 	indio_dev->buffer = ring;
-	/* Effectively select the ring buffer implementation */
-	ring->access = &ring_sw_access_funcs;
 	ring->scan_timestamp = true;
 	indio_dev->setup_ops = &adis16240_ring_setup_ops;
 
diff --git a/drivers/staging/iio/accel/lis3l02dq.h b/drivers/staging/iio/accel/lis3l02dq.h
index 2db383f..ae5f225 100644
--- a/drivers/staging/iio/accel/lis3l02dq.h
+++ b/drivers/staging/iio/accel/lis3l02dq.h
@@ -187,12 +187,10 @@
 #ifdef CONFIG_LIS3L02DQ_BUF_RING_SW
 #define lis3l02dq_free_buf iio_sw_rb_free
 #define lis3l02dq_alloc_buf iio_sw_rb_allocate
-#define lis3l02dq_access_funcs ring_sw_access_funcs
 #endif
 #ifdef CONFIG_LIS3L02DQ_BUF_KFIFO
 #define lis3l02dq_free_buf iio_kfifo_free
 #define lis3l02dq_alloc_buf iio_kfifo_allocate
-#define lis3l02dq_access_funcs kfifo_access_funcs
 #endif
 irqreturn_t lis3l02dq_data_rdy_trig_poll(int irq, void *private);
 #define lis3l02dq_th lis3l02dq_data_rdy_trig_poll
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index 98c5c92..0fc3973 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -239,7 +239,7 @@
 	__lis3l02dq_write_data_ready_config(&indio_dev->dev, state);
 	if (state == false) {
 		/*
-		 * A possible quirk with teh handler is currently worked around
+		 * A possible quirk with the handler is currently worked around
 		 *  by ensuring outstanding read events are cleared.
 		 */
 		ret = lis3l02dq_read_all(indio_dev, NULL);
@@ -406,8 +406,6 @@
 		return -ENOMEM;
 
 	indio_dev->buffer = buffer;
-	/* Effectively select the buffer implementation */
-	indio_dev->buffer->access = &lis3l02dq_access_funcs;
 
 	buffer->scan_timestamp = true;
 	indio_dev->setup_ops = &lis3l02dq_buffer_setup_ops;
diff --git a/drivers/staging/iio/accel/sca3000.h b/drivers/staging/iio/accel/sca3000.h
index ad38dd9..131daac 100644
--- a/drivers/staging/iio/accel/sca3000.h
+++ b/drivers/staging/iio/accel/sca3000.h
@@ -136,7 +136,7 @@
 #define SCA3000_INT_MASK_ACTIVE_HIGH		0x01
 #define SCA3000_INT_MASK_ACTIVE_LOW		0x00
 
-/* Values of mulipexed registers (write to ctrl_data after select) */
+/* Values of multiplexed registers (write to ctrl_data after select) */
 #define SCA3000_REG_ADDR_CTRL_DATA		0x22
 
 /* Measurement modes available on some sca3000 series chips. Code assumes others
diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index d9decea..592eabd 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -193,4 +193,13 @@
 	  Say yes here to include ring buffer support in the MAX1363
 	  ADC driver.
 
+config LPC32XX_ADC
+	tristate "NXP LPC32XX ADC"
+	depends on ARCH_LPC32XX && !TOUCHSCREEN_LPC32XX
+	help
+	  Say yes here to build support for the integrated ADC inside the
+	  LPC32XX SoC. Note that this feature uses the same hardware as the
+	  touchscreen driver, so you can only select one of the two drivers
+	  (lpc32xx_adc or lpc32xx_ts). Provides direct access via sysfs.
+
 endmenu
diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
index ceee7f3..f83ab95 100644
--- a/drivers/staging/iio/adc/Makefile
+++ b/drivers/staging/iio/adc/Makefile
@@ -37,3 +37,4 @@
 obj-$(CONFIG_ADT7310) += adt7310.o
 obj-$(CONFIG_ADT7410) += adt7410.o
 obj-$(CONFIG_AD7280) += ad7280a.o
+obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index 45f4504..9fd6d63 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -561,8 +561,6 @@
 		ret = -ENOMEM;
 		goto error_ret;
 	}
-	/* Effectively select the ring buffer implementation */
-	indio_dev->buffer->access = &ring_sw_access_funcs;
 	indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
 						 &ad7192_trigger_handler,
 						 IRQF_ONESHOT,
@@ -824,25 +822,20 @@
 	NULL
 };
 
-static umode_t ad7192_attr_is_visible(struct kobject *kobj,
-				     struct attribute *attr, int n)
-{
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct ad7192_state *st = iio_priv(indio_dev);
-
-	umode_t mode = attr->mode;
-
-	if ((st->devid != ID_AD7195) &&
-		(attr == &iio_dev_attr_ac_excitation_en.dev_attr.attr))
-		mode = 0;
-
-	return mode;
-}
-
 static const struct attribute_group ad7192_attribute_group = {
 	.attrs = ad7192_attributes,
-	.is_visible = ad7192_attr_is_visible,
+};
+
+static struct attribute *ad7195_attributes[] = {
+	&iio_dev_attr_sampling_frequency.dev_attr.attr,
+	&iio_dev_attr_in_v_m_v_scale_available.dev_attr.attr,
+	&iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
+	&iio_dev_attr_bridge_switch_en.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group ad7195_attribute_group = {
+	.attrs = ad7195_attributes,
 };
 
 static int ad7192_read_raw(struct iio_dev *indio_dev,
@@ -972,6 +965,15 @@
 	.driver_module = THIS_MODULE,
 };
 
+static const struct iio_info ad7195_info = {
+	.read_raw = &ad7192_read_raw,
+	.write_raw = &ad7192_write_raw,
+	.write_raw_get_fmt = &ad7192_write_raw_get_fmt,
+	.attrs = &ad7195_attribute_group,
+	.validate_trigger = ad7192_validate_trigger,
+	.driver_module = THIS_MODULE,
+};
+
 #define AD7192_CHAN_DIFF(_chan, _chan2, _name, _address, _si)		\
 	{ .type = IIO_VOLTAGE,						\
 	  .differential = 1,						\
@@ -1064,7 +1066,10 @@
 	indio_dev->channels = ad7192_channels;
 	indio_dev->num_channels = ARRAY_SIZE(ad7192_channels);
 	indio_dev->available_scan_masks = st->available_scan_masks;
-	indio_dev->info = &ad7192_info;
+	if (st->devid == ID_AD7195)
+		indio_dev->info = &ad7195_info;
+	else
+		indio_dev->info = &ad7192_info;
 
 	for (i = 0; i < indio_dev->num_channels; i++)
 		st->available_scan_masks[i] = (1 << i) | (1 <<
diff --git a/drivers/staging/iio/adc/ad7291.c b/drivers/staging/iio/adc/ad7291.c
index 0a13616..81d6b61 100644
--- a/drivers/staging/iio/adc/ad7291.c
+++ b/drivers/staging/iio/adc/ad7291.c
@@ -321,7 +321,7 @@
 
 	switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
 	case IIO_VOLTAGE:
-		reg = ad7291_limit_regs[IIO_EVENT_CODE_EXTRACT_NUM(event_code)]
+		reg = ad7291_limit_regs[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)]
 			[!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
 			   IIO_EV_DIR_RISING)];
 
@@ -359,7 +359,7 @@
 	case IIO_VOLTAGE:
 		if (val > AD7291_VALUE_MASK || val < 0)
 			return -EINVAL;
-		reg = ad7291_limit_regs[IIO_EVENT_CODE_EXTRACT_NUM(event_code)]
+		reg = ad7291_limit_regs[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)]
 			[!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
 			   IIO_EV_DIR_RISING)];
 		return ad7291_i2c_write(chip, reg, val);
@@ -386,7 +386,7 @@
 	switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
 	case IIO_VOLTAGE:
 		if (chip->c_mask &
-		    (1 << (15 - IIO_EVENT_CODE_EXTRACT_NUM(event_code))))
+		    (1 << (15 - IIO_EVENT_CODE_EXTRACT_CHAN(event_code))))
 			return 1;
 		else
 			return 0;
@@ -418,12 +418,12 @@
 	switch (IIO_EVENT_CODE_EXTRACT_TYPE(event_code)) {
 	case IIO_VOLTAGE:
 		if ((!state) && (chip->c_mask & (1 << (15 -
-				IIO_EVENT_CODE_EXTRACT_NUM(event_code)))))
-			chip->c_mask &= ~(1 << (15 - IIO_EVENT_CODE_EXTRACT_NUM
+				IIO_EVENT_CODE_EXTRACT_CHAN(event_code)))))
+			chip->c_mask &= ~(1 << (15 - IIO_EVENT_CODE_EXTRACT_CHAN
 							(event_code)));
 		else if (state && (!(chip->c_mask & (1 << (15 -
-				IIO_EVENT_CODE_EXTRACT_NUM(event_code))))))
-			chip->c_mask |= (1 << (15 - IIO_EVENT_CODE_EXTRACT_NUM
+				IIO_EVENT_CODE_EXTRACT_CHAN(event_code))))))
+			chip->c_mask |= (1 << (15 - IIO_EVENT_CODE_EXTRACT_CHAN
 							(event_code)));
 		else
 			break;
diff --git a/drivers/staging/iio/adc/ad7298_ring.c b/drivers/staging/iio/adc/ad7298_ring.c
index d1a12dd..feeb0ee 100644
--- a/drivers/staging/iio/adc/ad7298_ring.c
+++ b/drivers/staging/iio/adc/ad7298_ring.c
@@ -131,9 +131,6 @@
 		ret = -ENOMEM;
 		goto error_ret;
 	}
-	/* Effectively select the ring buffer implementation */
-	indio_dev->buffer->access = &ring_sw_access_funcs;
-
 	indio_dev->pollfunc = iio_alloc_pollfunc(NULL,
 						 &ad7298_trigger_handler,
 						 IRQF_ONESHOT,
diff --git a/drivers/staging/iio/adc/ad7476_ring.c b/drivers/staging/iio/adc/ad7476_ring.c
index 4e298b2..d6af6c0 100644
--- a/drivers/staging/iio/adc/ad7476_ring.c
+++ b/drivers/staging/iio/adc/ad7476_ring.c
@@ -23,7 +23,7 @@
 /**
  * ad7476_ring_preenable() setup the parameters of the ring before enabling
  *
- * The complex nature of the setting of the nuber of bytes per datum is due
+ * The complex nature of the setting of the number of bytes per datum is due
  * to this driver currently ensuring that the timestamp is stored at an 8
  * byte boundary.
  **/
@@ -98,8 +98,6 @@
 		ret = -ENOMEM;
 		goto error_ret;
 	}
-	/* Effectively select the ring buffer implementation */
-	indio_dev->buffer->access = &ring_sw_access_funcs;
 	indio_dev->pollfunc
 		= iio_alloc_pollfunc(NULL,
 				     &ad7476_trigger_handler,
diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c
index ddb7ef9..97e8d3d 100644
--- a/drivers/staging/iio/adc/ad7606_core.c
+++ b/drivers/staging/iio/adc/ad7606_core.c
@@ -197,7 +197,7 @@
 		       ad7606_store_oversampling_ratio, 0);
 static IIO_CONST_ATTR(oversampling_ratio_available, "0 2 4 8 16 32 64");
 
-static struct attribute *ad7606_attributes[] = {
+static struct attribute *ad7606_attributes_os_and_range[] = {
 	&iio_dev_attr_in_voltage_range.dev_attr.attr,
 	&iio_const_attr_in_voltage_range_available.dev_attr.attr,
 	&iio_dev_attr_oversampling_ratio.dev_attr.attr,
@@ -205,34 +205,28 @@
 	NULL,
 };
 
-static umode_t ad7606_attr_is_visible(struct kobject *kobj,
-				     struct attribute *attr, int n)
-{
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct ad7606_state *st = iio_priv(indio_dev);
+static const struct attribute_group ad7606_attribute_group_os_and_range = {
+	.attrs = ad7606_attributes_os_and_range,
+};
 
-	umode_t mode = attr->mode;
+static struct attribute *ad7606_attributes_os[] = {
+	&iio_dev_attr_oversampling_ratio.dev_attr.attr,
+	&iio_const_attr_oversampling_ratio_available.dev_attr.attr,
+	NULL,
+};
 
-	if (!(gpio_is_valid(st->pdata->gpio_os0) &&
-	      gpio_is_valid(st->pdata->gpio_os1) &&
-	      gpio_is_valid(st->pdata->gpio_os2)) &&
-	    (attr == &iio_dev_attr_oversampling_ratio.dev_attr.attr ||
-	     attr ==
-	     &iio_const_attr_oversampling_ratio_available.dev_attr.attr))
-		mode = 0;
-	else if (!gpio_is_valid(st->pdata->gpio_range) &&
-		 (attr == &iio_dev_attr_in_voltage_range.dev_attr.attr ||
-		  attr ==
-		  &iio_const_attr_in_voltage_range_available.dev_attr.attr))
-		mode = 0;
+static const struct attribute_group ad7606_attribute_group_os = {
+	.attrs = ad7606_attributes_os,
+};
 
-	return mode;
-}
+static struct attribute *ad7606_attributes_range[] = {
+	&iio_dev_attr_in_voltage_range.dev_attr.attr,
+	&iio_const_attr_in_voltage_range_available.dev_attr.attr,
+	NULL,
+};
 
-static const struct attribute_group ad7606_attribute_group = {
-	.attrs = ad7606_attributes,
-	.is_visible = ad7606_attr_is_visible,
+static const struct attribute_group ad7606_attribute_group_range = {
+	.attrs = ad7606_attributes_range,
 };
 
 #define AD7606_CHANNEL(num)				\
@@ -435,10 +429,27 @@
 	return IRQ_HANDLED;
 };
 
-static const struct iio_info ad7606_info = {
+static const struct iio_info ad7606_info_no_os_or_range = {
 	.driver_module = THIS_MODULE,
 	.read_raw = &ad7606_read_raw,
-	.attrs = &ad7606_attribute_group,
+};
+
+static const struct iio_info ad7606_info_os_and_range = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &ad7606_read_raw,
+	.attrs = &ad7606_attribute_group_os_and_range,
+};
+
+static const struct iio_info ad7606_info_os = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &ad7606_read_raw,
+	.attrs = &ad7606_attribute_group_os,
+};
+
+static const struct iio_info ad7606_info_range = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &ad7606_read_raw,
+	.attrs = &ad7606_attribute_group_range,
 };
 
 struct iio_dev *ad7606_probe(struct device *dev, int irq,
@@ -483,7 +494,19 @@
 	st->chip_info = &ad7606_chip_info_tbl[id];
 
 	indio_dev->dev.parent = dev;
-	indio_dev->info = &ad7606_info;
+	if (gpio_is_valid(st->pdata->gpio_os0) &&
+	    gpio_is_valid(st->pdata->gpio_os1) &&
+	    gpio_is_valid(st->pdata->gpio_os2)) {
+		if (gpio_is_valid(st->pdata->gpio_range))
+			indio_dev->info = &ad7606_info_os_and_range;
+		else
+			indio_dev->info = &ad7606_info_os;
+	} else {
+		if (gpio_is_valid(st->pdata->gpio_range))
+			indio_dev->info = &ad7606_info_range;
+		else
+			indio_dev->info = &ad7606_info_no_os_or_range;
+	}
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->name = st->chip_info->name;
 	indio_dev->channels = st->chip_info->channels;
diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c
index cff9756..bb152a8 100644
--- a/drivers/staging/iio/adc/ad7606_par.c
+++ b/drivers/staging/iio/adc/ad7606_par.c
@@ -173,18 +173,7 @@
 	},
 };
 
-static int __init ad7606_init(void)
-{
-	return platform_driver_register(&ad7606_driver);
-}
-
-static void __exit ad7606_cleanup(void)
-{
-	platform_driver_unregister(&ad7606_driver);
-}
-
-module_init(ad7606_init);
-module_exit(ad7606_cleanup);
+module_platform_driver(ad7606_driver);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c
index e8f94a1..1ef9fbc 100644
--- a/drivers/staging/iio/adc/ad7606_ring.c
+++ b/drivers/staging/iio/adc/ad7606_ring.c
@@ -110,8 +110,6 @@
 		goto error_ret;
 	}
 
-	/* Effectively select the ring buffer implementation */
-	indio_dev->buffer->access = &ring_sw_access_funcs;
 	indio_dev->pollfunc = iio_alloc_pollfunc(&ad7606_trigger_handler_th_bh,
 						 &ad7606_trigger_handler_th_bh,
 						 0,
diff --git a/drivers/staging/iio/adc/ad7793.c b/drivers/staging/iio/adc/ad7793.c
index 6a058b1..84ecde1 100644
--- a/drivers/staging/iio/adc/ad7793.c
+++ b/drivers/staging/iio/adc/ad7793.c
@@ -427,8 +427,6 @@
 		ret = -ENOMEM;
 		goto error_ret;
 	}
-	/* Effectively select the ring buffer implementation */
-	indio_dev->buffer->access = &ring_sw_access_funcs;
 	indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
 						 &ad7793_trigger_handler,
 						 IRQF_ONESHOT,
diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c
index 85076cd..d180907 100644
--- a/drivers/staging/iio/adc/ad7887_ring.c
+++ b/drivers/staging/iio/adc/ad7887_ring.c
@@ -131,8 +131,6 @@
 		ret = -ENOMEM;
 		goto error_ret;
 	}
-	/* Effectively select the ring buffer implementation */
-	indio_dev->buffer->access = &ring_sw_access_funcs;
 	indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
 						 &ad7887_trigger_handler,
 						 IRQF_ONESHOT,
diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c
index d5b581d..a845866 100644
--- a/drivers/staging/iio/adc/ad799x_core.c
+++ b/drivers/staging/iio/adc/ad799x_core.c
@@ -256,7 +256,7 @@
 	struct ad799x_state *st = iio_priv(indio_dev);
 	int direction = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
 			   IIO_EV_DIR_FALLING);
-	int number = IIO_EVENT_CODE_EXTRACT_NUM(event_code);
+	int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
 
 	mutex_lock(&indio_dev->mlock);
 	ret = ad799x_i2c_write16(st,
@@ -275,7 +275,7 @@
 	struct ad799x_state *st = iio_priv(indio_dev);
 	int direction = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
 			   IIO_EV_DIR_FALLING);
-	int number = IIO_EVENT_CODE_EXTRACT_NUM(event_code);
+	int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
 	u16 valin;
 
 	mutex_lock(&indio_dev->mlock);
diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c
index 5dded9e..069765c 100644
--- a/drivers/staging/iio/adc/ad799x_ring.c
+++ b/drivers/staging/iio/adc/ad799x_ring.c
@@ -26,7 +26,7 @@
 /**
  * ad799x_ring_preenable() setup the parameters of the ring before enabling
  *
- * The complex nature of the setting of the nuber of bytes per datum is due
+ * The complex nature of the setting of the number of bytes per datum is due
  * to this driver currently ensuring that the timestamp is stored at an 8
  * byte boundary.
  **/
@@ -141,8 +141,6 @@
 		ret = -ENOMEM;
 		goto error_ret;
 	}
-	/* Effectively select the ring buffer implementation */
-	indio_dev->buffer->access = &ring_sw_access_funcs;
 	indio_dev->pollfunc = iio_alloc_pollfunc(NULL,
 						 &ad799x_trigger_handler,
 						 IRQF_ONESHOT,
diff --git a/drivers/staging/iio/adc/adt7310.c b/drivers/staging/iio/adc/adt7310.c
index eec2f32..caf57c1 100644
--- a/drivers/staging/iio/adc/adt7310.c
+++ b/drivers/staging/iio/adc/adt7310.c
@@ -725,32 +725,19 @@
 	&iio_dev_attr_fault_queue.dev_attr.attr,
 	&iio_dev_attr_t_alarm_high.dev_attr.attr,
 	&iio_dev_attr_t_alarm_low.dev_attr.attr,
-	&iio_dev_attr_t_hyst.dev_attr.attr,
-	NULL,
-};
-
-static struct attribute *adt7310_event_ct_attributes[] = {
-	&iio_dev_attr_event_mode.dev_attr.attr,
-	&iio_dev_attr_available_event_modes.dev_attr.attr,
-	&iio_dev_attr_fault_queue.dev_attr.attr,
 	&iio_dev_attr_t_crit.dev_attr.attr,
 	&iio_dev_attr_t_hyst.dev_attr.attr,
 	NULL,
 };
 
-static struct attribute_group adt7310_event_attribute_group[ADT7310_IRQS] = {
-	{
-		.attrs = adt7310_event_int_attributes,
-		.name = "events",
-	}, {
-		.attrs = adt7310_event_ct_attributes,
-		.name = "events",
-	}
+static struct attribute_group adt7310_event_attribute_group = {
+	.attrs = adt7310_event_int_attributes,
+	.name = "events",
 };
 
 static const struct iio_info adt7310_info = {
 	.attrs = &adt7310_attribute_group,
-	.event_attrs = adt7310_event_attribute_group,
+	.event_attrs = &adt7310_event_attribute_group,
 	.driver_module = THIS_MODULE,
 };
 
diff --git a/drivers/staging/iio/adc/adt7410.c b/drivers/staging/iio/adc/adt7410.c
index c62248c..dff3e8c 100644
--- a/drivers/staging/iio/adc/adt7410.c
+++ b/drivers/staging/iio/adc/adt7410.c
@@ -693,32 +693,19 @@
 	&iio_dev_attr_fault_queue.dev_attr.attr,
 	&iio_dev_attr_t_alarm_high.dev_attr.attr,
 	&iio_dev_attr_t_alarm_low.dev_attr.attr,
-	&iio_dev_attr_t_hyst.dev_attr.attr,
-	NULL,
-};
-
-static struct attribute *adt7410_event_ct_attributes[] = {
-	&iio_dev_attr_event_mode.dev_attr.attr,
-	&iio_dev_attr_available_event_modes.dev_attr.attr,
-	&iio_dev_attr_fault_queue.dev_attr.attr,
 	&iio_dev_attr_t_crit.dev_attr.attr,
 	&iio_dev_attr_t_hyst.dev_attr.attr,
 	NULL,
 };
 
-static struct attribute_group adt7410_event_attribute_group[ADT7410_IRQS] = {
-	{
-		.attrs = adt7410_event_int_attributes,
-		.name = "events",
-	}, {
-		.attrs = adt7410_event_ct_attributes,
-		.name = "events",
-	}
+static struct attribute_group adt7410_event_attribute_group = {
+	.attrs = adt7410_event_int_attributes,
+	.name = "events",
 };
 
 static const struct iio_info adt7410_info = {
 	.attrs = &adt7410_attribute_group,
-	.event_attrs = adt7410_event_attribute_group,
+	.event_attrs = &adt7410_event_attribute_group,
 	.driver_module = THIS_MODULE,
 };
 
diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c
new file mode 100644
index 0000000..dfc9033
--- /dev/null
+++ b/drivers/staging/iio/adc/lpc32xx_adc.c
@@ -0,0 +1,237 @@
+/*
+ *  lpc32xx_adc.c - Support for ADC in LPC32XX
+ *
+ *  3-channel, 10-bit ADC
+ *
+ *  Copyright (C) 2011, 2012 Roland Stigge <stigge@antcom.de>
+ *
+ *  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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/completion.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * LPC32XX registers definitions
+ */
+#define LPC32XX_ADC_SELECT(x)	((x) + 0x04)
+#define LPC32XX_ADC_CTRL(x)	((x) + 0x08)
+#define LPC32XX_ADC_VALUE(x)	((x) + 0x48)
+
+/* Bit definitions for LPC32XX_ADC_SELECT: */
+#define AD_REFm         0x00000200 /* constant, always write this value! */
+#define AD_REFp		0x00000080 /* constant, always write this value! */
+#define AD_IN		0x00000010 /* multiple of this is the */
+				   /* channel number: 0, 1, 2 */
+#define AD_INTERNAL	0x00000004 /* constant, always write this value! */
+
+/* Bit definitions for LPC32XX_ADC_CTRL: */
+#define AD_STROBE	0x00000002
+#define AD_PDN_CTRL	0x00000004
+
+/* Bit definitions for LPC32XX_ADC_VALUE: */
+#define ADC_VALUE_MASK	0x000003FF
+
+#define MOD_NAME "lpc32xx-adc"
+
+struct lpc32xx_adc_info {
+	void __iomem *adc_base;
+	struct clk *clk;
+	struct completion completion;
+
+	u32 value;
+};
+
+static int lpc32xx_read_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int *val,
+				int *val2,
+				long mask)
+{
+	struct lpc32xx_adc_info *info = iio_priv(indio_dev);
+
+	if (mask == 0) {
+		mutex_lock(&indio_dev->mlock);
+		clk_enable(info->clk);
+		/* Measurement setup */
+		__raw_writel(AD_INTERNAL | (chan->address) | AD_REFp | AD_REFm,
+			LPC32XX_ADC_SELECT(info->adc_base));
+		/* Trigger conversion */
+		__raw_writel(AD_PDN_CTRL | AD_STROBE,
+			LPC32XX_ADC_CTRL(info->adc_base));
+		wait_for_completion(&info->completion); /* set by ISR */
+		clk_disable(info->clk);
+		*val = info->value;
+		mutex_unlock(&indio_dev->mlock);
+
+		return IIO_VAL_INT;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info lpc32xx_adc_iio_info = {
+	.read_raw = &lpc32xx_read_raw,
+	.driver_module = THIS_MODULE,
+};
+
+#define LPC32XX_ADC_CHANNEL(_index) {		\
+	.type = IIO_VOLTAGE,			\
+	.indexed = 1,				\
+	.channel = _index,			\
+	.address = AD_IN * _index,		\
+	.scan_index = _index,			\
+}
+
+static struct iio_chan_spec lpc32xx_adc_iio_channels[] = {
+	LPC32XX_ADC_CHANNEL(0),
+	LPC32XX_ADC_CHANNEL(1),
+	LPC32XX_ADC_CHANNEL(2),
+};
+
+static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id)
+{
+	struct lpc32xx_adc_info *info = (struct lpc32xx_adc_info *) dev_id;
+
+	/* Read value and clear irq */
+	info->value = __raw_readl(LPC32XX_ADC_VALUE(info->adc_base)) &
+				ADC_VALUE_MASK;
+	complete(&info->completion);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit lpc32xx_adc_probe(struct platform_device *pdev)
+{
+	struct lpc32xx_adc_info *info = NULL;
+	struct resource *res;
+	int retval = -ENODEV;
+	struct iio_dev *iodev = NULL;
+	int irq;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get platform I/O memory\n");
+		retval = -EBUSY;
+		goto errout1;
+	}
+
+	iodev = iio_allocate_device(sizeof(struct lpc32xx_adc_info));
+	if (!iodev) {
+		dev_err(&pdev->dev, "failed allocating iio device\n");
+		retval = -ENOMEM;
+		goto errout1;
+	}
+
+	info = iio_priv(iodev);
+
+	info->adc_base = ioremap(res->start, res->end - res->start + 1);
+	if (!info->adc_base) {
+		dev_err(&pdev->dev, "failed mapping memory\n");
+		retval = -EBUSY;
+		goto errout2;
+	}
+
+	info->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(info->clk)) {
+		dev_err(&pdev->dev, "failed getting clock\n");
+		goto errout3;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if ((irq < 0) || (irq >= NR_IRQS)) {
+		dev_err(&pdev->dev, "failed getting interrupt resource\n");
+		retval = -EINVAL;
+		goto errout4;
+	}
+
+	retval = request_irq(irq, lpc32xx_adc_isr, 0, MOD_NAME, info);
+	if (retval < 0) {
+		dev_err(&pdev->dev, "failed requesting interrupt\n");
+		goto errout4;
+	}
+
+	platform_set_drvdata(pdev, iodev);
+
+	init_completion(&info->completion);
+
+	iodev->name = MOD_NAME;
+	iodev->dev.parent = &pdev->dev;
+	iodev->info = &lpc32xx_adc_iio_info;
+	iodev->modes = INDIO_DIRECT_MODE;
+	iodev->channels = lpc32xx_adc_iio_channels;
+	iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels);
+
+	retval = iio_device_register(iodev);
+	if (retval)
+		goto errout5;
+
+	dev_info(&pdev->dev, "LPC32XX ADC driver loaded, IRQ %d\n", irq);
+
+	return 0;
+
+errout5:
+	free_irq(irq, iodev);
+errout4:
+	clk_put(info->clk);
+errout3:
+	iounmap(info->adc_base);
+errout2:
+	iio_free_device(iodev);
+errout1:
+	return retval;
+}
+
+static int __devexit lpc32xx_adc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *iodev = platform_get_drvdata(pdev);
+	struct lpc32xx_adc_info *info = iio_priv(iodev);
+	int irq = platform_get_irq(pdev, 0);
+
+	iio_device_unregister(iodev);
+	free_irq(irq, iodev);
+	platform_set_drvdata(pdev, NULL);
+	clk_put(info->clk);
+	iounmap(info->adc_base);
+	iio_free_device(iodev);
+
+	return 0;
+}
+
+static struct platform_driver lpc32xx_adc_driver = {
+	.probe		= lpc32xx_adc_probe,
+	.remove		= __devexit_p(lpc32xx_adc_remove),
+	.driver		= {
+		.name	= MOD_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(lpc32xx_adc_driver);
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("LPC32XX ADC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c
index b92cb4a..cf3e2ca 100644
--- a/drivers/staging/iio/adc/max1363_core.c
+++ b/drivers/staging/iio/adc/max1363_core.c
@@ -341,7 +341,7 @@
 static struct iio_chan_spec max1363_channels[] =
 	MAX1363_4X_CHANS(12, MAX1363_EV_M);
 
-/* Appies to max1236, max1237 */
+/* Applies to max1236, max1237 */
 static const enum max1363_modes max1236_mode_list[] = {
 	_s0, _s1, _s2, _s3,
 	s0to1, s0to2, s0to3,
@@ -543,9 +543,9 @@
 {
 	struct max1363_state *st = iio_priv(indio_dev);
 	if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING)
-		*val = st->thresh_low[IIO_EVENT_CODE_EXTRACT_NUM(event_code)];
+		*val = st->thresh_low[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)];
 	else
-		*val = st->thresh_high[IIO_EVENT_CODE_EXTRACT_NUM(event_code)];
+		*val = st->thresh_high[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)];
 	return 0;
 }
 
@@ -568,10 +568,10 @@
 
 	switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
 	case IIO_EV_DIR_FALLING:
-		st->thresh_low[IIO_EVENT_CODE_EXTRACT_NUM(event_code)] = val;
+		st->thresh_low[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)] = val;
 		break;
 	case IIO_EV_DIR_RISING:
-		st->thresh_high[IIO_EVENT_CODE_EXTRACT_NUM(event_code)] = val;
+		st->thresh_high[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)] = val;
 		break;
 	}
 
@@ -622,7 +622,7 @@
 	struct max1363_state *st = iio_priv(indio_dev);
 
 	int val;
-	int number = IIO_EVENT_CODE_EXTRACT_NUM(event_code);
+	int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
 	mutex_lock(&indio_dev->mlock);
 	if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING)
 		val = (1 << number) & st->mask_low;
@@ -775,7 +775,7 @@
 	int ret = 0;
 	struct max1363_state *st = iio_priv(indio_dev);
 	u16 unifiedmask;
-	int number = IIO_EVENT_CODE_EXTRACT_NUM(event_code);
+	int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
 
 	mutex_lock(&indio_dev->mlock);
 	unifiedmask = st->mask_low | st->mask_high;
@@ -1245,10 +1245,31 @@
 	return max1363_set_scan_mode(st);
 }
 
+static int __devinit max1363_alloc_scan_masks(struct iio_dev *indio_dev)
+{
+	struct max1363_state *st = iio_priv(indio_dev);
+	unsigned long *masks;
+	int i;
+
+	masks = kzalloc(BITS_TO_LONGS(MAX1363_MAX_CHANNELS)*sizeof(long)*
+			  (st->chip_info->num_modes + 1), GFP_KERNEL);
+	if (!masks)
+		return -ENOMEM;
+
+	for (i = 0; i < st->chip_info->num_modes; i++)
+		bitmap_copy(masks + BITS_TO_LONGS(MAX1363_MAX_CHANNELS)*i,
+			    max1363_mode_table[st->chip_info->mode_list[i]]
+			    .modemask, MAX1363_MAX_CHANNELS);
+
+	indio_dev->available_scan_masks = masks;
+
+	return 0;
+}
+
 static int __devinit max1363_probe(struct i2c_client *client,
 				   const struct i2c_device_id *id)
 {
-	int ret, i;
+	int ret;
 	struct max1363_state *st;
 	struct iio_dev *indio_dev;
 	struct regulator *reg;
@@ -1276,19 +1297,10 @@
 	st->chip_info = &max1363_chip_info_tbl[id->driver_data];
 	st->client = client;
 
-	indio_dev->available_scan_masks
-		= kzalloc(BITS_TO_LONGS(MAX1363_MAX_CHANNELS)*sizeof(long)*
-			  (st->chip_info->num_modes + 1), GFP_KERNEL);
-	if (!indio_dev->available_scan_masks) {
-		ret = -ENOMEM;
+	ret = max1363_alloc_scan_masks(indio_dev);
+	if (ret)
 		goto error_free_device;
-	}
 
-	for (i = 0; i < st->chip_info->num_modes; i++)
-		bitmap_copy(indio_dev->available_scan_masks +
-			    BITS_TO_LONGS(MAX1363_MAX_CHANNELS)*i,
-			    max1363_mode_table[st->chip_info->mode_list[i]]
-			    .modemask, MAX1363_MAX_CHANNELS);
 	/* Estabilish that the iio_dev is a child of the i2c device */
 	indio_dev->dev.parent = &client->dev;
 	indio_dev->name = id->name;
diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c
index f730b3f..d0a60a3 100644
--- a/drivers/staging/iio/adc/max1363_ring.c
+++ b/drivers/staging/iio/adc/max1363_ring.c
@@ -116,8 +116,6 @@
 		ret = -ENOMEM;
 		goto error_deallocate_sw_rb;
 	}
-	/* Effectively select the ring buffer implementation */
-	indio_dev->buffer->access = &ring_sw_access_funcs;
 	/* Ring buffer functions - here trigger setup related */
 	indio_dev->setup_ops = &max1363_ring_setup_ops;
 
diff --git a/drivers/staging/iio/addac/adt7316-i2c.c b/drivers/staging/iio/addac/adt7316-i2c.c
index 2c03a39..9e128dd 100644
--- a/drivers/staging/iio/addac/adt7316-i2c.c
+++ b/drivers/staging/iio/addac/adt7316-i2c.c
@@ -125,30 +125,14 @@
 
 MODULE_DEVICE_TABLE(i2c, adt7316_i2c_id);
 
-#ifdef CONFIG_PM
-static int adt7316_i2c_suspend(struct i2c_client *client, pm_message_t message)
-{
-	return adt7316_disable(&client->dev);
-}
-
-static int adt7316_i2c_resume(struct i2c_client *client)
-{
-	return adt7316_enable(&client->dev);
-}
-#else
-# define adt7316_i2c_suspend NULL
-# define adt7316_i2c_resume  NULL
-#endif
-
 static struct i2c_driver adt7316_driver = {
 	.driver = {
 		.name = "adt7316",
+		.pm = ADT7316_PM_OPS,
 		.owner  = THIS_MODULE,
 	},
 	.probe = adt7316_i2c_probe,
 	.remove = __devexit_p(adt7316_i2c_remove),
-	.suspend = adt7316_i2c_suspend,
-	.resume = adt7316_i2c_resume,
 	.id_table = adt7316_i2c_id,
 };
 module_i2c_driver(adt7316_driver);
diff --git a/drivers/staging/iio/addac/adt7316-spi.c b/drivers/staging/iio/addac/adt7316-spi.c
index 1ea3cd0..985f7d8 100644
--- a/drivers/staging/iio/addac/adt7316-spi.c
+++ b/drivers/staging/iio/addac/adt7316-spi.c
@@ -133,30 +133,14 @@
 
 MODULE_DEVICE_TABLE(spi, adt7316_spi_id);
 
-#ifdef CONFIG_PM
-static int adt7316_spi_suspend(struct spi_device *spi_dev, pm_message_t message)
-{
-	return adt7316_disable(&spi_dev->dev);
-}
-
-static int adt7316_spi_resume(struct spi_device *spi_dev)
-{
-	return adt7316_enable(&spi_dev->dev);
-}
-#else
-# define adt7316_spi_suspend NULL
-# define adt7316_spi_resume  NULL
-#endif
-
 static struct spi_driver adt7316_driver = {
 	.driver = {
 		.name = "adt7316",
+		.pm = ADT7316_PM_OPS,
 		.owner = THIS_MODULE,
 	},
 	.probe = adt7316_spi_probe,
 	.remove = __devexit_p(adt7316_spi_remove),
-	.suspend = adt7316_spi_suspend,
-	.resume = adt7316_spi_resume,
 	.id_table = adt7316_spi_id,
 };
 module_spi_driver(adt7316_driver);
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
index 13c3929..fd6a454 100644
--- a/drivers/staging/iio/addac/adt7316.c
+++ b/drivers/staging/iio/addac/adt7316.c
@@ -2089,24 +2089,25 @@
 	.name = "events",
 };
 
-#ifdef CONFIG_PM
-int adt7316_disable(struct device *dev)
+#ifdef CONFIG_PM_SLEEP
+static int adt7316_disable(struct device *dev)
 {
 	struct iio_dev *dev_info = dev_get_drvdata(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return _adt7316_store_enabled(chip, 0);
 }
-EXPORT_SYMBOL(adt7316_disable);
 
-int adt7316_enable(struct device *dev)
+static int adt7316_enable(struct device *dev)
 {
 	struct iio_dev *dev_info = dev_get_drvdata(dev);
 	struct adt7316_chip_info *chip = iio_priv(dev_info);
 
 	return _adt7316_store_enabled(chip, 1);
 }
-EXPORT_SYMBOL(adt7316_enable);
+
+SIMPLE_DEV_PM_OPS(adt7316_pm_ops, adt7316_disable, adt7316_enable);
+EXPORT_SYMBOL_GPL(adt7316_pm_ops);
 #endif
 
 static const struct iio_info adt7316_info = {
diff --git a/drivers/staging/iio/addac/adt7316.h b/drivers/staging/iio/addac/adt7316.h
index d34bd67..4d3efff 100644
--- a/drivers/staging/iio/addac/adt7316.h
+++ b/drivers/staging/iio/addac/adt7316.h
@@ -10,6 +10,7 @@
 #define _ADT7316_H_
 
 #include <linux/types.h>
+#include <linux/pm.h>
 
 #define ADT7316_REG_MAX_ADDR		0x3F
 
@@ -23,9 +24,11 @@
 	int (*multi_write) (void *client, u8 first_reg, u8 count, u8 *data);
 };
 
-#ifdef CONFIG_PM
-int adt7316_disable(struct device *dev);
-int adt7316_enable(struct device *dev);
+#ifdef CONFIG_PM_SLEEP
+extern const struct dev_pm_ops adt7316_pm_ops;
+#define ADT7316_PM_OPS (&adt7316_pm_ops)
+#else
+#define ADT7316_PM_OPS NULL
 #endif
 int adt7316_probe(struct device *dev, struct adt7316_bus *bus, const char *name);
 int adt7316_remove(struct device *dev);
diff --git a/drivers/staging/iio/buffer.h b/drivers/staging/iio/buffer.h
index 6fb6e64..df2046d 100644
--- a/drivers/staging/iio/buffer.h
+++ b/drivers/staging/iio/buffer.h
@@ -91,8 +91,6 @@
  **/
 void iio_buffer_init(struct iio_buffer *buffer);
 
-void iio_buffer_deinit(struct iio_buffer *buffer);
-
 /**
  * __iio_update_buffer() - update common elements of buffers
  * @buffer:		buffer that is the event source
diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c
index b73007d..e4a08dc 100644
--- a/drivers/staging/iio/cdc/ad7150.c
+++ b/drivers/staging/iio/cdc/ad7150.c
@@ -167,7 +167,7 @@
 	u16 value;
 	u8 sens, timeout;
 	struct ad7150_chip_info *chip = iio_priv(indio_dev);
-	int chan = IIO_EVENT_CODE_EXTRACT_NUM(event_code);
+	int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
 	int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
 			IIO_EV_DIR_RISING);
 
@@ -279,7 +279,7 @@
 				   u64 event_code,
 				   int *val)
 {
-	int chan = IIO_EVENT_CODE_EXTRACT_NUM(event_code);
+	int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
 	struct ad7150_chip_info *chip = iio_priv(indio_dev);
 	int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
 			IIO_EV_DIR_RISING);
@@ -309,7 +309,7 @@
 {
 	int ret;
 	struct ad7150_chip_info *chip = iio_priv(indio_dev);
-	int chan = IIO_EVENT_CODE_EXTRACT_NUM(event_code);
+	int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
 	int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
 			IIO_EV_DIR_RISING);
 
@@ -347,7 +347,7 @@
 	u8 value;
 
 	/* use the event code for consistency reasons */
-	int chan = IIO_EVENT_CODE_EXTRACT_NUM(this_attr->address);
+	int chan = IIO_EVENT_CODE_EXTRACT_CHAN(this_attr->address);
 	int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(this_attr->address)
 			== IIO_EV_DIR_RISING);
 
@@ -373,7 +373,7 @@
 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct ad7150_chip_info *chip = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	int chan = IIO_EVENT_CODE_EXTRACT_NUM(this_attr->address);
+	int chan = IIO_EVENT_CODE_EXTRACT_CHAN(this_attr->address);
 	int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(this_attr->address) ==
 			IIO_EV_DIR_RISING);
 	u8 data;
diff --git a/drivers/staging/iio/consumer.h b/drivers/staging/iio/consumer.h
new file mode 100644
index 0000000..36a060c
--- /dev/null
+++ b/drivers/staging/iio/consumer.h
@@ -0,0 +1,96 @@
+/*
+ * Industrial I/O in kernel consumer interface
+ *
+ * Copyright (c) 2011 Jonathan Cameron
+ *
+ * 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 _IIO_INKERN_CONSUMER_H_
+#define _IIO_INKERN_CONSUMER_H
+#include "types.h"
+
+struct iio_dev;
+struct iio_chan_spec;
+
+/**
+ * struct iio_channel - everything needed for a consumer to use a channel
+ * @indio_dev:		Device on which the channel exists.
+ * @channel:		Full description of the channel.
+ */
+struct iio_channel {
+	struct iio_dev *indio_dev;
+	const struct iio_chan_spec *channel;
+};
+
+/**
+ * iio_channel_get() - get description of all that is needed to access channel.
+ * @name:		Unique name of the device as provided in the iio_map
+ *			with which the desired provider to consumer mapping
+ *			was registered.
+ * @consumer_channel:	Unique name to identify the channel on the consumer
+ *			side. This typically describes the channels use within
+ *			the consumer. E.g. 'battery_voltage'
+ */
+struct iio_channel *iio_st_channel_get(const char *name,
+				       const char *consumer_channel);
+
+/**
+ * iio_st_channel_release() - release channels obtained via iio_st_channel_get
+ * @chan:		The channel to be released.
+ */
+void iio_st_channel_release(struct iio_channel *chan);
+
+/**
+ * iio_st_channel_get_all() - get all channels associated with a client
+ * @name:		name of consumer device.
+ *
+ * Returns an array of iio_channel structures terminated with one with
+ * null iio_dev pointer.
+ * This function is used by fairly generic consumers to get all the
+ * channels registered as having this consumer.
+ */
+struct iio_channel *iio_st_channel_get_all(const char *name);
+
+/**
+ * iio_st_channel_release_all() - reverse iio_st_get_all
+ * @chan:		Array of channels to be released.
+ */
+void iio_st_channel_release_all(struct iio_channel *chan);
+
+/**
+ * iio_st_read_channel_raw() - read from a given channel
+ * @channel:		The channel being queried.
+ * @val:		Value read back.
+ *
+ * Note raw reads from iio channels are in adc counts and hence
+ * scale will need to be applied if standard units required.
+ */
+int iio_st_read_channel_raw(struct iio_channel *chan,
+			    int *val);
+
+/**
+ * iio_st_get_channel_type() - get the type of a channel
+ * @channel:		The channel being queried.
+ * @type:		The type of the channel.
+ *
+ * returns the enum iio_chan_type of the channel
+ */
+int iio_st_get_channel_type(struct iio_channel *channel,
+			    enum iio_chan_type *type);
+
+/**
+ * iio_st_read_channel_scale() - read the scale value for a channel
+ * @channel:		The channel being queried.
+ * @val:		First part of value read back.
+ * @val2:		Second part of value read back.
+ *
+ * Note returns a description of what is in val and val2, such
+ * as IIO_VAL_INT_PLUS_MICRO telling us we have a value of val
+ * + val2/1e6
+ */
+int iio_st_read_channel_scale(struct iio_channel *chan, int *val,
+			      int *val2);
+
+#endif
diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig
index 13e2797..a57803a 100644
--- a/drivers/staging/iio/dac/Kconfig
+++ b/drivers/staging/iio/dac/Kconfig
@@ -4,11 +4,12 @@
 menu "Digital to analog converters"
 
 config AD5064
-	tristate "Analog Devices AD5064/64-1/44/24 DAC driver"
+	tristate "Analog Devices AD5064/64-1/65/44/45/24/25, AD5628/48/66/68 DAC driver"
 	depends on SPI
 	help
-	  Say yes here to build support for Analog Devices AD5064, AD5064-1,
-	  AD5044, AD5024 Digital to Analog Converter.
+	  Say yes here to build support for Analog Devices AD5024, AD5025, AD5044,
+	  AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5648, AD5666, AD5668 Digital
+	  to Analog Converter.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad5064.
diff --git a/drivers/staging/iio/dac/ad5064.c b/drivers/staging/iio/dac/ad5064.c
index 049a855..06b1627 100644
--- a/drivers/staging/iio/dac/ad5064.c
+++ b/drivers/staging/iio/dac/ad5064.c
@@ -1,5 +1,6 @@
 /*
- * AD5064, AD5064-1, AD5044, AD5024 Digital to analog converters  driver
+ * AD5024, AD5025, AD5044, AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5648,
+ * AD5666, AD5668 Digital to analog converters driver
  *
  * Copyright 2011 Analog Devices Inc.
  *
@@ -19,7 +20,8 @@
 #include "../sysfs.h"
 #include "dac.h"
 
-#define AD5064_DAC_CHANNELS			4
+#define AD5064_MAX_DAC_CHANNELS			8
+#define AD5064_MAX_VREFS			4
 
 #define AD5064_ADDR(x)				((x) << 20)
 #define AD5064_CMD(x)				((x) << 24)
@@ -35,7 +37,10 @@
 #define AD5064_CMD_CLEAR			0x5
 #define AD5064_CMD_LDAC_MASK			0x6
 #define AD5064_CMD_RESET			0x7
-#define AD5064_CMD_DAISY_CHAIN_ENABLE		0x8
+#define AD5064_CMD_CONFIG			0x8
+
+#define AD5064_CONFIG_DAISY_CHAIN_ENABLE	BIT(1)
+#define AD5064_CONFIG_INT_VREF_ENABLE		BIT(0)
 
 #define AD5064_LDAC_PWRDN_NONE			0x0
 #define AD5064_LDAC_PWRDN_1K			0x1
@@ -45,12 +50,17 @@
 /**
  * struct ad5064_chip_info - chip specific information
  * @shared_vref:	whether the vref supply is shared between channels
+ * @internal_vref:	internal reference voltage. 0 if the chip has no internal
+ *			vref.
  * @channel:		channel specification
-*/
+ * @num_channels:	number of channels
+ */
 
 struct ad5064_chip_info {
 	bool shared_vref;
-	struct iio_chan_spec channel[AD5064_DAC_CHANNELS];
+	unsigned long internal_vref;
+	const struct iio_chan_spec *channels;
+	unsigned int num_channels;
 };
 
 /**
@@ -61,16 +71,19 @@
  * @pwr_down:		whether channel is powered down
  * @pwr_down_mode:	channel's current power down mode
  * @dac_cache:		current DAC raw value (chip does not support readback)
+ * @use_internal_vref:	set to true if the internal reference voltage should be
+ *			used.
  * @data:		spi transfer buffers
  */
 
 struct ad5064_state {
 	struct spi_device		*spi;
 	const struct ad5064_chip_info	*chip_info;
-	struct regulator_bulk_data	vref_reg[AD5064_DAC_CHANNELS];
-	bool				pwr_down[AD5064_DAC_CHANNELS];
-	u8				pwr_down_mode[AD5064_DAC_CHANNELS];
-	unsigned int			dac_cache[AD5064_DAC_CHANNELS];
+	struct regulator_bulk_data	vref_reg[AD5064_MAX_VREFS];
+	bool				pwr_down[AD5064_MAX_DAC_CHANNELS];
+	u8				pwr_down_mode[AD5064_MAX_DAC_CHANNELS];
+	unsigned int			dac_cache[AD5064_MAX_DAC_CHANNELS];
+	bool				use_internal_vref;
 
 	/*
 	 * DMA (thus cache coherency maintenance) requires the
@@ -81,50 +94,20 @@
 
 enum ad5064_type {
 	ID_AD5024,
+	ID_AD5025,
 	ID_AD5044,
+	ID_AD5045,
 	ID_AD5064,
 	ID_AD5064_1,
-};
-
-#define AD5064_CHANNEL(chan, bits) {				\
-	.type = IIO_VOLTAGE,					\
-	.indexed = 1,						\
-	.output = 1,						\
-	.channel = (chan),					\
-	.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,	\
-	.address = AD5064_ADDR_DAC(chan),			\
-	.scan_type = IIO_ST('u', (bits), 16, 20 - (bits))	\
-}
-
-static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
-	[ID_AD5024] = {
-		.shared_vref = false,
-		.channel[0] = AD5064_CHANNEL(0, 12),
-		.channel[1] = AD5064_CHANNEL(1, 12),
-		.channel[2] = AD5064_CHANNEL(2, 12),
-		.channel[3] = AD5064_CHANNEL(3, 12),
-	},
-	[ID_AD5044] = {
-		.shared_vref = false,
-		.channel[0] = AD5064_CHANNEL(0, 14),
-		.channel[1] = AD5064_CHANNEL(1, 14),
-		.channel[2] = AD5064_CHANNEL(2, 14),
-		.channel[3] = AD5064_CHANNEL(3, 14),
-	},
-	[ID_AD5064] = {
-		.shared_vref = false,
-		.channel[0] = AD5064_CHANNEL(0, 16),
-		.channel[1] = AD5064_CHANNEL(1, 16),
-		.channel[2] = AD5064_CHANNEL(2, 16),
-		.channel[3] = AD5064_CHANNEL(3, 16),
-	},
-	[ID_AD5064_1] = {
-		.shared_vref = true,
-		.channel[0] = AD5064_CHANNEL(0, 16),
-		.channel[1] = AD5064_CHANNEL(1, 16),
-		.channel[2] = AD5064_CHANNEL(2, 16),
-		.channel[3] = AD5064_CHANNEL(3, 16),
-	},
+	ID_AD5065,
+	ID_AD5628_1,
+	ID_AD5628_2,
+	ID_AD5648_1,
+	ID_AD5648_2,
+	ID_AD5666_1,
+	ID_AD5666_2,
+	ID_AD5668_1,
+	ID_AD5668_2,
 };
 
 static int ad5064_spi_write(struct ad5064_state *st, unsigned int cmd,
@@ -160,22 +143,25 @@
 	[AD5064_LDAC_PWRDN_3STATE]	= "three_state",
 };
 
-static ssize_t ad5064_read_powerdown_mode(struct device *dev,
-	struct device_attribute *attr, char *buf)
+static ssize_t ad5064_read_powerdown_mode_available(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, char *buf)
 {
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	return sprintf(buf, "%s %s %s\n", ad5064_powerdown_modes[1],
+		ad5064_powerdown_modes[2], ad5064_powerdown_modes[3]);
+}
+
+static ssize_t ad5064_read_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, char *buf)
+{
 	struct ad5064_state *st = iio_priv(indio_dev);
 
 	return sprintf(buf, "%s\n",
-		ad5064_powerdown_modes[st->pwr_down_mode[this_attr->address]]);
+		ad5064_powerdown_modes[st->pwr_down_mode[chan->channel]]);
 }
 
-static ssize_t ad5064_write_powerdown_mode(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t len)
+static ssize_t ad5064_write_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, const char *buf, size_t len)
 {
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct ad5064_state *st = iio_priv(indio_dev);
 	unsigned int mode, i;
 	int ret;
@@ -192,31 +178,26 @@
 		return  -EINVAL;
 
 	mutex_lock(&indio_dev->mlock);
-	st->pwr_down_mode[this_attr->address] = mode;
+	st->pwr_down_mode[chan->channel] = mode;
 
-	ret = ad5064_sync_powerdown_mode(st, this_attr->address);
+	ret = ad5064_sync_powerdown_mode(st, chan->channel);
 	mutex_unlock(&indio_dev->mlock);
 
 	return ret ? ret : len;
 }
 
-static ssize_t ad5064_read_dac_powerdown(struct device *dev,
-					   struct device_attribute *attr,
-					   char *buf)
+static ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, char *buf)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct ad5064_state *st = iio_priv(indio_dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
-	return sprintf(buf, "%d\n", st->pwr_down[this_attr->address]);
+	return sprintf(buf, "%d\n", st->pwr_down[chan->channel]);
 }
 
-static ssize_t ad5064_write_dac_powerdown(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t len)
+static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, const char *buf, size_t len)
 {
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct ad5064_state *st = iio_priv(indio_dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	bool pwr_down;
 	int ret;
 
@@ -225,53 +206,24 @@
 		return ret;
 
 	mutex_lock(&indio_dev->mlock);
-	st->pwr_down[this_attr->address] = pwr_down;
+	st->pwr_down[chan->channel] = pwr_down;
 
-	ret = ad5064_sync_powerdown_mode(st, this_attr->address);
+	ret = ad5064_sync_powerdown_mode(st, chan->channel);
 	mutex_unlock(&indio_dev->mlock);
 	return ret ? ret : len;
 }
 
-static IIO_CONST_ATTR(out_voltage_powerdown_mode_available,
-			"1kohm_to_gnd 100kohm_to_gnd three_state");
+static int ad5064_get_vref(struct ad5064_state *st,
+	struct iio_chan_spec const *chan)
+{
+	unsigned int i;
 
-#define IIO_DEV_ATTR_DAC_POWERDOWN_MODE(_chan) \
-	IIO_DEVICE_ATTR(out_voltage##_chan##_powerdown_mode, \
-			S_IRUGO | S_IWUSR, \
-			ad5064_read_powerdown_mode, \
-			ad5064_write_powerdown_mode, _chan);
+	if (st->use_internal_vref)
+		return st->chip_info->internal_vref;
 
-#define IIO_DEV_ATTR_DAC_POWERDOWN(_chan)				\
-	IIO_DEVICE_ATTR(out_voltage##_chan##_powerdown,			\
-			S_IRUGO | S_IWUSR,				\
-			ad5064_read_dac_powerdown,			\
-			ad5064_write_dac_powerdown, _chan)
-
-static IIO_DEV_ATTR_DAC_POWERDOWN(0);
-static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(0);
-static IIO_DEV_ATTR_DAC_POWERDOWN(1);
-static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(1);
-static IIO_DEV_ATTR_DAC_POWERDOWN(2);
-static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(2);
-static IIO_DEV_ATTR_DAC_POWERDOWN(3);
-static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(3);
-
-static struct attribute *ad5064_attributes[] = {
-	&iio_dev_attr_out_voltage0_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage1_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage2_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage3_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage0_powerdown_mode.dev_attr.attr,
-	&iio_dev_attr_out_voltage1_powerdown_mode.dev_attr.attr,
-	&iio_dev_attr_out_voltage2_powerdown_mode.dev_attr.attr,
-	&iio_dev_attr_out_voltage3_powerdown_mode.dev_attr.attr,
-	&iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group ad5064_attribute_group = {
-	.attrs = ad5064_attributes,
-};
+	i = st->chip_info->shared_vref ? 0 : chan->channel;
+	return regulator_get_voltage(st->vref_reg[i].consumer);
+}
 
 static int ad5064_read_raw(struct iio_dev *indio_dev,
 			   struct iio_chan_spec const *chan,
@@ -280,7 +232,6 @@
 			   long m)
 {
 	struct ad5064_state *st = iio_priv(indio_dev);
-	unsigned int vref;
 	int scale_uv;
 
 	switch (m) {
@@ -288,8 +239,7 @@
 		*val = st->dac_cache[chan->channel];
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
-		vref = st->chip_info->shared_vref ? 0 : chan->channel;
-		scale_uv = regulator_get_voltage(st->vref_reg[vref].consumer);
+		scale_uv = ad5064_get_vref(st, chan);
 		if (scale_uv < 0)
 			return scale_uv;
 
@@ -331,13 +281,144 @@
 static const struct iio_info ad5064_info = {
 	.read_raw = ad5064_read_raw,
 	.write_raw = ad5064_write_raw,
-	.attrs = &ad5064_attribute_group,
 	.driver_module = THIS_MODULE,
 };
 
+static struct iio_chan_spec_ext_info ad5064_ext_info[] = {
+	{
+		.name = "powerdown",
+		.read = ad5064_read_dac_powerdown,
+		.write = ad5064_write_dac_powerdown,
+	},
+	{
+		.name = "powerdown_mode",
+		.read = ad5064_read_powerdown_mode,
+		.write = ad5064_write_powerdown_mode,
+	},
+	{
+		.name = "powerdown_mode_available",
+		.shared = true,
+		.read = ad5064_read_powerdown_mode_available,
+	},
+	{ },
+};
+
+#define AD5064_CHANNEL(chan, bits) {				\
+	.type = IIO_VOLTAGE,					\
+	.indexed = 1,						\
+	.output = 1,						\
+	.channel = (chan),					\
+	.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,	\
+	.address = AD5064_ADDR_DAC(chan),			\
+	.scan_type = IIO_ST('u', (bits), 16, 20 - (bits)),	\
+	.ext_info = ad5064_ext_info,				\
+}
+
+#define DECLARE_AD5064_CHANNELS(name, bits) \
+const struct iio_chan_spec name[] = { \
+	AD5064_CHANNEL(0, bits), \
+	AD5064_CHANNEL(1, bits), \
+	AD5064_CHANNEL(2, bits), \
+	AD5064_CHANNEL(3, bits), \
+	AD5064_CHANNEL(4, bits), \
+	AD5064_CHANNEL(5, bits), \
+	AD5064_CHANNEL(6, bits), \
+	AD5064_CHANNEL(7, bits), \
+}
+
+static DECLARE_AD5064_CHANNELS(ad5024_channels, 12);
+static DECLARE_AD5064_CHANNELS(ad5044_channels, 14);
+static DECLARE_AD5064_CHANNELS(ad5064_channels, 16);
+
+static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
+	[ID_AD5024] = {
+		.shared_vref = false,
+		.channels = ad5024_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5025] = {
+		.shared_vref = false,
+		.channels = ad5024_channels,
+		.num_channels = 2,
+	},
+	[ID_AD5044] = {
+		.shared_vref = false,
+		.channels = ad5044_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5045] = {
+		.shared_vref = false,
+		.channels = ad5044_channels,
+		.num_channels = 2,
+	},
+	[ID_AD5064] = {
+		.shared_vref = false,
+		.channels = ad5064_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5064_1] = {
+		.shared_vref = true,
+		.channels = ad5064_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5065] = {
+		.shared_vref = false,
+		.channels = ad5064_channels,
+		.num_channels = 2,
+	},
+	[ID_AD5628_1] = {
+		.shared_vref = true,
+		.internal_vref = 2500000,
+		.channels = ad5024_channels,
+		.num_channels = 8,
+	},
+	[ID_AD5628_2] = {
+		.shared_vref = true,
+		.internal_vref = 5000000,
+		.channels = ad5024_channels,
+		.num_channels = 8,
+	},
+	[ID_AD5648_1] = {
+		.shared_vref = true,
+		.internal_vref = 2500000,
+		.channels = ad5044_channels,
+		.num_channels = 8,
+	},
+	[ID_AD5648_2] = {
+		.shared_vref = true,
+		.internal_vref = 5000000,
+		.channels = ad5044_channels,
+		.num_channels = 8,
+	},
+	[ID_AD5666_1] = {
+		.shared_vref = true,
+		.internal_vref = 2500000,
+		.channels = ad5064_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5666_2] = {
+		.shared_vref = true,
+		.internal_vref = 5000000,
+		.channels = ad5064_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5668_1] = {
+		.shared_vref = true,
+		.internal_vref = 2500000,
+		.channels = ad5064_channels,
+		.num_channels = 8,
+	},
+	[ID_AD5668_2] = {
+		.shared_vref = true,
+		.internal_vref = 5000000,
+		.channels = ad5064_channels,
+		.num_channels = 8,
+	},
+};
+
 static inline unsigned int ad5064_num_vref(struct ad5064_state *st)
 {
-	return st->chip_info->shared_vref ? 1 : AD5064_DAC_CHANNELS;
+	return st->chip_info->shared_vref ? 1 : st->chip_info->num_channels;
 }
 
 static const char * const ad5064_vref_names[] = {
@@ -376,14 +457,24 @@
 
 	ret = regulator_bulk_get(&st->spi->dev, ad5064_num_vref(st),
 		st->vref_reg);
-	if (ret)
-		goto error_free;
+	if (ret) {
+		if (!st->chip_info->internal_vref)
+			goto error_free;
+		st->use_internal_vref = true;
+		ret = ad5064_spi_write(st, AD5064_CMD_CONFIG, 0,
+			AD5064_CONFIG_INT_VREF_ENABLE, 0);
+		if (ret) {
+			dev_err(&spi->dev, "Failed to enable internal vref: %d\n",
+				ret);
+			goto error_free;
+		}
+	} else {
+		ret = regulator_bulk_enable(ad5064_num_vref(st), st->vref_reg);
+		if (ret)
+			goto error_free_reg;
+	}
 
-	ret = regulator_bulk_enable(ad5064_num_vref(st), st->vref_reg);
-	if (ret)
-		goto error_free_reg;
-
-	for (i = 0; i < AD5064_DAC_CHANNELS; ++i) {
+	for (i = 0; i < st->chip_info->num_channels; ++i) {
 		st->pwr_down_mode[i] = AD5064_LDAC_PWRDN_1K;
 		st->dac_cache[i] = 0x8000;
 	}
@@ -392,8 +483,8 @@
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->info = &ad5064_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->channels = st->chip_info->channel;
-	indio_dev->num_channels = AD5064_DAC_CHANNELS;
+	indio_dev->channels = st->chip_info->channels;
+	indio_dev->num_channels = st->chip_info->num_channels;
 
 	ret = iio_device_register(indio_dev);
 	if (ret)
@@ -402,9 +493,11 @@
 	return 0;
 
 error_disable_reg:
-	regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
+	if (!st->use_internal_vref)
+		regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
 error_free_reg:
-	regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
+	if (!st->use_internal_vref)
+		regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
 error_free:
 	iio_free_device(indio_dev);
 
@@ -419,8 +512,10 @@
 
 	iio_device_unregister(indio_dev);
 
-	regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
-	regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
+	if (!st->use_internal_vref) {
+		regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
+		regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
+	}
 
 	iio_free_device(indio_dev);
 
@@ -429,9 +524,21 @@
 
 static const struct spi_device_id ad5064_id[] = {
 	{"ad5024", ID_AD5024},
+	{"ad5025", ID_AD5025},
 	{"ad5044", ID_AD5044},
+	{"ad5045", ID_AD5045},
 	{"ad5064", ID_AD5064},
 	{"ad5064-1", ID_AD5064_1},
+	{"ad5065", ID_AD5065},
+	{"ad5628-1", ID_AD5628_1},
+	{"ad5628-2", ID_AD5628_2},
+	{"ad5648-1", ID_AD5648_1},
+	{"ad5648-2", ID_AD5648_2},
+	{"ad5666-1", ID_AD5666_1},
+	{"ad5666-2", ID_AD5666_2},
+	{"ad5668-1", ID_AD5668_1},
+	{"ad5668-2", ID_AD5668_2},
+	{"ad5668-3", ID_AD5668_2}, /* similar enough to ad5668-2 */
 	{}
 };
 MODULE_DEVICE_TABLE(spi, ad5064_id);
@@ -448,5 +555,5 @@
 module_spi_driver(ad5064_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("Analog Devices AD5064/64-1/44/24 DAC");
+MODULE_DESCRIPTION("Analog Devices AD5024/25/44/45/64/64-1/65, AD5628/48/66/68 DAC");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dac/ad5360.c b/drivers/staging/iio/dac/ad5360.c
index 710b256..cec3693 100644
--- a/drivers/staging/iio/dac/ad5360.c
+++ b/drivers/staging/iio/dac/ad5360.c
@@ -439,8 +439,8 @@
 	struct iio_chan_spec *channels;
 	unsigned int i;
 
-	channels = kcalloc(sizeof(struct iio_chan_spec),
-			st->chip_info->num_channels, GFP_KERNEL);
+	channels = kcalloc(st->chip_info->num_channels,
+			   sizeof(struct iio_chan_spec), GFP_KERNEL);
 
 	if (!channels)
 		return -ENOMEM;
diff --git a/drivers/staging/iio/dac/ad5380.c b/drivers/staging/iio/dac/ad5380.c
index eff97ae0..4c50716 100644
--- a/drivers/staging/iio/dac/ad5380.c
+++ b/drivers/staging/iio/dac/ad5380.c
@@ -363,8 +363,8 @@
 	struct iio_chan_spec *channels;
 	unsigned int i;
 
-	channels = kcalloc(sizeof(struct iio_chan_spec),
-			st->chip_info->num_channels, GFP_KERNEL);
+	channels = kcalloc(st->chip_info->num_channels,
+			   sizeof(struct iio_chan_spec), GFP_KERNEL);
 
 	if (!channels)
 		return -ENOMEM;
diff --git a/drivers/staging/iio/dac/ad5421.c b/drivers/staging/iio/dac/ad5421.c
index 71ee868..0b040b2 100644
--- a/drivers/staging/iio/dac/ad5421.c
+++ b/drivers/staging/iio/dac/ad5421.c
@@ -536,18 +536,7 @@
 	.probe = ad5421_probe,
 	.remove = __devexit_p(ad5421_remove),
 };
-
-static __init int ad5421_init(void)
-{
-	return spi_register_driver(&ad5421_driver);
-}
-module_init(ad5421_init);
-
-static __exit void ad5421_exit(void)
-{
-	spi_unregister_driver(&ad5421_driver);
-}
-module_exit(ad5421_exit);
+module_spi_driver(ad5421_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("Analog Devices AD5421 DAC");
diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c
index 693e748..633ffbb 100644
--- a/drivers/staging/iio/dac/ad5446.c
+++ b/drivers/staging/iio/dac/ad5446.c
@@ -149,30 +149,8 @@
 	NULL,
 };
 
-static umode_t ad5446_attr_is_visible(struct kobject *kobj,
-				     struct attribute *attr, int n)
-{
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct ad5446_state *st = iio_priv(indio_dev);
-
-	umode_t mode = attr->mode;
-
-	if (!st->chip_info->store_pwr_down &&
-		(attr == &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr ||
-		attr == &iio_dev_attr_out_voltage_powerdown_mode.
-		 dev_attr.attr ||
-		attr ==
-		&iio_const_attr_out_voltage_powerdown_mode_available.
-		 dev_attr.attr))
-		mode = 0;
-
-	return mode;
-}
-
 static const struct attribute_group ad5446_attribute_group = {
 	.attrs = ad5446_attributes,
-	.is_visible = ad5446_attr_is_visible,
 };
 
 #define AD5446_CHANNEL(bits, storage, shift) { \
@@ -321,6 +299,12 @@
 	.driver_module = THIS_MODULE,
 };
 
+static const struct iio_info ad5446_info_no_pwr_down = {
+	.read_raw = ad5446_read_raw,
+	.write_raw = ad5446_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
 static int __devinit ad5446_probe(struct spi_device *spi)
 {
 	struct ad5446_state *st;
@@ -350,10 +334,13 @@
 	st->reg = reg;
 	st->spi = spi;
 
-	/* Estabilish that the iio_dev is a child of the spi device */
+	/* Establish that the iio_dev is a child of the spi device */
 	indio_dev->dev.parent = &spi->dev;
 	indio_dev->name = spi_get_device_id(spi)->name;
-	indio_dev->info = &ad5446_info;
+	if (st->chip_info->store_pwr_down)
+		indio_dev->info = &ad5446_info;
+	else
+		indio_dev->info = &ad5446_info_no_pwr_down;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = &st->chip_info->channel;
 	indio_dev->num_channels = 1;
diff --git a/drivers/staging/iio/dac/ad5764.c b/drivers/staging/iio/dac/ad5764.c
index ff91480..f73a730 100644
--- a/drivers/staging/iio/dac/ad5764.c
+++ b/drivers/staging/iio/dac/ad5764.c
@@ -375,18 +375,7 @@
 	.remove = __devexit_p(ad5764_remove),
 	.id_table = ad5764_ids,
 };
-
-static int __init ad5764_spi_init(void)
-{
-	return spi_register_driver(&ad5764_driver);
-}
-module_init(ad5764_spi_init);
-
-static void __exit ad5764_spi_exit(void)
-{
-	spi_unregister_driver(&ad5764_driver);
-}
-module_exit(ad5764_spi_exit);
+module_spi_driver(ad5764_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("Analog Devices AD5744/AD5744R/AD5764/AD5764R DAC");
diff --git a/drivers/staging/iio/dac/max517.c b/drivers/staging/iio/dac/max517.c
index a4df6d7..41483c7 100644
--- a/drivers/staging/iio/dac/max517.c
+++ b/drivers/staging/iio/dac/max517.c
@@ -179,20 +179,27 @@
 	.attrs = max518_attributes,
 };
 
-static int max517_suspend(struct i2c_client *client, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+static int max517_suspend(struct device *dev)
 {
 	u8 outbuf = COMMAND_PD;
 
-	return i2c_master_send(client, &outbuf, 1);
+	return i2c_master_send(to_i2c_client(dev), &outbuf, 1);
 }
 
-static int max517_resume(struct i2c_client *client)
+static int max517_resume(struct device *dev)
 {
 	u8 outbuf = 0;
 
-	return i2c_master_send(client, &outbuf, 1);
+	return i2c_master_send(to_i2c_client(dev), &outbuf, 1);
 }
 
+static SIMPLE_DEV_PM_OPS(max517_pm_ops, max517_suspend, max517_resume);
+#define MAX517_PM_OPS (&max517_pm_ops)
+#else
+#define MAX517_PM_OPS NULL
+#endif
+
 static const struct iio_info max517_info = {
 	.attrs = &max517_attribute_group,
 	.driver_module = THIS_MODULE,
@@ -273,11 +280,10 @@
 static struct i2c_driver max517_driver = {
 	.driver = {
 		.name	= MAX517_DRV_NAME,
+		.pm		= MAX517_PM_OPS,
 	},
 	.probe		= max517_probe,
 	.remove		= max517_remove,
-	.suspend	= max517_suspend,
-	.resume		= max517_resume,
 	.id_table	= max517_id,
 };
 module_i2c_driver(max517_driver);
diff --git a/drivers/staging/iio/dds/ad9834.c b/drivers/staging/iio/dds/ad9834.c
index 5e67104..38a2de0 100644
--- a/drivers/staging/iio/dds/ad9834.c
+++ b/drivers/staging/iio/dds/ad9834.c
@@ -281,29 +281,27 @@
 	NULL,
 };
 
-static umode_t ad9834_attr_is_visible(struct kobject *kobj,
-				     struct attribute *attr, int n)
-{
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct ad9834_state *st = iio_priv(indio_dev);
-
-	umode_t mode = attr->mode;
-
-	if (((st->devid == ID_AD9833) || (st->devid == ID_AD9837)) &&
-		((attr == &iio_dev_attr_dds0_out1_enable.dev_attr.attr) ||
-		(attr == &iio_dev_attr_dds0_out1_wavetype.dev_attr.attr) ||
-		(attr ==
-		&iio_dev_attr_dds0_out1_wavetype_available.dev_attr.attr) ||
-		(attr == &iio_dev_attr_dds0_pincontrol_en.dev_attr.attr)))
-		mode = 0;
-
-	return mode;
-}
+static struct attribute *ad9833_attributes[] = {
+	&iio_dev_attr_dds0_freq0.dev_attr.attr,
+	&iio_dev_attr_dds0_freq1.dev_attr.attr,
+	&iio_const_attr_dds0_freq_scale.dev_attr.attr,
+	&iio_dev_attr_dds0_phase0.dev_attr.attr,
+	&iio_dev_attr_dds0_phase1.dev_attr.attr,
+	&iio_const_attr_dds0_phase_scale.dev_attr.attr,
+	&iio_dev_attr_dds0_freqsymbol.dev_attr.attr,
+	&iio_dev_attr_dds0_phasesymbol.dev_attr.attr,
+	&iio_dev_attr_dds0_out_enable.dev_attr.attr,
+	&iio_dev_attr_dds0_out0_wavetype.dev_attr.attr,
+	&iio_dev_attr_dds0_out0_wavetype_available.dev_attr.attr,
+	NULL,
+};
 
 static const struct attribute_group ad9834_attribute_group = {
 	.attrs = ad9834_attributes,
-	.is_visible = ad9834_attr_is_visible,
+};
+
+static const struct attribute_group ad9833_attribute_group = {
+	.attrs = ad9833_attributes,
 };
 
 static const struct iio_info ad9834_info = {
@@ -311,6 +309,11 @@
 	.driver_module = THIS_MODULE,
 };
 
+static const struct iio_info ad9833_info = {
+	.attrs = &ad9833_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
 static int __devinit ad9834_probe(struct spi_device *spi)
 {
 	struct ad9834_platform_data *pdata = spi->dev.platform_data;
@@ -344,7 +347,15 @@
 	st->reg = reg;
 	indio_dev->dev.parent = &spi->dev;
 	indio_dev->name = spi_get_device_id(spi)->name;
-	indio_dev->info = &ad9834_info;
+	switch (st->devid) {
+	case ID_AD9833:
+	case ID_AD9837:
+		indio_dev->info = &ad9833_info;
+		break;
+	default:
+		indio_dev->info = &ad9834_info;
+		break;
+	}
 	indio_dev->modes = INDIO_DIRECT_MODE;
 
 	/* Setup default messages */
diff --git a/drivers/staging/iio/driver.h b/drivers/staging/iio/driver.h
new file mode 100644
index 0000000..a4f8b2e
--- /dev/null
+++ b/drivers/staging/iio/driver.h
@@ -0,0 +1,34 @@
+/*
+ * Industrial I/O in kernel access map interface.
+ *
+ * Copyright (c) 2011 Jonathan Cameron
+ *
+ * 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 _IIO_INKERN_H_
+#define _IIO_INKERN_H_
+
+struct iio_map;
+
+/**
+ * iio_map_array_register() - tell the core about inkernel consumers
+ * @indio_dev:	provider device
+ * @map:	array of mappings specifying association of channel with client
+ */
+int iio_map_array_register(struct iio_dev *indio_dev,
+			   struct iio_map *map);
+
+/**
+ * iio_map_array_unregister() - tell the core to remove consumer mappings
+ * @indio_dev:	provider device
+ * @map:	array of mappings to remove. Note these must have same memory
+ *		addresses as those originally added not just equal parameter
+ *		values.
+ */
+int iio_map_array_unregister(struct iio_dev *indio_dev,
+			     struct iio_map *map);
+
+#endif
diff --git a/drivers/staging/iio/events.h b/drivers/staging/iio/events.h
index bfb6340..c25f0e3 100644
--- a/drivers/staging/iio/events.h
+++ b/drivers/staging/iio/events.h
@@ -96,8 +96,10 @@
 
 /* Event code number extraction depends on which type of event we have.
  * Perhaps review this function in the future*/
-#define IIO_EVENT_CODE_EXTRACT_NUM(mask) ((__s16)(mask & 0xFFFF))
+#define IIO_EVENT_CODE_EXTRACT_CHAN(mask) ((__s16)(mask & 0xFFFF))
+#define IIO_EVENT_CODE_EXTRACT_CHAN2(mask) ((__s16)(((mask) >> 16) & 0xFFFF))
 
 #define IIO_EVENT_CODE_EXTRACT_MODIFIER(mask) ((mask >> 40) & 0xFF)
+#define IIO_EVENT_CODE_EXTRACT_DIFF(mask) (((mask) >> 55) & 0x1)
 
 #endif
diff --git a/drivers/staging/iio/gyro/adis16260_ring.c b/drivers/staging/iio/gyro/adis16260_ring.c
index 699a615..711f151 100644
--- a/drivers/staging/iio/gyro/adis16260_ring.c
+++ b/drivers/staging/iio/gyro/adis16260_ring.c
@@ -115,8 +115,6 @@
 		return ret;
 	}
 	indio_dev->buffer = ring;
-	/* Effectively select the ring buffer implementation */
-	ring->access = &ring_sw_access_funcs;
 	ring->scan_timestamp = true;
 	indio_dev->setup_ops = &adis16260_ring_setup_ops;
 
diff --git a/drivers/staging/iio/iio.h b/drivers/staging/iio/iio.h
index be6ced3..b9cd454 100644
--- a/drivers/staging/iio/iio.h
+++ b/drivers/staging/iio/iio.h
@@ -26,7 +26,7 @@
 
 /* Could add the raw attributes as well - allowing buffer only devices */
 enum iio_chan_info_enum {
-	/* 0 is reserverd for raw attributes */
+	/* 0 is reserved for raw attributes */
 	IIO_CHAN_INFO_SCALE = 1,
 	IIO_CHAN_INFO_OFFSET,
 	IIO_CHAN_INFO_CALIBSCALE,
@@ -88,10 +88,29 @@
 	IIO_LE,
 };
 
+struct iio_chan_spec;
+struct iio_dev;
+
+/**
+ * struct iio_chan_spec_ext_info - Extended channel info attribute
+ * @name:	Info attribute name
+ * @shared:	Whether this attribute is shared between all channels.
+ * @read:	Read callback for this info attribute, may be NULL.
+ * @write:	Write callback for this info attribute, may be NULL.
+ */
+struct iio_chan_spec_ext_info {
+	const char *name;
+	bool shared;
+	ssize_t (*read)(struct iio_dev *, struct iio_chan_spec const *,
+			char *buf);
+	ssize_t (*write)(struct iio_dev *, struct iio_chan_spec const *,
+			const char *buf, size_t len);
+};
+
 /**
  * struct iio_chan_spec - specification of a single channel
  * @type:		What type of measurement is the channel making.
- * @channel:		What number or name do we wish to asign the channel.
+ * @channel:		What number or name do we wish to assign the channel.
  * @channel2:		If there is a second number for a differential
  *			channel then this is it. If modified is set then the
  *			value here specifies the modifier.
@@ -107,11 +126,14 @@
  * @info_mask:		What information is to be exported about this channel.
  *			This includes calibbias, scale etc.
  * @event_mask:	What events can this channel produce.
+ * @ext_info:		Array of extended info attributes for this channel.
+ *			The array is NULL terminated, the last element should
+ *			have it's name field set to NULL.
  * @extend_name:	Allows labeling of channel attributes with an
  *			informative name. Note this has no effect codes etc,
  *			unlike modifiers.
  * @datasheet_name:	A name used in in kernel mapping of channels. It should
- *			corrspond to the first name that the channel is referred
+ *			correspond to the first name that the channel is referred
  *			to by in the datasheet (e.g. IND), or the nearest
  *			possible compound name (e.g. IND-INC).
  * @processed_val:	Flag to specify the data access attribute should be
@@ -141,6 +163,7 @@
 	} scan_type;
 	long			info_mask;
 	long			event_mask;
+	const struct iio_chan_spec_ext_info *ext_info;
 	char			*extend_name;
 	const char		*datasheet_name;
 	unsigned		processed_val:1;
@@ -197,12 +220,6 @@
 #define INDIO_ALL_BUFFER_MODES					\
 	(INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE)
 
-/* Vast majority of this is set by the industrialio subsystem on a
- * call to iio_device_register. */
-#define IIO_VAL_INT 1
-#define IIO_VAL_INT_PLUS_MICRO 2
-#define IIO_VAL_INT_PLUS_NANO 3
-
 struct iio_trigger; /* forward declaration */
 struct iio_dev;
 
@@ -226,7 +243,7 @@
  * @write_event_config:	set if the event is enabled.
  * @read_event_value:	read a value associated with the event. Meaning
  *			is event dependant. event_code specifies which event.
- * @write_event_value:	write the value associate with the event.
+ * @write_event_value:	write the value associated with the event.
  *			Meaning is event dependent.
  * @validate_trigger:	function to validate the trigger when the
  *			current trigger gets changed.
@@ -269,6 +286,9 @@
 				struct iio_trigger *trig);
 	int (*update_scan_mode)(struct iio_dev *indio_dev,
 				const unsigned long *scan_mask);
+	int (*debugfs_reg_access)(struct iio_dev *indio_dev,
+				  unsigned reg, unsigned writeval,
+				  unsigned *readval);
 };
 
 /**
@@ -310,11 +330,14 @@
  * @chan_attr_group:	[INTERN] group for all attrs in base directory
  * @name:		[DRIVER] name of the device.
  * @info:		[DRIVER] callbacks and constant info from driver
+ * @info_exist_lock:	[INTERN] lock to prevent use during removal
  * @chrdev:		[INTERN] associated character device
  * @groups:		[INTERN] attribute groups
  * @groupcounter:	[INTERN] index of next attribute group
  * @flags:		[INTERN] file ops related flags including busy flag.
- **/
+ * @debugfs_dentry:	[INTERN] device specific debugfs dentry.
+ * @cached_reg_addr:	[INTERN] cached register address for debugfs reads.
+ */
 struct iio_dev {
 	int				id;
 
@@ -327,9 +350,9 @@
 	struct iio_buffer		*buffer;
 	struct mutex			mlock;
 
-	unsigned long			*available_scan_masks;
+	const unsigned long		*available_scan_masks;
 	unsigned			masklength;
-	unsigned long			*active_scan_mask;
+	const unsigned long		*active_scan_mask;
 	struct iio_trigger		*trig;
 	struct iio_poll_func		*pollfunc;
 
@@ -340,6 +363,7 @@
 	struct attribute_group		chan_attr_group;
 	const char			*name;
 	const struct iio_info		*info;
+	struct mutex			info_exist_lock;
 	const struct iio_buffer_setup_ops	*setup_ops;
 	struct cdev			chrdev;
 #define IIO_MAX_GROUPS 6
@@ -347,6 +371,10 @@
 	int				groupcounter;
 
 	unsigned long			flags;
+#if defined(CONFIG_DEBUG_FS)
+	struct dentry			*debugfs_dentry;
+	unsigned			cached_reg_addr;
+#endif
 };
 
 /**
@@ -424,4 +452,20 @@
 		& (INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE);
 };
 
+/**
+ * iio_get_debugfs_dentry() - helper function to get the debugfs_dentry
+ * @indio_dev:		IIO device info structure for device
+ **/
+#if defined(CONFIG_DEBUG_FS)
+static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
+{
+	return indio_dev->debugfs_dentry;
+};
+#else
+static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
+{
+	return NULL;
+};
+#endif
+
 #endif /* _INDUSTRIAL_IO_H_ */
diff --git a/drivers/staging/iio/iio_core.h b/drivers/staging/iio/iio_core.h
index 107cfb1..c9dfcba 100644
--- a/drivers/staging/iio/iio_core.h
+++ b/drivers/staging/iio/iio_core.h
@@ -49,4 +49,8 @@
 
 #endif
 
+int iio_device_register_eventset(struct iio_dev *indio_dev);
+void iio_device_unregister_eventset(struct iio_dev *indio_dev);
+int iio_event_getfd(struct iio_dev *indio_dev);
+
 #endif
diff --git a/drivers/staging/iio/iio_dummy_evgen.c b/drivers/staging/iio/iio_dummy_evgen.c
index cdbf289..f39f346 100644
--- a/drivers/staging/iio/iio_dummy_evgen.c
+++ b/drivers/staging/iio/iio_dummy_evgen.c
@@ -32,7 +32,7 @@
  * @chip: irq chip we are faking
  * @base: base of irq range
  * @enabled: mask of which irqs are enabled
- * @inuse: mask of which irqs actually have anyone connected
+ * @inuse: mask of which irqs are connected
  * @lock: protect the evgen state
  */
 struct iio_dummy_eventgen {
diff --git a/drivers/staging/iio/iio_hwmon.c b/drivers/staging/iio/iio_hwmon.c
new file mode 100644
index 0000000..a603a5f
--- /dev/null
+++ b/drivers/staging/iio/iio_hwmon.c
@@ -0,0 +1,232 @@
+/* Hwmon client for industrial I/O devices
+ *
+ * Copyright (c) 2011 Jonathan Cameron
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include "consumer.h"
+#include "types.h"
+
+/**
+ * struct iio_hwmon_state - device instance state
+ * @channels:		filled with array of channels from iio
+ * @num_channels:	number of channels in channels (saves counting twice)
+ * @hwmon_dev:		associated hwmon device
+ * @attr_group:	the group of attributes
+ * @attrs:		null terminated array of attribute pointers.
+ */
+struct iio_hwmon_state {
+	struct iio_channel *channels;
+	int num_channels;
+	struct device *hwmon_dev;
+	struct attribute_group attr_group;
+	struct attribute **attrs;
+};
+
+/*
+ * Assumes that IIO and hwmon operate in the same base units.
+ * This is supposed to be true, but needs verification for
+ * new channel types.
+ */
+static ssize_t iio_hwmon_read_val(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	long result;
+	int val, ret, scaleint, scalepart;
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct iio_hwmon_state *state = dev_get_drvdata(dev);
+
+	/*
+	 * No locking between this pair, so theoretically possible
+	 * the scale has changed.
+	 */
+	ret = iio_st_read_channel_raw(&state->channels[sattr->index],
+				      &val);
+	if (ret < 0)
+		return ret;
+
+	ret = iio_st_read_channel_scale(&state->channels[sattr->index],
+					&scaleint, &scalepart);
+	if (ret < 0)
+		return ret;
+	switch (ret) {
+	case IIO_VAL_INT:
+		result = val * scaleint;
+		break;
+	case IIO_VAL_INT_PLUS_MICRO:
+		result = (s64)val * (s64)scaleint +
+			div_s64((s64)val * (s64)scalepart, 1000000LL);
+		break;
+	case IIO_VAL_INT_PLUS_NANO:
+		result = (s64)val * (s64)scaleint +
+			div_s64((s64)val * (s64)scalepart, 1000000000LL);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return sprintf(buf, "%ld\n", result);
+}
+
+static void iio_hwmon_free_attrs(struct iio_hwmon_state *st)
+{
+	int i;
+	struct sensor_device_attribute *a;
+	for (i = 0; i < st->num_channels; i++)
+		if (st->attrs[i]) {
+			a = to_sensor_dev_attr(
+				container_of(st->attrs[i],
+					     struct device_attribute,
+					     attr));
+			kfree(a);
+		}
+}
+
+static int __devinit iio_hwmon_probe(struct platform_device *pdev)
+{
+	struct iio_hwmon_state *st;
+	struct sensor_device_attribute *a;
+	int ret, i;
+	int in_i = 1, temp_i = 1, curr_i = 1;
+	enum iio_chan_type type;
+
+	st = kzalloc(sizeof(*st), GFP_KERNEL);
+	if (st == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	st->channels = iio_st_channel_get_all(dev_name(&pdev->dev));
+	if (IS_ERR(st->channels)) {
+		ret = PTR_ERR(st->channels);
+		goto error_free_state;
+	}
+
+	/* count how many attributes we have */
+	while (st->channels[st->num_channels].indio_dev)
+		st->num_channels++;
+
+	st->attrs = kzalloc(sizeof(st->attrs) * (st->num_channels + 1),
+			    GFP_KERNEL);
+	if (st->attrs == NULL) {
+		ret = -ENOMEM;
+		goto error_release_channels;
+	}
+	for (i = 0; i < st->num_channels; i++) {
+		a = kzalloc(sizeof(*a), GFP_KERNEL);
+		if (a == NULL) {
+			ret = -ENOMEM;
+			goto error_free_attrs;
+		}
+
+		sysfs_attr_init(&a->dev_attr.attr);
+		ret = iio_st_get_channel_type(&st->channels[i], &type);
+		if (ret < 0) {
+			kfree(a);
+			goto error_free_attrs;
+		}
+		switch (type) {
+		case IIO_VOLTAGE:
+			a->dev_attr.attr.name = kasprintf(GFP_KERNEL,
+							  "in%d_input",
+							  in_i++);
+			break;
+		case IIO_TEMP:
+			a->dev_attr.attr.name = kasprintf(GFP_KERNEL,
+							  "temp%d_input",
+							  temp_i++);
+			break;
+		case IIO_CURRENT:
+			a->dev_attr.attr.name = kasprintf(GFP_KERNEL,
+							  "curr%d_input",
+							  curr_i++);
+			break;
+		default:
+			ret = -EINVAL;
+			kfree(a);
+			goto error_free_attrs;
+		}
+		if (a->dev_attr.attr.name == NULL) {
+			kfree(a);
+			ret = -ENOMEM;
+			goto error_free_attrs;
+		}
+		a->dev_attr.show = iio_hwmon_read_val;
+		a->dev_attr.attr.mode = S_IRUGO;
+		a->index = i;
+		st->attrs[i] = &a->dev_attr.attr;
+	}
+
+	st->attr_group.attrs = st->attrs;
+	platform_set_drvdata(pdev, st);
+	ret = sysfs_create_group(&pdev->dev.kobj, &st->attr_group);
+	if (ret < 0)
+		goto error_free_attrs;
+
+	st->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(st->hwmon_dev)) {
+		ret = PTR_ERR(st->hwmon_dev);
+		goto error_remove_group;
+	}
+	return 0;
+
+error_remove_group:
+	sysfs_remove_group(&pdev->dev.kobj, &st->attr_group);
+error_free_attrs:
+	iio_hwmon_free_attrs(st);
+	kfree(st->attrs);
+error_release_channels:
+	iio_st_channel_release_all(st->channels);
+error_free_state:
+	kfree(st);
+error_ret:
+	return ret;
+}
+
+static int __devexit iio_hwmon_remove(struct platform_device *pdev)
+{
+	struct iio_hwmon_state *st = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(st->hwmon_dev);
+	sysfs_remove_group(&pdev->dev.kobj, &st->attr_group);
+	iio_hwmon_free_attrs(st);
+	kfree(st->attrs);
+	iio_st_channel_release_all(st->channels);
+
+	return 0;
+}
+
+static struct platform_driver __refdata iio_hwmon_driver = {
+	.driver = {
+		.name = "iio_hwmon",
+		.owner = THIS_MODULE,
+	},
+	.probe = iio_hwmon_probe,
+	.remove = __devexit_p(iio_hwmon_remove),
+};
+
+static int iio_inkern_init(void)
+{
+	return platform_driver_register(&iio_hwmon_driver);
+}
+module_init(iio_inkern_init);
+
+static void iio_inkern_exit(void)
+{
+	platform_driver_unregister(&iio_hwmon_driver);
+}
+module_exit(iio_inkern_exit);
+
+MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
+MODULE_DESCRIPTION("IIO to hwmon driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c
index d6a1c0e..bb4daf7 100644
--- a/drivers/staging/iio/iio_simple_dummy_buffer.c
+++ b/drivers/staging/iio/iio_simple_dummy_buffer.c
@@ -142,8 +142,6 @@
 	}
 
 	indio_dev->buffer = buffer;
-	/* Tell the core how to access the buffer */
-	buffer->access = &kfifo_access_funcs;
 
 	/* Enable timestamps by default */
 	buffer->scan_timestamp = true;
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index 9a2ca55..cd82b56 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -607,9 +607,6 @@
 	if (!indio_dev->buffer)
 		return -ENOMEM;
 
-	/* Effectively select the ring buffer implementation */
-	indio_dev->buffer->access = &ring_sw_access_funcs;
-
 	/* Ring buffer functions - here trigger setup related */
 	indio_dev->setup_ops = &ad5933_ring_setup_ops;
 
diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c
index ac22de5..8daa038 100644
--- a/drivers/staging/iio/imu/adis16400_ring.c
+++ b/drivers/staging/iio/imu/adis16400_ring.c
@@ -187,8 +187,6 @@
 		return ret;
 	}
 	indio_dev->buffer = ring;
-	/* Effectively select the ring buffer implementation */
-	ring->access = &ring_sw_access_funcs;
 	ring->scan_timestamp = true;
 	indio_dev->setup_ops = &adis16400_ring_setup_ops;
 
diff --git a/drivers/staging/iio/industrialio-buffer.c b/drivers/staging/iio/industrialio-buffer.c
index d7b1e9e..386ba76 100644
--- a/drivers/staging/iio/industrialio-buffer.c
+++ b/drivers/staging/iio/industrialio-buffer.c
@@ -489,9 +489,9 @@
 EXPORT_SYMBOL(iio_buffer_show_enable);
 
 /* note NULL used as error indicator as it doesn't make sense. */
-static unsigned long *iio_scan_mask_match(unsigned long *av_masks,
+static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks,
 					  unsigned int masklength,
-					  unsigned long *mask)
+					  const unsigned long *mask)
 {
 	if (bitmap_empty(mask, masklength))
 		return NULL;
@@ -554,7 +554,7 @@
 int iio_scan_mask_set(struct iio_dev *indio_dev,
 		      struct iio_buffer *buffer, int bit)
 {
-	unsigned long *mask;
+	const unsigned long *mask;
 	unsigned long *trialmask;
 
 	trialmask = kmalloc(sizeof(*trialmask)*
diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c
index 19f897f..d303bfb 100644
--- a/drivers/staging/iio/industrialio-core.c
+++ b/drivers/staging/iio/industrialio-core.c
@@ -22,6 +22,7 @@
 #include <linux/cdev.h>
 #include <linux/slab.h>
 #include <linux/anon_inodes.h>
+#include <linux/debugfs.h>
 #include "iio.h"
 #include "iio_core.h"
 #include "iio_core_trigger.h"
@@ -39,6 +40,8 @@
 };
 EXPORT_SYMBOL(iio_bus_type);
 
+static struct dentry *iio_debugfs_dentry;
+
 static const char * const iio_data_type_name[] = {
 	[IIO_RAW] = "raw",
 	[IIO_PROCESSED] = "input",
@@ -100,71 +103,6 @@
 	return NULL;
 }
 
-/**
- * struct iio_detected_event_list - list element for events that have occurred
- * @list:		linked list header
- * @ev:			the event itself
- */
-struct iio_detected_event_list {
-	struct list_head		list;
-	struct iio_event_data		ev;
-};
-
-/**
- * struct iio_event_interface - chrdev interface for an event line
- * @dev:		device assocated with event interface
- * @wait:		wait queue to allow blocking reads of events
- * @event_list_lock:	mutex to protect the list of detected events
- * @det_events:		list of detected events
- * @max_events:		maximum number of events before new ones are dropped
- * @current_events:	number of events in detected list
- * @flags:		file operations related flags including busy flag.
- */
-struct iio_event_interface {
-	wait_queue_head_t			wait;
-	struct mutex				event_list_lock;
-	struct list_head			det_events;
-	int					max_events;
-	int					current_events;
-	struct list_head dev_attr_list;
-	unsigned long flags;
-	struct attribute_group			group;
-};
-
-int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
-{
-	struct iio_event_interface *ev_int = indio_dev->event_interface;
-	struct iio_detected_event_list *ev;
-	int ret = 0;
-
-	/* Does anyone care? */
-	mutex_lock(&ev_int->event_list_lock);
-	if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
-		if (ev_int->current_events == ev_int->max_events) {
-			mutex_unlock(&ev_int->event_list_lock);
-			return 0;
-		}
-		ev = kmalloc(sizeof(*ev), GFP_KERNEL);
-		if (ev == NULL) {
-			ret = -ENOMEM;
-			mutex_unlock(&ev_int->event_list_lock);
-			goto error_ret;
-		}
-		ev->ev.id = ev_code;
-		ev->ev.timestamp = timestamp;
-
-		list_add_tail(&ev->list, &ev_int->det_events);
-		ev_int->current_events++;
-		mutex_unlock(&ev_int->event_list_lock);
-		wake_up_interruptible(&ev_int->wait);
-	} else
-		mutex_unlock(&ev_int->event_list_lock);
-
-error_ret:
-	return ret;
-}
-EXPORT_SYMBOL(iio_push_event);
-
 /* This turns up an awful lot */
 ssize_t iio_read_const_attr(struct device *dev,
 			    struct device_attribute *attr,
@@ -174,110 +112,6 @@
 }
 EXPORT_SYMBOL(iio_read_const_attr);
 
-static ssize_t iio_event_chrdev_read(struct file *filep,
-				     char __user *buf,
-				     size_t count,
-				     loff_t *f_ps)
-{
-	struct iio_event_interface *ev_int = filep->private_data;
-	struct iio_detected_event_list *el;
-	size_t len = sizeof(el->ev);
-	int ret;
-
-	if (count < len)
-		return -EINVAL;
-
-	mutex_lock(&ev_int->event_list_lock);
-	if (list_empty(&ev_int->det_events)) {
-		if (filep->f_flags & O_NONBLOCK) {
-			ret = -EAGAIN;
-			goto error_mutex_unlock;
-		}
-		mutex_unlock(&ev_int->event_list_lock);
-		/* Blocking on device; waiting for something to be there */
-		ret = wait_event_interruptible(ev_int->wait,
-					       !list_empty(&ev_int
-							   ->det_events));
-		if (ret)
-			goto error_ret;
-		/* Single access device so no one else can get the data */
-		mutex_lock(&ev_int->event_list_lock);
-	}
-
-	el = list_first_entry(&ev_int->det_events,
-			      struct iio_detected_event_list,
-			      list);
-	if (copy_to_user(buf, &(el->ev), len)) {
-		ret = -EFAULT;
-		goto error_mutex_unlock;
-	}
-	list_del(&el->list);
-	ev_int->current_events--;
-	mutex_unlock(&ev_int->event_list_lock);
-	kfree(el);
-
-	return len;
-
-error_mutex_unlock:
-	mutex_unlock(&ev_int->event_list_lock);
-error_ret:
-
-	return ret;
-}
-
-static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
-{
-	struct iio_event_interface *ev_int = filep->private_data;
-	struct iio_detected_event_list *el, *t;
-
-	mutex_lock(&ev_int->event_list_lock);
-	clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
-	/*
-	 * In order to maintain a clean state for reopening,
-	 * clear out any awaiting events. The mask will prevent
-	 * any new __iio_push_event calls running.
-	 */
-	list_for_each_entry_safe(el, t, &ev_int->det_events, list) {
-		list_del(&el->list);
-		kfree(el);
-	}
-	ev_int->current_events = 0;
-	mutex_unlock(&ev_int->event_list_lock);
-
-	return 0;
-}
-
-static const struct file_operations iio_event_chrdev_fileops = {
-	.read =  iio_event_chrdev_read,
-	.release = iio_event_chrdev_release,
-	.owner = THIS_MODULE,
-	.llseek = noop_llseek,
-};
-
-static int iio_event_getfd(struct iio_dev *indio_dev)
-{
-	struct iio_event_interface *ev_int = indio_dev->event_interface;
-	int fd;
-
-	if (ev_int == NULL)
-		return -ENODEV;
-
-	mutex_lock(&ev_int->event_list_lock);
-	if (test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
-		mutex_unlock(&ev_int->event_list_lock);
-		return -EBUSY;
-	}
-	mutex_unlock(&ev_int->event_list_lock);
-	fd = anon_inode_getfd("iio:event",
-				&iio_event_chrdev_fileops, ev_int, O_RDONLY);
-	if (fd < 0) {
-		mutex_lock(&ev_int->event_list_lock);
-		clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
-		mutex_unlock(&ev_int->event_list_lock);
-	}
-	return fd;
-}
-
 static int __init iio_init(void)
 {
 	int ret;
@@ -298,6 +132,8 @@
 		goto error_unregister_bus_type;
 	}
 
+	iio_debugfs_dentry = debugfs_create_dir("iio", NULL);
+
 	return 0;
 
 error_unregister_bus_type:
@@ -311,6 +147,154 @@
 	if (iio_devt)
 		unregister_chrdev_region(iio_devt, IIO_DEV_MAX);
 	bus_unregister(&iio_bus_type);
+	debugfs_remove(iio_debugfs_dentry);
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static int iio_debugfs_open(struct inode *inode, struct file *file)
+{
+	if (inode->i_private)
+		file->private_data = inode->i_private;
+
+	return 0;
+}
+
+static ssize_t iio_debugfs_read_reg(struct file *file, char __user *userbuf,
+			      size_t count, loff_t *ppos)
+{
+	struct iio_dev *indio_dev = file->private_data;
+	char buf[20];
+	unsigned val = 0;
+	ssize_t len;
+	int ret;
+
+	ret = indio_dev->info->debugfs_reg_access(indio_dev,
+						  indio_dev->cached_reg_addr,
+						  0, &val);
+	if (ret)
+		dev_err(indio_dev->dev.parent, "%s: read failed\n", __func__);
+
+	len = snprintf(buf, sizeof(buf), "0x%X\n", val);
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+static ssize_t iio_debugfs_write_reg(struct file *file,
+		     const char __user *userbuf, size_t count, loff_t *ppos)
+{
+	struct iio_dev *indio_dev = file->private_data;
+	unsigned reg, val;
+	char buf[80];
+	int ret;
+
+	count = min_t(size_t, count, (sizeof(buf)-1));
+	if (copy_from_user(buf, userbuf, count))
+		return -EFAULT;
+
+	buf[count] = 0;
+
+	ret = sscanf(buf, "%i %i", &reg, &val);
+
+	switch (ret) {
+	case 1:
+		indio_dev->cached_reg_addr = reg;
+		break;
+	case 2:
+		indio_dev->cached_reg_addr = reg;
+		ret = indio_dev->info->debugfs_reg_access(indio_dev, reg,
+							  val, NULL);
+		if (ret) {
+			dev_err(indio_dev->dev.parent, "%s: write failed\n",
+				__func__);
+			return ret;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static const struct file_operations iio_debugfs_reg_fops = {
+	.open = iio_debugfs_open,
+	.read = iio_debugfs_read_reg,
+	.write = iio_debugfs_write_reg,
+};
+
+static void iio_device_unregister_debugfs(struct iio_dev *indio_dev)
+{
+	debugfs_remove_recursive(indio_dev->debugfs_dentry);
+}
+
+static int iio_device_register_debugfs(struct iio_dev *indio_dev)
+{
+	struct dentry *d;
+
+	if (indio_dev->info->debugfs_reg_access == NULL)
+		return 0;
+
+	if (IS_ERR(iio_debugfs_dentry))
+		return 0;
+
+	indio_dev->debugfs_dentry =
+		debugfs_create_dir(dev_name(&indio_dev->dev),
+				   iio_debugfs_dentry);
+	if (IS_ERR(indio_dev->debugfs_dentry))
+		return PTR_ERR(indio_dev->debugfs_dentry);
+
+	if (indio_dev->debugfs_dentry == NULL) {
+		dev_warn(indio_dev->dev.parent,
+			 "Failed to create debugfs directory\n");
+		return -EFAULT;
+	}
+
+	d = debugfs_create_file("direct_reg_access", 0644,
+				indio_dev->debugfs_dentry,
+				indio_dev, &iio_debugfs_reg_fops);
+	if (!d) {
+		iio_device_unregister_debugfs(indio_dev);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+#else
+static int iio_device_register_debugfs(struct iio_dev *indio_dev)
+{
+	return 0;
+}
+
+static void iio_device_unregister_debugfs(struct iio_dev *indio_dev)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static ssize_t iio_read_channel_ext_info(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	const struct iio_chan_spec_ext_info *ext_info;
+
+	ext_info = &this_attr->c->ext_info[this_attr->address];
+
+	return ext_info->read(indio_dev, this_attr->c, buf);
+}
+
+static ssize_t iio_write_channel_ext_info(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf,
+					 size_t len)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	const struct iio_chan_spec_ext_info *ext_info;
+
+	ext_info = &this_attr->c->ext_info[this_attr->address];
+
+	return ext_info->write(indio_dev, this_attr->c, buf, len);
 }
 
 static ssize_t iio_read_channel_info(struct device *dev,
@@ -455,7 +439,7 @@
 		goto error_ret;
 	}
 
-	if (chan->differential) { /* Differential  can not have modifier */
+	if (chan->differential) { /* Differential can not have modifier */
 		if (generic)
 			name_format
 				= kasprintf(GFP_KERNEL, "%s_%s-%s_%s",
@@ -592,6 +576,7 @@
 					struct iio_chan_spec const *chan)
 {
 	int ret, i, attrcount = 0;
+	const struct iio_chan_spec_ext_info *ext_info;
 
 	if (chan->channel < 0)
 		return 0;
@@ -626,6 +611,31 @@
 			goto error_ret;
 		attrcount++;
 	}
+
+	if (chan->ext_info) {
+		unsigned int i = 0;
+		for (ext_info = chan->ext_info; ext_info->name; ext_info++) {
+			ret = __iio_add_chan_devattr(ext_info->name,
+					chan,
+					ext_info->read ?
+					    &iio_read_channel_ext_info : NULL,
+					ext_info->write ?
+					    &iio_write_channel_ext_info : NULL,
+					i,
+					ext_info->shared,
+					&indio_dev->dev,
+					&indio_dev->channel_attr_list);
+			i++;
+			if (ret == -EBUSY && ext_info->shared)
+				continue;
+
+			if (ret)
+				goto error_ret;
+
+			attrcount++;
+		}
+	}
+
 	ret = attrcount;
 error_ret:
 	return ret;
@@ -663,7 +673,7 @@
 	attrcount = attrcount_orig;
 	/*
 	 * New channel registration method - relies on the fact a group does
-	 *  not need to be initialized if it is name is NULL.
+	 * not need to be initialized if it is name is NULL.
 	 */
 	INIT_LIST_HEAD(&indio_dev->channel_attr_list);
 	if (indio_dev->channels)
@@ -726,295 +736,6 @@
 	kfree(indio_dev->chan_attr_group.attrs);
 }
 
-static const char * const iio_ev_type_text[] = {
-	[IIO_EV_TYPE_THRESH] = "thresh",
-	[IIO_EV_TYPE_MAG] = "mag",
-	[IIO_EV_TYPE_ROC] = "roc",
-	[IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
-	[IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
-};
-
-static const char * const iio_ev_dir_text[] = {
-	[IIO_EV_DIR_EITHER] = "either",
-	[IIO_EV_DIR_RISING] = "rising",
-	[IIO_EV_DIR_FALLING] = "falling"
-};
-
-static ssize_t iio_ev_state_store(struct device *dev,
-				  struct device_attribute *attr,
-				  const char *buf,
-				  size_t len)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	int ret;
-	bool val;
-
-	ret = strtobool(buf, &val);
-	if (ret < 0)
-		return ret;
-
-	ret = indio_dev->info->write_event_config(indio_dev,
-						  this_attr->address,
-						  val);
-	return (ret < 0) ? ret : len;
-}
-
-static ssize_t iio_ev_state_show(struct device *dev,
-				 struct device_attribute *attr,
-				 char *buf)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	int val = indio_dev->info->read_event_config(indio_dev,
-						     this_attr->address);
-
-	if (val < 0)
-		return val;
-	else
-		return sprintf(buf, "%d\n", val);
-}
-
-static ssize_t iio_ev_value_show(struct device *dev,
-				 struct device_attribute *attr,
-				 char *buf)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	int val, ret;
-
-	ret = indio_dev->info->read_event_value(indio_dev,
-						this_attr->address, &val);
-	if (ret < 0)
-		return ret;
-
-	return sprintf(buf, "%d\n", val);
-}
-
-static ssize_t iio_ev_value_store(struct device *dev,
-				  struct device_attribute *attr,
-				  const char *buf,
-				  size_t len)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	unsigned long val;
-	int ret;
-
-	if (!indio_dev->info->write_event_value)
-		return -EINVAL;
-
-	ret = strict_strtoul(buf, 10, &val);
-	if (ret)
-		return ret;
-
-	ret = indio_dev->info->write_event_value(indio_dev, this_attr->address,
-						 val);
-	if (ret < 0)
-		return ret;
-
-	return len;
-}
-
-static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
-				      struct iio_chan_spec const *chan)
-{
-	int ret = 0, i, attrcount = 0;
-	u64 mask = 0;
-	char *postfix;
-	if (!chan->event_mask)
-		return 0;
-
-	for_each_set_bit(i, &chan->event_mask, sizeof(chan->event_mask)*8) {
-		postfix = kasprintf(GFP_KERNEL, "%s_%s_en",
-				    iio_ev_type_text[i/IIO_EV_DIR_MAX],
-				    iio_ev_dir_text[i%IIO_EV_DIR_MAX]);
-		if (postfix == NULL) {
-			ret = -ENOMEM;
-			goto error_ret;
-		}
-		if (chan->modified)
-			mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel,
-						  i/IIO_EV_DIR_MAX,
-						  i%IIO_EV_DIR_MAX);
-		else if (chan->differential)
-			mask = IIO_EVENT_CODE(chan->type,
-					      0, 0,
-					      i%IIO_EV_DIR_MAX,
-					      i/IIO_EV_DIR_MAX,
-					      0,
-					      chan->channel,
-					      chan->channel2);
-		else
-			mask = IIO_UNMOD_EVENT_CODE(chan->type,
-						    chan->channel,
-						    i/IIO_EV_DIR_MAX,
-						    i%IIO_EV_DIR_MAX);
-
-		ret = __iio_add_chan_devattr(postfix,
-					     chan,
-					     &iio_ev_state_show,
-					     iio_ev_state_store,
-					     mask,
-					     0,
-					     &indio_dev->dev,
-					     &indio_dev->event_interface->
-					     dev_attr_list);
-		kfree(postfix);
-		if (ret)
-			goto error_ret;
-		attrcount++;
-		postfix = kasprintf(GFP_KERNEL, "%s_%s_value",
-				    iio_ev_type_text[i/IIO_EV_DIR_MAX],
-				    iio_ev_dir_text[i%IIO_EV_DIR_MAX]);
-		if (postfix == NULL) {
-			ret = -ENOMEM;
-			goto error_ret;
-		}
-		ret = __iio_add_chan_devattr(postfix, chan,
-					     iio_ev_value_show,
-					     iio_ev_value_store,
-					     mask,
-					     0,
-					     &indio_dev->dev,
-					     &indio_dev->event_interface->
-					     dev_attr_list);
-		kfree(postfix);
-		if (ret)
-			goto error_ret;
-		attrcount++;
-	}
-	ret = attrcount;
-error_ret:
-	return ret;
-}
-
-static inline void __iio_remove_event_config_attrs(struct iio_dev *indio_dev)
-{
-	struct iio_dev_attr *p, *n;
-	list_for_each_entry_safe(p, n,
-				 &indio_dev->event_interface->
-				 dev_attr_list, l) {
-		kfree(p->dev_attr.attr.name);
-		kfree(p);
-	}
-}
-
-static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev)
-{
-	int j, ret, attrcount = 0;
-
-	INIT_LIST_HEAD(&indio_dev->event_interface->dev_attr_list);
-	/* Dynically created from the channels array */
-	for (j = 0; j < indio_dev->num_channels; j++) {
-		ret = iio_device_add_event_sysfs(indio_dev,
-						 &indio_dev->channels[j]);
-		if (ret < 0)
-			goto error_clear_attrs;
-		attrcount += ret;
-	}
-	return attrcount;
-
-error_clear_attrs:
-	__iio_remove_event_config_attrs(indio_dev);
-
-	return ret;
-}
-
-static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev)
-{
-	int j;
-
-	for (j = 0; j < indio_dev->num_channels; j++)
-		if (indio_dev->channels[j].event_mask != 0)
-			return true;
-	return false;
-}
-
-static void iio_setup_ev_int(struct iio_event_interface *ev_int)
-{
-	mutex_init(&ev_int->event_list_lock);
-	/* discussion point - make this variable? */
-	ev_int->max_events = 10;
-	ev_int->current_events = 0;
-	INIT_LIST_HEAD(&ev_int->det_events);
-	init_waitqueue_head(&ev_int->wait);
-}
-
-static const char *iio_event_group_name = "events";
-static int iio_device_register_eventset(struct iio_dev *indio_dev)
-{
-	struct iio_dev_attr *p;
-	int ret = 0, attrcount_orig = 0, attrcount, attrn;
-	struct attribute **attr;
-
-	if (!(indio_dev->info->event_attrs ||
-	      iio_check_for_dynamic_events(indio_dev)))
-		return 0;
-
-	indio_dev->event_interface =
-		kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL);
-	if (indio_dev->event_interface == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-
-	iio_setup_ev_int(indio_dev->event_interface);
-	if (indio_dev->info->event_attrs != NULL) {
-		attr = indio_dev->info->event_attrs->attrs;
-		while (*attr++ != NULL)
-			attrcount_orig++;
-	}
-	attrcount = attrcount_orig;
-	if (indio_dev->channels) {
-		ret = __iio_add_event_config_attrs(indio_dev);
-		if (ret < 0)
-			goto error_free_setup_event_lines;
-		attrcount += ret;
-	}
-
-	indio_dev->event_interface->group.name = iio_event_group_name;
-	indio_dev->event_interface->group.attrs = kcalloc(attrcount + 1,
-							  sizeof(indio_dev->event_interface->group.attrs[0]),
-							  GFP_KERNEL);
-	if (indio_dev->event_interface->group.attrs == NULL) {
-		ret = -ENOMEM;
-		goto error_free_setup_event_lines;
-	}
-	if (indio_dev->info->event_attrs)
-		memcpy(indio_dev->event_interface->group.attrs,
-		       indio_dev->info->event_attrs->attrs,
-		       sizeof(indio_dev->event_interface->group.attrs[0])
-		       *attrcount_orig);
-	attrn = attrcount_orig;
-	/* Add all elements from the list. */
-	list_for_each_entry(p,
-			    &indio_dev->event_interface->dev_attr_list,
-			    l)
-		indio_dev->event_interface->group.attrs[attrn++] =
-			&p->dev_attr.attr;
-	indio_dev->groups[indio_dev->groupcounter++] =
-		&indio_dev->event_interface->group;
-
-	return 0;
-
-error_free_setup_event_lines:
-	__iio_remove_event_config_attrs(indio_dev);
-	kfree(indio_dev->event_interface);
-error_ret:
-
-	return ret;
-}
-
-static void iio_device_unregister_eventset(struct iio_dev *indio_dev)
-{
-	if (indio_dev->event_interface == NULL)
-		return;
-	__iio_remove_event_config_attrs(indio_dev);
-	kfree(indio_dev->event_interface->group.attrs);
-	kfree(indio_dev->event_interface);
-}
-
 static void iio_dev_release(struct device *device)
 {
 	struct iio_dev *indio_dev = container_of(device, struct iio_dev, dev);
@@ -1023,6 +744,7 @@
 		iio_device_unregister_trigger_consumer(indio_dev);
 	iio_device_unregister_eventset(indio_dev);
 	iio_device_unregister_sysfs(indio_dev);
+	iio_device_unregister_debugfs(indio_dev);
 }
 
 static struct device_type iio_dev_type = {
@@ -1052,6 +774,7 @@
 		device_initialize(&dev->dev);
 		dev_set_drvdata(&dev->dev, (void *)dev);
 		mutex_init(&dev->mlock);
+		mutex_init(&dev->info_exist_lock);
 
 		dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL);
 		if (dev->id < 0) {
@@ -1131,6 +854,8 @@
 	.compat_ioctl = iio_ioctl,
 };
 
+static const struct iio_buffer_setup_ops noop_ring_setup_ops;
+
 int iio_device_register(struct iio_dev *indio_dev)
 {
 	int ret;
@@ -1138,11 +863,17 @@
 	/* configure elements for the chrdev */
 	indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
 
+	ret = iio_device_register_debugfs(indio_dev);
+	if (ret) {
+		dev_err(indio_dev->dev.parent,
+			"Failed to register debugfs interfaces\n");
+		goto error_ret;
+	}
 	ret = iio_device_register_sysfs(indio_dev);
 	if (ret) {
 		dev_err(indio_dev->dev.parent,
 			"Failed to register sysfs interfaces\n");
-		goto error_ret;
+		goto error_unreg_debugfs;
 	}
 	ret = iio_device_register_eventset(indio_dev);
 	if (ret) {
@@ -1153,6 +884,10 @@
 	if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
 		iio_device_register_trigger_consumer(indio_dev);
 
+	if ((indio_dev->modes & INDIO_ALL_BUFFER_MODES) &&
+		indio_dev->setup_ops == NULL)
+		indio_dev->setup_ops = &noop_ring_setup_ops;
+
 	ret = device_add(&indio_dev->dev);
 	if (ret < 0)
 		goto error_unreg_eventset;
@@ -1169,6 +904,8 @@
 	iio_device_unregister_eventset(indio_dev);
 error_free_sysfs:
 	iio_device_unregister_sysfs(indio_dev);
+error_unreg_debugfs:
+	iio_device_unregister_debugfs(indio_dev);
 error_ret:
 	return ret;
 }
@@ -1176,6 +913,9 @@
 
 void iio_device_unregister(struct iio_dev *indio_dev)
 {
+	mutex_lock(&indio_dev->info_exist_lock);
+	indio_dev->info = NULL;
+	mutex_unlock(&indio_dev->info_exist_lock);
 	device_unregister(&indio_dev->dev);
 }
 EXPORT_SYMBOL(iio_device_unregister);
diff --git a/drivers/staging/iio/industrialio-event.c b/drivers/staging/iio/industrialio-event.c
new file mode 100644
index 0000000..5fdf739
--- /dev/null
+++ b/drivers/staging/iio/industrialio-event.c
@@ -0,0 +1,453 @@
+/* Industrial I/O event handling
+ *
+ * Copyright (c) 2008 Jonathan Cameron
+ *
+ * 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.
+ *
+ * Based on elements of hwmon and input subsystems.
+ */
+
+#include <linux/anon_inodes.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/kfifo.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include "iio.h"
+#include "iio_core.h"
+#include "sysfs.h"
+#include "events.h"
+
+/**
+ * struct iio_event_interface - chrdev interface for an event line
+ * @wait:		wait queue to allow blocking reads of events
+ * @det_events:		list of detected events
+ * @dev_attr_list:	list of event interface sysfs attribute
+ * @flags:		file operations related flags including busy flag.
+ * @group:		event interface sysfs attribute group
+ */
+struct iio_event_interface {
+	wait_queue_head_t	wait;
+	DECLARE_KFIFO(det_events, struct iio_event_data, 16);
+
+	struct list_head	dev_attr_list;
+	unsigned long		flags;
+	struct attribute_group	group;
+};
+
+int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
+{
+	struct iio_event_interface *ev_int = indio_dev->event_interface;
+	struct iio_event_data ev;
+	int copied;
+
+	/* Does anyone care? */
+	spin_lock(&ev_int->wait.lock);
+	if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
+
+		ev.id = ev_code;
+		ev.timestamp = timestamp;
+
+		copied = kfifo_put(&ev_int->det_events, &ev);
+		if (copied != 0)
+			wake_up_locked_poll(&ev_int->wait, POLLIN);
+	}
+	spin_unlock(&ev_int->wait.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(iio_push_event);
+
+/**
+ * iio_event_poll() - poll the event queue to find out if it has data
+ */
+static unsigned int iio_event_poll(struct file *filep,
+			     struct poll_table_struct *wait)
+{
+	struct iio_event_interface *ev_int = filep->private_data;
+	unsigned int events = 0;
+
+	poll_wait(filep, &ev_int->wait, wait);
+
+	spin_lock(&ev_int->wait.lock);
+	if (!kfifo_is_empty(&ev_int->det_events))
+		events = POLLIN | POLLRDNORM;
+	spin_unlock(&ev_int->wait.lock);
+
+	return events;
+}
+
+static ssize_t iio_event_chrdev_read(struct file *filep,
+				     char __user *buf,
+				     size_t count,
+				     loff_t *f_ps)
+{
+	struct iio_event_interface *ev_int = filep->private_data;
+	unsigned int copied;
+	int ret;
+
+	if (count < sizeof(struct iio_event_data))
+		return -EINVAL;
+
+	spin_lock(&ev_int->wait.lock);
+	if (kfifo_is_empty(&ev_int->det_events)) {
+		if (filep->f_flags & O_NONBLOCK) {
+			ret = -EAGAIN;
+			goto error_unlock;
+		}
+		/* Blocking on device; waiting for something to be there */
+		ret = wait_event_interruptible_locked(ev_int->wait,
+					!kfifo_is_empty(&ev_int->det_events));
+		if (ret)
+			goto error_unlock;
+		/* Single access device so no one else can get the data */
+	}
+
+	ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied);
+
+error_unlock:
+	spin_unlock(&ev_int->wait.lock);
+
+	return ret ? ret : copied;
+}
+
+static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
+{
+	struct iio_event_interface *ev_int = filep->private_data;
+
+	spin_lock(&ev_int->wait.lock);
+	__clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
+	/*
+	 * In order to maintain a clean state for reopening,
+	 * clear out any awaiting events. The mask will prevent
+	 * any new __iio_push_event calls running.
+	 */
+	kfifo_reset_out(&ev_int->det_events);
+	spin_unlock(&ev_int->wait.lock);
+
+	return 0;
+}
+
+static const struct file_operations iio_event_chrdev_fileops = {
+	.read =  iio_event_chrdev_read,
+	.poll =  iio_event_poll,
+	.release = iio_event_chrdev_release,
+	.owner = THIS_MODULE,
+	.llseek = noop_llseek,
+};
+
+int iio_event_getfd(struct iio_dev *indio_dev)
+{
+	struct iio_event_interface *ev_int = indio_dev->event_interface;
+	int fd;
+
+	if (ev_int == NULL)
+		return -ENODEV;
+
+	spin_lock(&ev_int->wait.lock);
+	if (__test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
+		spin_unlock(&ev_int->wait.lock);
+		return -EBUSY;
+	}
+	spin_unlock(&ev_int->wait.lock);
+	fd = anon_inode_getfd("iio:event",
+				&iio_event_chrdev_fileops, ev_int, O_RDONLY);
+	if (fd < 0) {
+		spin_lock(&ev_int->wait.lock);
+		__clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
+		spin_unlock(&ev_int->wait.lock);
+	}
+	return fd;
+}
+
+static const char * const iio_ev_type_text[] = {
+	[IIO_EV_TYPE_THRESH] = "thresh",
+	[IIO_EV_TYPE_MAG] = "mag",
+	[IIO_EV_TYPE_ROC] = "roc",
+	[IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
+	[IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
+};
+
+static const char * const iio_ev_dir_text[] = {
+	[IIO_EV_DIR_EITHER] = "either",
+	[IIO_EV_DIR_RISING] = "rising",
+	[IIO_EV_DIR_FALLING] = "falling"
+};
+
+static ssize_t iio_ev_state_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf,
+				  size_t len)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	int ret;
+	bool val;
+
+	ret = strtobool(buf, &val);
+	if (ret < 0)
+		return ret;
+
+	ret = indio_dev->info->write_event_config(indio_dev,
+						  this_attr->address,
+						  val);
+	return (ret < 0) ? ret : len;
+}
+
+static ssize_t iio_ev_state_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	int val = indio_dev->info->read_event_config(indio_dev,
+						     this_attr->address);
+
+	if (val < 0)
+		return val;
+	else
+		return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t iio_ev_value_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	int val, ret;
+
+	ret = indio_dev->info->read_event_value(indio_dev,
+						this_attr->address, &val);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t iio_ev_value_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf,
+				  size_t len)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	unsigned long val;
+	int ret;
+
+	if (!indio_dev->info->write_event_value)
+		return -EINVAL;
+
+	ret = strict_strtoul(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	ret = indio_dev->info->write_event_value(indio_dev, this_attr->address,
+						 val);
+	if (ret < 0)
+		return ret;
+
+	return len;
+}
+
+static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
+				      struct iio_chan_spec const *chan)
+{
+	int ret = 0, i, attrcount = 0;
+	u64 mask = 0;
+	char *postfix;
+	if (!chan->event_mask)
+		return 0;
+
+	for_each_set_bit(i, &chan->event_mask, sizeof(chan->event_mask)*8) {
+		postfix = kasprintf(GFP_KERNEL, "%s_%s_en",
+				    iio_ev_type_text[i/IIO_EV_DIR_MAX],
+				    iio_ev_dir_text[i%IIO_EV_DIR_MAX]);
+		if (postfix == NULL) {
+			ret = -ENOMEM;
+			goto error_ret;
+		}
+		if (chan->modified)
+			mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel,
+						  i/IIO_EV_DIR_MAX,
+						  i%IIO_EV_DIR_MAX);
+		else if (chan->differential)
+			mask = IIO_EVENT_CODE(chan->type,
+					      0, 0,
+					      i%IIO_EV_DIR_MAX,
+					      i/IIO_EV_DIR_MAX,
+					      0,
+					      chan->channel,
+					      chan->channel2);
+		else
+			mask = IIO_UNMOD_EVENT_CODE(chan->type,
+						    chan->channel,
+						    i/IIO_EV_DIR_MAX,
+						    i%IIO_EV_DIR_MAX);
+
+		ret = __iio_add_chan_devattr(postfix,
+					     chan,
+					     &iio_ev_state_show,
+					     iio_ev_state_store,
+					     mask,
+					     0,
+					     &indio_dev->dev,
+					     &indio_dev->event_interface->
+					     dev_attr_list);
+		kfree(postfix);
+		if (ret)
+			goto error_ret;
+		attrcount++;
+		postfix = kasprintf(GFP_KERNEL, "%s_%s_value",
+				    iio_ev_type_text[i/IIO_EV_DIR_MAX],
+				    iio_ev_dir_text[i%IIO_EV_DIR_MAX]);
+		if (postfix == NULL) {
+			ret = -ENOMEM;
+			goto error_ret;
+		}
+		ret = __iio_add_chan_devattr(postfix, chan,
+					     iio_ev_value_show,
+					     iio_ev_value_store,
+					     mask,
+					     0,
+					     &indio_dev->dev,
+					     &indio_dev->event_interface->
+					     dev_attr_list);
+		kfree(postfix);
+		if (ret)
+			goto error_ret;
+		attrcount++;
+	}
+	ret = attrcount;
+error_ret:
+	return ret;
+}
+
+static inline void __iio_remove_event_config_attrs(struct iio_dev *indio_dev)
+{
+	struct iio_dev_attr *p, *n;
+	list_for_each_entry_safe(p, n,
+				 &indio_dev->event_interface->
+				 dev_attr_list, l) {
+		kfree(p->dev_attr.attr.name);
+		kfree(p);
+	}
+}
+
+static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev)
+{
+	int j, ret, attrcount = 0;
+
+	INIT_LIST_HEAD(&indio_dev->event_interface->dev_attr_list);
+	/* Dynically created from the channels array */
+	for (j = 0; j < indio_dev->num_channels; j++) {
+		ret = iio_device_add_event_sysfs(indio_dev,
+						 &indio_dev->channels[j]);
+		if (ret < 0)
+			goto error_clear_attrs;
+		attrcount += ret;
+	}
+	return attrcount;
+
+error_clear_attrs:
+	__iio_remove_event_config_attrs(indio_dev);
+
+	return ret;
+}
+
+static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev)
+{
+	int j;
+
+	for (j = 0; j < indio_dev->num_channels; j++)
+		if (indio_dev->channels[j].event_mask != 0)
+			return true;
+	return false;
+}
+
+static void iio_setup_ev_int(struct iio_event_interface *ev_int)
+{
+	INIT_KFIFO(ev_int->det_events);
+	init_waitqueue_head(&ev_int->wait);
+}
+
+static const char *iio_event_group_name = "events";
+int iio_device_register_eventset(struct iio_dev *indio_dev)
+{
+	struct iio_dev_attr *p;
+	int ret = 0, attrcount_orig = 0, attrcount, attrn;
+	struct attribute **attr;
+
+	if (!(indio_dev->info->event_attrs ||
+	      iio_check_for_dynamic_events(indio_dev)))
+		return 0;
+
+	indio_dev->event_interface =
+		kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL);
+	if (indio_dev->event_interface == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	iio_setup_ev_int(indio_dev->event_interface);
+	if (indio_dev->info->event_attrs != NULL) {
+		attr = indio_dev->info->event_attrs->attrs;
+		while (*attr++ != NULL)
+			attrcount_orig++;
+	}
+	attrcount = attrcount_orig;
+	if (indio_dev->channels) {
+		ret = __iio_add_event_config_attrs(indio_dev);
+		if (ret < 0)
+			goto error_free_setup_event_lines;
+		attrcount += ret;
+	}
+
+	indio_dev->event_interface->group.name = iio_event_group_name;
+	indio_dev->event_interface->group.attrs = kcalloc(attrcount + 1,
+							  sizeof(indio_dev->event_interface->group.attrs[0]),
+							  GFP_KERNEL);
+	if (indio_dev->event_interface->group.attrs == NULL) {
+		ret = -ENOMEM;
+		goto error_free_setup_event_lines;
+	}
+	if (indio_dev->info->event_attrs)
+		memcpy(indio_dev->event_interface->group.attrs,
+		       indio_dev->info->event_attrs->attrs,
+		       sizeof(indio_dev->event_interface->group.attrs[0])
+		       *attrcount_orig);
+	attrn = attrcount_orig;
+	/* Add all elements from the list. */
+	list_for_each_entry(p,
+			    &indio_dev->event_interface->dev_attr_list,
+			    l)
+		indio_dev->event_interface->group.attrs[attrn++] =
+			&p->dev_attr.attr;
+	indio_dev->groups[indio_dev->groupcounter++] =
+		&indio_dev->event_interface->group;
+
+	return 0;
+
+error_free_setup_event_lines:
+	__iio_remove_event_config_attrs(indio_dev);
+	kfree(indio_dev->event_interface);
+error_ret:
+
+	return ret;
+}
+
+void iio_device_unregister_eventset(struct iio_dev *indio_dev)
+{
+	if (indio_dev->event_interface == NULL)
+		return;
+	__iio_remove_event_config_attrs(indio_dev);
+	kfree(indio_dev->event_interface->group.attrs);
+	kfree(indio_dev->event_interface);
+}
diff --git a/drivers/staging/iio/inkern.c b/drivers/staging/iio/inkern.c
new file mode 100644
index 0000000..de2c8ea
--- /dev/null
+++ b/drivers/staging/iio/inkern.c
@@ -0,0 +1,292 @@
+/* The industrial I/O core in kernel channel mapping
+ *
+ * Copyright (c) 2011 Jonathan Cameron
+ *
+ * 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.
+ */
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+
+#include "iio.h"
+#include "iio_core.h"
+#include "machine.h"
+#include "driver.h"
+#include "consumer.h"
+
+struct iio_map_internal {
+	struct iio_dev *indio_dev;
+	struct iio_map *map;
+	struct list_head l;
+};
+
+static LIST_HEAD(iio_map_list);
+static DEFINE_MUTEX(iio_map_list_lock);
+
+int iio_map_array_register(struct iio_dev *indio_dev, struct iio_map *maps)
+{
+	int i = 0, ret = 0;
+	struct iio_map_internal *mapi;
+
+	if (maps == NULL)
+		return 0;
+
+	mutex_lock(&iio_map_list_lock);
+	while (maps[i].consumer_dev_name != NULL) {
+		mapi = kzalloc(sizeof(*mapi), GFP_KERNEL);
+		if (mapi == NULL) {
+			ret = -ENOMEM;
+			goto error_ret;
+		}
+		mapi->map = &maps[i];
+		mapi->indio_dev = indio_dev;
+		list_add(&mapi->l, &iio_map_list);
+		i++;
+	}
+error_ret:
+	mutex_unlock(&iio_map_list_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_map_array_register);
+
+
+/* Assumes the exact same array (e.g. memory locations)
+ * used at unregistration as used at registration rather than
+ * more complex checking of contents.
+ */
+int iio_map_array_unregister(struct iio_dev *indio_dev,
+			     struct iio_map *maps)
+{
+	int i = 0, ret = 0;
+	bool found_it;
+	struct iio_map_internal *mapi;
+
+	if (maps == NULL)
+		return 0;
+
+	mutex_lock(&iio_map_list_lock);
+	while (maps[i].consumer_dev_name != NULL) {
+		found_it = false;
+		list_for_each_entry(mapi, &iio_map_list, l)
+			if (&maps[i] == mapi->map) {
+				list_del(&mapi->l);
+				kfree(mapi);
+				found_it = true;
+				break;
+			}
+		if (found_it == false) {
+			ret = -ENODEV;
+			goto error_ret;
+		}
+	}
+error_ret:
+	mutex_unlock(&iio_map_list_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_map_array_unregister);
+
+static const struct iio_chan_spec
+*iio_chan_spec_from_name(const struct iio_dev *indio_dev,
+			 const char *name)
+{
+	int i;
+	const struct iio_chan_spec *chan = NULL;
+
+	for (i = 0; i < indio_dev->num_channels; i++)
+		if (indio_dev->channels[i].datasheet_name &&
+		    strcmp(name, indio_dev->channels[i].datasheet_name) == 0) {
+			chan = &indio_dev->channels[i];
+			break;
+		}
+	return chan;
+}
+
+
+struct iio_channel *iio_st_channel_get(const char *name,
+				       const char *channel_name)
+{
+	struct iio_map_internal *c_i = NULL, *c = NULL;
+	struct iio_channel *channel;
+
+	if (name == NULL && channel_name == NULL)
+		return ERR_PTR(-ENODEV);
+
+	/* first find matching entry the channel map */
+	mutex_lock(&iio_map_list_lock);
+	list_for_each_entry(c_i, &iio_map_list, l) {
+		if ((name && strcmp(name, c_i->map->consumer_dev_name) != 0) ||
+		    (channel_name &&
+		     strcmp(channel_name, c_i->map->consumer_channel) != 0))
+			continue;
+		c = c_i;
+		get_device(&c->indio_dev->dev);
+		break;
+	}
+	mutex_unlock(&iio_map_list_lock);
+	if (c == NULL)
+		return ERR_PTR(-ENODEV);
+
+	channel = kmalloc(sizeof(*channel), GFP_KERNEL);
+	if (channel == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	channel->indio_dev = c->indio_dev;
+
+	if (c->map->adc_channel_label)
+		channel->channel =
+			iio_chan_spec_from_name(channel->indio_dev,
+						c->map->adc_channel_label);
+
+	return channel;
+}
+EXPORT_SYMBOL_GPL(iio_st_channel_get);
+
+void iio_st_channel_release(struct iio_channel *channel)
+{
+	put_device(&channel->indio_dev->dev);
+	kfree(channel);
+}
+EXPORT_SYMBOL_GPL(iio_st_channel_release);
+
+struct iio_channel *iio_st_channel_get_all(const char *name)
+{
+	struct iio_channel *chans;
+	struct iio_map_internal *c = NULL;
+	int nummaps = 0;
+	int mapind = 0;
+	int i, ret;
+
+	if (name == NULL)
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(&iio_map_list_lock);
+	/* first count the matching maps */
+	list_for_each_entry(c, &iio_map_list, l)
+		if (name && strcmp(name, c->map->consumer_dev_name) != 0)
+			continue;
+		else
+			nummaps++;
+
+	if (nummaps == 0) {
+		ret = -ENODEV;
+		goto error_ret;
+	}
+
+	/* NULL terminated array to save passing size */
+	chans = kzalloc(sizeof(*chans)*(nummaps + 1), GFP_KERNEL);
+	if (chans == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	/* for each map fill in the chans element */
+	list_for_each_entry(c, &iio_map_list, l) {
+		if (name && strcmp(name, c->map->consumer_dev_name) != 0)
+			continue;
+		chans[mapind].indio_dev = c->indio_dev;
+		chans[mapind].channel =
+			iio_chan_spec_from_name(chans[mapind].indio_dev,
+						c->map->adc_channel_label);
+		if (chans[mapind].channel == NULL) {
+			ret = -EINVAL;
+			put_device(&chans[mapind].indio_dev->dev);
+			goto error_free_chans;
+		}
+		get_device(&chans[mapind].indio_dev->dev);
+		mapind++;
+	}
+	mutex_unlock(&iio_map_list_lock);
+	if (mapind == 0) {
+		ret = -ENODEV;
+		goto error_free_chans;
+	}
+	return chans;
+
+error_free_chans:
+	for (i = 0; i < nummaps; i++)
+		if (chans[i].indio_dev)
+			put_device(&chans[i].indio_dev->dev);
+	kfree(chans);
+error_ret:
+	mutex_unlock(&iio_map_list_lock);
+
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(iio_st_channel_get_all);
+
+void iio_st_channel_release_all(struct iio_channel *channels)
+{
+	struct iio_channel *chan = &channels[0];
+
+	while (chan->indio_dev) {
+		put_device(&chan->indio_dev->dev);
+		chan++;
+	}
+	kfree(channels);
+}
+EXPORT_SYMBOL_GPL(iio_st_channel_release_all);
+
+int iio_st_read_channel_raw(struct iio_channel *chan, int *val)
+{
+	int val2, ret;
+
+	mutex_lock(&chan->indio_dev->info_exist_lock);
+	if (chan->indio_dev->info == NULL) {
+		ret = -ENODEV;
+		goto err_unlock;
+	}
+
+	ret = chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel,
+					      val, &val2, 0);
+err_unlock:
+	mutex_unlock(&chan->indio_dev->info_exist_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_st_read_channel_raw);
+
+int iio_st_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
+{
+	int ret;
+
+	mutex_lock(&chan->indio_dev->info_exist_lock);
+	if (chan->indio_dev->info == NULL) {
+		ret = -ENODEV;
+		goto err_unlock;
+	}
+
+	ret = chan->indio_dev->info->read_raw(chan->indio_dev,
+					      chan->channel,
+					      val, val2,
+					      IIO_CHAN_INFO_SCALE);
+err_unlock:
+	mutex_unlock(&chan->indio_dev->info_exist_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_st_read_channel_scale);
+
+int iio_st_get_channel_type(struct iio_channel *chan,
+			    enum iio_chan_type *type)
+{
+	int ret = 0;
+	/* Need to verify underlying driver has not gone away */
+
+	mutex_lock(&chan->indio_dev->info_exist_lock);
+	if (chan->indio_dev->info == NULL) {
+		ret = -ENODEV;
+		goto err_unlock;
+	}
+
+	*type = chan->channel->type;
+err_unlock:
+	mutex_unlock(&chan->indio_dev->info_exist_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_st_get_channel_type);
diff --git a/drivers/staging/iio/kfifo_buf.c b/drivers/staging/iio/kfifo_buf.c
index e1e9c06..9f3bd59 100644
--- a/drivers/staging/iio/kfifo_buf.c
+++ b/drivers/staging/iio/kfifo_buf.c
@@ -59,21 +59,6 @@
 	.name = "buffer",
 };
 
-struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
-{
-	struct iio_kfifo *kf;
-
-	kf = kzalloc(sizeof *kf, GFP_KERNEL);
-	if (!kf)
-		return NULL;
-	kf->update_needed = true;
-	iio_buffer_init(&kf->buffer);
-	kf->buffer.attrs = &iio_kfifo_attribute_group;
-
-	return &kf->buffer;
-}
-EXPORT_SYMBOL(iio_kfifo_allocate);
-
 static int iio_get_bytes_per_datum_kfifo(struct iio_buffer *r)
 {
 	return r->bytes_per_datum;
@@ -104,12 +89,6 @@
 	return 0;
 }
 
-void iio_kfifo_free(struct iio_buffer *r)
-{
-	kfree(iio_to_kfifo(r));
-}
-EXPORT_SYMBOL(iio_kfifo_free);
-
 static int iio_store_to_kfifo(struct iio_buffer *r,
 			      u8 *data,
 			      s64 timestamp)
@@ -137,7 +116,7 @@
 	return copied;
 }
 
-const struct iio_buffer_access_funcs kfifo_access_funcs = {
+static const struct iio_buffer_access_funcs kfifo_access_funcs = {
 	.store_to = &iio_store_to_kfifo,
 	.read_first_n = &iio_read_first_n_kfifo,
 	.request_update = &iio_request_update_kfifo,
@@ -146,6 +125,27 @@
 	.get_length = &iio_get_length_kfifo,
 	.set_length = &iio_set_length_kfifo,
 };
-EXPORT_SYMBOL(kfifo_access_funcs);
+
+struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
+{
+	struct iio_kfifo *kf;
+
+	kf = kzalloc(sizeof *kf, GFP_KERNEL);
+	if (!kf)
+		return NULL;
+	kf->update_needed = true;
+	iio_buffer_init(&kf->buffer);
+	kf->buffer.attrs = &iio_kfifo_attribute_group;
+	kf->buffer.access = &kfifo_access_funcs;
+
+	return &kf->buffer;
+}
+EXPORT_SYMBOL(iio_kfifo_allocate);
+
+void iio_kfifo_free(struct iio_buffer *r)
+{
+	kfree(iio_to_kfifo(r));
+}
+EXPORT_SYMBOL(iio_kfifo_free);
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/kfifo_buf.h b/drivers/staging/iio/kfifo_buf.h
index cc2bd9a..9f7da01 100644
--- a/drivers/staging/iio/kfifo_buf.h
+++ b/drivers/staging/iio/kfifo_buf.h
@@ -3,8 +3,6 @@
 #include "iio.h"
 #include "buffer.h"
 
-extern const struct iio_buffer_access_funcs kfifo_access_funcs;
-
 struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev);
 void iio_kfifo_free(struct iio_buffer *r);
 
diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c
index 849d6a5..38ec52b 100644
--- a/drivers/staging/iio/light/isl29018.c
+++ b/drivers/staging/iio/light/isl29018.c
@@ -592,11 +592,18 @@
 
 MODULE_DEVICE_TABLE(i2c, isl29018_id);
 
+static const struct of_device_id isl29018_of_match[] = {
+	{ .compatible = "invn,isl29018", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, isl29018_of_match);
+
 static struct i2c_driver isl29018_driver = {
 	.class	= I2C_CLASS_HWMON,
 	.driver	 = {
 			.name = "isl29018",
 			.owner = THIS_MODULE,
+			.of_match_table = isl29018_of_match,
 		    },
 	.probe	 = isl29018_probe,
 	.remove	 = __devexit_p(isl29018_remove),
diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c
index ffca85e..546c95a 100644
--- a/drivers/staging/iio/light/tsl2563.c
+++ b/drivers/staging/iio/light/tsl2563.c
@@ -118,7 +118,7 @@
 	struct delayed_work	poweroff_work;
 
 	/* Remember state for suspend and resume functions */
-	pm_message_t		state;
+	bool suspended;
 
 	struct tsl2563_gainlevel_coeff const *gainlevel;
 
@@ -315,7 +315,7 @@
 	int retry = 1;
 	int ret = 0;
 
-	if (chip->state.event != PM_EVENT_ON)
+	if (chip->suspended)
 		goto out;
 
 	if (!chip->int_enabled) {
@@ -708,7 +708,6 @@
 	struct tsl2563_chip *chip;
 	struct tsl2563_platform_data *pdata = client->dev.platform_data;
 	int err = 0;
-	int ret;
 	u8 id = 0;
 
 	indio_dev = iio_allocate_device(sizeof(*chip));
@@ -722,13 +721,15 @@
 
 	err = tsl2563_detect(chip);
 	if (err) {
-		dev_err(&client->dev, "device not found, error %d\n", -err);
+		dev_err(&client->dev, "detect error %d\n", -err);
 		goto fail1;
 	}
 
 	err = tsl2563_read_id(chip, &id);
-	if (err)
+	if (err) {
+		dev_err(&client->dev, "read id error %d\n", -err);
 		goto fail1;
+	}
 
 	mutex_init(&chip->lock);
 
@@ -751,40 +752,52 @@
 	indio_dev->num_channels = ARRAY_SIZE(tsl2563_channels);
 	indio_dev->dev.parent = &client->dev;
 	indio_dev->modes = INDIO_DIRECT_MODE;
+
 	if (client->irq)
 		indio_dev->info = &tsl2563_info;
 	else
 		indio_dev->info = &tsl2563_info_no_irq;
+
 	if (client->irq) {
-		ret = request_threaded_irq(client->irq,
+		err = request_threaded_irq(client->irq,
 					   NULL,
 					   &tsl2563_event_handler,
 					   IRQF_TRIGGER_RISING | IRQF_ONESHOT,
 					   "tsl2563_event",
 					   indio_dev);
-		if (ret)
-			goto fail2;
+		if (err) {
+			dev_err(&client->dev, "irq request error %d\n", -err);
+			goto fail1;
+		}
 	}
+
 	err = tsl2563_configure(chip);
-	if (err)
-		goto fail3;
+	if (err) {
+		dev_err(&client->dev, "configure error %d\n", -err);
+		goto fail2;
+	}
 
 	INIT_DELAYED_WORK(&chip->poweroff_work, tsl2563_poweroff_work);
+
 	/* The interrupt cannot yet be enabled so this is fine without lock */
 	schedule_delayed_work(&chip->poweroff_work, 5 * HZ);
 
-	ret = iio_device_register(indio_dev);
-	if (ret)
+	err = iio_device_register(indio_dev);
+	if (err) {
+		dev_err(&client->dev, "iio registration error %d\n", -err);
 		goto fail3;
+	}
 
 	return 0;
+
 fail3:
+	cancel_delayed_work(&chip->poweroff_work);
+	flush_scheduled_work();
+fail2:
 	if (client->irq)
 		free_irq(client->irq, indio_dev);
-fail2:
-	iio_free_device(indio_dev);
 fail1:
-	kfree(chip);
+	iio_free_device(indio_dev);
 	return err;
 }
 
@@ -810,9 +823,10 @@
 	return 0;
 }
 
-static int tsl2563_suspend(struct i2c_client *client, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int tsl2563_suspend(struct device *dev)
 {
-	struct tsl2563_chip *chip = i2c_get_clientdata(client);
+	struct tsl2563_chip *chip = i2c_get_clientdata(to_i2c_client(dev));
 	int ret;
 
 	mutex_lock(&chip->lock);
@@ -821,16 +835,16 @@
 	if (ret)
 		goto out;
 
-	chip->state = state;
+	chip->suspended = true;
 
 out:
 	mutex_unlock(&chip->lock);
 	return ret;
 }
 
-static int tsl2563_resume(struct i2c_client *client)
+static int tsl2563_resume(struct device *dev)
 {
-	struct tsl2563_chip *chip = i2c_get_clientdata(client);
+	struct tsl2563_chip *chip = i2c_get_clientdata(to_i2c_client(dev));
 	int ret;
 
 	mutex_lock(&chip->lock);
@@ -843,13 +857,19 @@
 	if (ret)
 		goto out;
 
-	chip->state.event = PM_EVENT_ON;
+	chip->suspended = false;
 
 out:
 	mutex_unlock(&chip->lock);
 	return ret;
 }
 
+static SIMPLE_DEV_PM_OPS(tsl2563_pm_ops, tsl2563_suspend, tsl2563_resume);
+#define TSL2563_PM_OPS (&tsl2563_pm_ops)
+#else
+#define TSL2563_PM_OPS NULL
+#endif
+
 static const struct i2c_device_id tsl2563_id[] = {
 	{ "tsl2560", 0 },
 	{ "tsl2561", 1 },
@@ -862,9 +882,8 @@
 static struct i2c_driver tsl2563_i2c_driver = {
 	.driver = {
 		.name	 = "tsl2563",
+		.pm	= TSL2563_PM_OPS,
 	},
-	.suspend	= tsl2563_suspend,
-	.resume		= tsl2563_resume,
 	.probe		= tsl2563_probe,
 	.remove		= __devexit_p(tsl2563_remove),
 	.id_table	= tsl2563_id,
diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c
index 5b6455a..8671d98 100644
--- a/drivers/staging/iio/light/tsl2583.c
+++ b/drivers/staging/iio/light/tsl2583.c
@@ -113,7 +113,7 @@
 
 /* This structure is intentionally large to accommodate updates via sysfs. */
 /* Sized to 11 = max 10 segments + 1 termination segment */
-/* Assumption is is one and only one type of glass used  */
+/* Assumption is one and only one type of glass used  */
 static struct taos_lux taos_device_lux[11] = {
 	{  9830,  8520, 15729 },
 	{ 12452, 10807, 23344 },
@@ -884,9 +884,10 @@
 	return ret;
 }
 
-static int taos_suspend(struct i2c_client *client, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int taos_suspend(struct device *dev)
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 	struct tsl2583_chip *chip = iio_priv(indio_dev);
 	int ret = 0;
 
@@ -901,9 +902,9 @@
 	return ret;
 }
 
-static int taos_resume(struct i2c_client *client)
+static int taos_resume(struct device *dev)
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 	struct tsl2583_chip *chip = iio_priv(indio_dev);
 	int ret = 0;
 
@@ -916,6 +917,11 @@
 	return ret;
 }
 
+static SIMPLE_DEV_PM_OPS(taos_pm_ops, taos_suspend, taos_resume);
+#define TAOS_PM_OPS (&taos_pm_ops)
+#else
+#define TAOS_PM_OPS NULL
+#endif
 
 static int __devexit taos_remove(struct i2c_client *client)
 {
@@ -937,10 +943,9 @@
 static struct i2c_driver taos_driver = {
 	.driver = {
 		.name = "tsl2583",
+		.pm = TAOS_PM_OPS,
 	},
 	.id_table = taos_idtable,
-	.suspend	= taos_suspend,
-	.resume		= taos_resume,
 	.probe = taos_probe,
 	.remove = __devexit_p(taos_remove),
 };
diff --git a/drivers/staging/iio/machine.h b/drivers/staging/iio/machine.h
new file mode 100644
index 0000000..0b1f19b
--- /dev/null
+++ b/drivers/staging/iio/machine.h
@@ -0,0 +1,24 @@
+/*
+ * Industrial I/O in kernel access map definitions for board files.
+ *
+ * Copyright (c) 2011 Jonathan Cameron
+ *
+ * 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.
+ */
+
+/**
+ * struct iio_map - description of link between consumer and device channels
+ * @adc_channel_label:	Label used to identify the channel on the provider.
+ *			This is matched against the datasheet_name element
+ *			of struct iio_chan_spec.
+ * @consumer_dev_name:	Name to uniquely identify the consumer device.
+ * @consumer_channel:	Unique name used to idenitify the channel on the
+ *			consumer side.
+ */
+struct iio_map {
+	const char *adc_channel_label;
+	const char *consumer_dev_name;
+	const char *consumer_channel;
+};
diff --git a/drivers/staging/iio/magnetometer/ak8975.c b/drivers/staging/iio/magnetometer/ak8975.c
index 3158f12..d5ddac3 100644
--- a/drivers/staging/iio/magnetometer/ak8975.c
+++ b/drivers/staging/iio/magnetometer/ak8975.c
@@ -564,9 +564,17 @@
 
 MODULE_DEVICE_TABLE(i2c, ak8975_id);
 
+static const struct of_device_id ak8975_of_match[] = {
+	{ .compatible = "asahi-kasei,ak8975", },
+	{ .compatible = "ak8975", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ak8975_of_match);
+
 static struct i2c_driver ak8975_driver = {
 	.driver = {
 		.name	= "ak8975",
+		.of_match_table = ak8975_of_match,
 	},
 	.probe		= ak8975_probe,
 	.remove		= __devexit_p(ak8975_remove),
diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c
index f2e85a9..91dd3da 100644
--- a/drivers/staging/iio/magnetometer/hmc5843.c
+++ b/drivers/staging/iio/magnetometer/hmc5843.c
@@ -86,7 +86,7 @@
 #define	RATE_NOT_USED				0x07
 
 /*
- * Device Configutration
+ * Device Configuration
  */
 #define	CONF_NORMAL				0x00
 #define	CONF_POSITIVE_BIAS			0x01
@@ -142,7 +142,7 @@
 					(operating_mode & 0x03));
 }
 
-/* Return the measurement value from the  specified channel */
+/* Return the measurement value from the specified channel */
 static int hmc5843_read_measurement(struct iio_dev *indio_dev,
 				    int address,
 				    int *val)
@@ -169,7 +169,7 @@
 /*
  * From the datasheet
  * 0 - Continuous-Conversion Mode: In continuous-conversion mode, the
- * device continuously performs conversions an places the result in the
+ * device continuously performs conversions and places the result in the
  * data register.
  *
  * 1 - Single-Conversion Mode : device performs a single measurement,
@@ -588,19 +588,26 @@
 	return 0;
 }
 
-static int hmc5843_suspend(struct i2c_client *client, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+static int hmc5843_suspend(struct device *dev)
 {
-	hmc5843_configure(client, MODE_SLEEP);
+	hmc5843_configure(to_i2c_client(dev), MODE_SLEEP);
 	return 0;
 }
 
-static int hmc5843_resume(struct i2c_client *client)
+static int hmc5843_resume(struct device *dev)
 {
-	struct hmc5843_data *data = i2c_get_clientdata(client);
-	hmc5843_configure(client, data->operating_mode);
+	struct hmc5843_data *data = i2c_get_clientdata(to_i2c_client(dev));
+	hmc5843_configure(to_i2c_client(dev), data->operating_mode);
 	return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(hmc5843_pm_ops, hmc5843_suspend, hmc5843_resume);
+#define HMC5843_PM_OPS (&hmc5843_pm_ops)
+#else
+#define HMC5843_PM_OPS NULL
+#endif
+
 static const struct i2c_device_id hmc5843_id[] = {
 	{ "hmc5843", 0 },
 	{ }
@@ -610,14 +617,13 @@
 static struct i2c_driver hmc5843_driver = {
 	.driver = {
 		.name	= "hmc5843",
+		.pm	= HMC5843_PM_OPS,
 	},
 	.id_table	= hmc5843_id,
 	.probe		= hmc5843_probe,
 	.remove		= hmc5843_remove,
 	.detect		= hmc5843_detect,
 	.address_list	= normal_i2c,
-	.suspend	= hmc5843_suspend,
-	.resume		= hmc5843_resume,
 };
 module_i2c_driver(hmc5843_driver);
 
diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c
index f29f2b2..c45b23b 100644
--- a/drivers/staging/iio/meter/ade7758_ring.c
+++ b/drivers/staging/iio/meter/ade7758_ring.c
@@ -85,7 +85,7 @@
 /**
  * ade7758_ring_preenable() setup the parameters of the ring before enabling
  *
- * The complex nature of the setting of the nuber of bytes per datum is due
+ * The complex nature of the setting of the number of bytes per datum is due
  * to this driver currently ensuring that the timestamp is stored at an 8
  * byte boundary.
  **/
@@ -144,8 +144,6 @@
 		return ret;
 	}
 
-	/* Effectively select the ring buffer implementation */
-	indio_dev->buffer->access = &ring_sw_access_funcs;
 	indio_dev->setup_ops = &ade7758_ring_setup_ops;
 
 	indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
diff --git a/drivers/staging/iio/meter/meter.h b/drivers/staging/iio/meter/meter.h
index 142c50d..6a3db14 100644
--- a/drivers/staging/iio/meter/meter.h
+++ b/drivers/staging/iio/meter/meter.h
@@ -362,7 +362,7 @@
 #define IIO_EVENT_ATTR_CYCEND(_evlist, _show, _store, _mask) \
 	IIO_EVENT_ATTR_SH(cycend, _evlist, _show, _store, _mask)
 
-/* on the rising and falling edge of the the voltage waveform */
+/* on the rising and falling edge of the voltage waveform */
 #define IIO_EVENT_ATTR_ZERO_CROSS(_evlist, _show, _store, _mask) \
 	IIO_EVENT_ATTR_SH(zero_cross, _evlist, _show, _store, _mask)
 
diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c
index 3e24ec4..b9945ec 100644
--- a/drivers/staging/iio/ring_sw.c
+++ b/drivers/staging/iio/ring_sw.c
@@ -147,7 +147,7 @@
 	size_t data_available, buffer_size;
 
 	/* A userspace program has probably made an error if it tries to
-	 *  read something that is not a whole number of bpds.
+	 * read something that is not a whole number of bpds.
 	 * Return an error.
 	 */
 	if (n % ring->buf.bytes_per_datum) {
@@ -229,7 +229,7 @@
 
 	/* setup the next read position */
 	/* Beware, this may fail due to concurrency fun and games.
-	 *  Possible that sufficient fill commands have run to push the read
+	 * Possible that sufficient fill commands have run to push the read
 	 * pointer past where we would be after the rip. If this occurs, leave
 	 * it be.
 	 */
@@ -329,6 +329,16 @@
 	.name = "buffer",
 };
 
+static const struct iio_buffer_access_funcs ring_sw_access_funcs = {
+	.store_to = &iio_store_to_sw_rb,
+	.read_first_n = &iio_read_first_n_sw_rb,
+	.request_update = &iio_request_update_sw_rb,
+	.get_bytes_per_datum = &iio_get_bytes_per_datum_sw_rb,
+	.set_bytes_per_datum = &iio_set_bytes_per_datum_sw_rb,
+	.get_length = &iio_get_length_sw_rb,
+	.set_length = &iio_set_length_sw_rb,
+};
+
 struct iio_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev)
 {
 	struct iio_buffer *buf;
@@ -341,6 +351,7 @@
 	buf = &ring->buf;
 	iio_buffer_init(buf);
 	buf->attrs = &iio_ring_attribute_group;
+	buf->access = &ring_sw_access_funcs;
 
 	return buf;
 }
@@ -352,16 +363,5 @@
 }
 EXPORT_SYMBOL(iio_sw_rb_free);
 
-const struct iio_buffer_access_funcs ring_sw_access_funcs = {
-	.store_to = &iio_store_to_sw_rb,
-	.read_first_n = &iio_read_first_n_sw_rb,
-	.request_update = &iio_request_update_sw_rb,
-	.get_bytes_per_datum = &iio_get_bytes_per_datum_sw_rb,
-	.set_bytes_per_datum = &iio_set_bytes_per_datum_sw_rb,
-	.get_length = &iio_get_length_sw_rb,
-	.set_length = &iio_set_length_sw_rb,
-};
-EXPORT_SYMBOL(ring_sw_access_funcs);
-
 MODULE_DESCRIPTION("Industrialio I/O software ring buffer");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/ring_sw.h b/drivers/staging/iio/ring_sw.h
index e6a6e2c..7556e21 100644
--- a/drivers/staging/iio/ring_sw.h
+++ b/drivers/staging/iio/ring_sw.h
@@ -25,11 +25,6 @@
 #define _IIO_RING_SW_H_
 #include "buffer.h"
 
-/**
- * ring_sw_access_funcs - access functions for a software ring buffer
- **/
-extern const struct iio_buffer_access_funcs ring_sw_access_funcs;
-
 struct iio_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev);
 void iio_sw_rb_free(struct iio_buffer *ring);
 #endif /* _IIO_RING_SW_H_ */
diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
index 1cbb25d..665653d 100644
--- a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
+++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
@@ -232,17 +232,7 @@
 	.remove = __devexit_p(iio_bfin_tmr_trigger_remove),
 };
 
-static int __init iio_bfin_tmr_trig_init(void)
-{
-	return platform_driver_register(&iio_bfin_tmr_trigger_driver);
-}
-module_init(iio_bfin_tmr_trig_init);
-
-static void __exit iio_bfin_tmr_trig_exit(void)
-{
-	platform_driver_unregister(&iio_bfin_tmr_trigger_driver);
-}
-module_exit(iio_bfin_tmr_trig_exit);
+module_platform_driver(iio_bfin_tmr_trigger_driver);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("Blackfin system timer based trigger for the iio subsystem");
diff --git a/drivers/staging/iio/trigger/iio-trig-gpio.c b/drivers/staging/iio/trigger/iio-trig-gpio.c
index f2a6559..a346594 100644
--- a/drivers/staging/iio/trigger/iio-trig-gpio.c
+++ b/drivers/staging/iio/trigger/iio-trig-gpio.c
@@ -160,17 +160,7 @@
 	},
 };
 
-static int __init iio_gpio_trig_init(void)
-{
-	return platform_driver_register(&iio_gpio_trigger_driver);
-}
-module_init(iio_gpio_trig_init);
-
-static void __exit iio_gpio_trig_exit(void)
-{
-	platform_driver_unregister(&iio_gpio_trigger_driver);
-}
-module_exit(iio_gpio_trig_exit);
+module_platform_driver(iio_gpio_trigger_driver);
 
 MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
 MODULE_DESCRIPTION("Example gpio trigger for the iio subsystem");
diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
index bd7416b..a80cf67 100644
--- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
+++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
@@ -195,18 +195,8 @@
 	},
 };
 
-static int __init iio_trig_periodic_rtc_init(void)
-{
-	return platform_driver_register(&iio_trig_periodic_rtc_driver);
-}
+module_platform_driver(iio_trig_periodic_rtc_driver);
 
-static void __exit iio_trig_periodic_rtc_exit(void)
-{
-	return platform_driver_unregister(&iio_trig_periodic_rtc_driver);
-}
-
-module_init(iio_trig_periodic_rtc_init);
-module_exit(iio_trig_periodic_rtc_exit);
 MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
 MODULE_DESCRIPTION("Periodic realtime clock  trigger for the iio subsystem");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/types.h b/drivers/staging/iio/types.h
index b7d2647..0c32136 100644
--- a/drivers/staging/iio/types.h
+++ b/drivers/staging/iio/types.h
@@ -46,4 +46,8 @@
 	IIO_MOD_LIGHT_IR,
 };
 
+#define IIO_VAL_INT 1
+#define IIO_VAL_INT_PLUS_MICRO 2
+#define IIO_VAL_INT_PLUS_NANO 3
+
 #endif /* _IIO_TYPES_H_ */
diff --git a/drivers/staging/keucr/TODO b/drivers/staging/keucr/TODO
index 1c48e40..d6da656 100644
--- a/drivers/staging/keucr/TODO
+++ b/drivers/staging/keucr/TODO
@@ -9,4 +9,4 @@
 	- smcommon.h & smilsub.c: use kernel hweight8(), hweight16()
 
 Please send any patches for this driver to Al Cho <acho@novell.com> and
-Greg Kroah-Hartman <gregkh@suse.de>.
+Greg Kroah-Hartman <gregkh@linuxfoundation.org>.
diff --git a/drivers/staging/keucr/transport.h b/drivers/staging/keucr/transport.h
index 4ae57d0..2a11a98 100644
--- a/drivers/staging/keucr/transport.h
+++ b/drivers/staging/keucr/transport.h
@@ -3,43 +3,6 @@
 
 #include <linux/blkdev.h>
 
-/* Bulk only data structures */
-
-/* command block wrapper */
-struct bulk_cb_wrap {
-	__le32	Signature;			/* contains 'USBC' */
-	__u32	Tag;				/* unique per command id */
-	__le32	DataTransferLength;	/* size of data */
-	__u8	Flags;				/* direction in bit 0 */
-	__u8	Lun;					/* LUN normally 0 */
-	__u8	Length;				/* of of the CDB */
-	__u8	CDB[16];				/* max command */
-};
-
-#define US_BULK_CB_WRAP_LEN	31
-#define US_BULK_CB_SIGN		0x43425355	/*spells out USBC */
-#define US_BULK_FLAG_IN		1
-#define US_BULK_FLAG_OUT	0
-
-/* command status wrapper */
-struct bulk_cs_wrap {
-	__le32	Signature;		/* should = 'USBS' */
-	__u32		Tag;			/* same as original command */
-	__le32	Residue;		/* amount not transferred */
-	__u8		Status;		/* see below */
-	__u8		Filler[18];
-};
-
-#define US_BULK_CS_WRAP_LEN	13
-#define US_BULK_CS_SIGN		0x53425355	/* spells out 'USBS' */
-#define US_BULK_STAT_OK		0
-#define US_BULK_STAT_FAIL	1
-#define US_BULK_STAT_PHASE	2
-
-/* bulk-only class specific requests */
-#define US_BULK_RESET_REQUEST	0xff
-#define US_BULK_GET_MAX_LUN	0xfe
-
 /* usb_stor_bulk_transfer_xxx() return codes, in order of severity */
 #define USB_STOR_XFER_GOOD	0	/* good transfer                 */
 #define USB_STOR_XFER_SHORT	1	/* transferred less than expected */
diff --git a/drivers/staging/line6/capture.c b/drivers/staging/line6/capture.c
index 127f952..c85c5b6 100644
--- a/drivers/staging/line6/capture.c
+++ b/drivers/staging/line6/capture.c
@@ -107,7 +107,7 @@
 	Wait until unlinking of all currently active capture URBs has been
 	finished.
 */
-static void wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
+void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
 {
 	int timeout = HZ;
 	unsigned int i;
@@ -134,7 +134,7 @@
 void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
 {
 	line6_unlink_audio_in_urbs(line6pcm);
-	wait_clear_audio_in_urbs(line6pcm);
+	line6_wait_clear_audio_in_urbs(line6pcm);
 }
 
 /*
@@ -193,25 +193,6 @@
 	}
 }
 
-int line6_alloc_capture_buffer(struct snd_line6_pcm *line6pcm)
-{
-	/* We may be invoked multiple times in a row so allocate once only */
-	if (line6pcm->buffer_in)
-		return 0;
-
-	line6pcm->buffer_in =
-		kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
-			line6pcm->max_packet_size, GFP_KERNEL);
-
-	if (!line6pcm->buffer_in) {
-		dev_err(line6pcm->line6->ifcdev,
-			"cannot malloc capture buffer\n");
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
 void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm)
 {
 	kfree(line6pcm->buffer_in);
@@ -273,9 +254,9 @@
 		line6pcm->prev_fsize = fsize;
 
 #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-		if (!(line6pcm->flags & MASK_PCM_IMPULSE))
+		if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
 #endif
-			if (test_bit(BIT_PCM_ALSA_CAPTURE, &line6pcm->flags)
+			if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, &line6pcm->flags)
 			    && (fsize > 0))
 				line6_capture_copy(line6pcm, fbuf, fsize);
 	}
@@ -291,9 +272,9 @@
 		submit_audio_in_urb(line6pcm);
 
 #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-		if (!(line6pcm->flags & MASK_PCM_IMPULSE))
+		if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
 #endif
-			if (test_bit(BIT_PCM_ALSA_CAPTURE, &line6pcm->flags))
+			if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, &line6pcm->flags))
 				line6_capture_check_period(line6pcm, length);
 	}
 }
@@ -341,17 +322,17 @@
 	}
 	/* -- [FD] end */
 
-	if ((line6pcm->flags & MASK_CAPTURE) == 0) {
-		ret = line6_alloc_capture_buffer(line6pcm);
+	ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
 
-		if (ret < 0)
-			return ret;
-	}
+	if (ret < 0)
+		return ret;
 
 	ret = snd_pcm_lib_malloc_pages(substream,
 				       params_buffer_bytes(hw_params));
-	if (ret < 0)
+	if (ret < 0) {
+		line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
 		return ret;
+	}
 
 	line6pcm->period_in = params_period_bytes(hw_params);
 	return 0;
@@ -361,12 +342,7 @@
 static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream)
 {
 	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-	if ((line6pcm->flags & MASK_CAPTURE) == 0) {
-		line6_unlink_wait_clear_audio_in_urbs(line6pcm);
-		line6_free_capture_buffer(line6pcm);
-	}
-
+	line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
 	return snd_pcm_lib_free_pages(substream);
 }
 
@@ -380,7 +356,7 @@
 #ifdef CONFIG_PM
 	case SNDRV_PCM_TRIGGER_RESUME:
 #endif
-		err = line6_pcm_start(line6pcm, MASK_PCM_ALSA_CAPTURE);
+		err = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
 
 		if (err < 0)
 			return err;
@@ -391,7 +367,7 @@
 #ifdef CONFIG_PM
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 #endif
-		err = line6_pcm_stop(line6pcm, MASK_PCM_ALSA_CAPTURE);
+		err = line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
 
 		if (err < 0)
 			return err;
diff --git a/drivers/staging/line6/capture.h b/drivers/staging/line6/capture.h
index 366cbaa..4157bcb 100644
--- a/drivers/staging/line6/capture.h
+++ b/drivers/staging/line6/capture.h
@@ -19,7 +19,6 @@
 
 extern struct snd_pcm_ops snd_line6_capture_ops;
 
-extern int line6_alloc_capture_buffer(struct snd_line6_pcm *line6pcm);
 extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf,
 			       int fsize);
 extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm,
@@ -30,6 +29,7 @@
 extern void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm);
 extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm
 						  *line6pcm);
+extern void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm);
 extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd);
 
 #endif
diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c
index 6a1959e..e8023af 100644
--- a/drivers/staging/line6/driver.c
+++ b/drivers/staging/line6/driver.c
@@ -1346,7 +1346,7 @@
 		if (line6pcm == NULL)
 			continue;
 
-		line6_pcm_stop(line6pcm, ~0);
+		line6_pcm_release(line6pcm, ~0);
 	}
 
 	usb_deregister(&line6_driver);
diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c
index 37675e6..90d2d44 100644
--- a/drivers/staging/line6/pcm.c
+++ b/drivers/staging/line6/pcm.c
@@ -52,9 +52,9 @@
 	line6pcm->impulse_volume = value;
 
 	if (value > 0)
-		line6_pcm_start(line6pcm, MASK_PCM_IMPULSE);
+		line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE);
 	else
-		line6_pcm_stop(line6pcm, MASK_PCM_IMPULSE);
+		line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE);
 
 	return count;
 }
@@ -92,29 +92,43 @@
 	return ((flags0 & mask) == 0) && ((flags1 & mask) != 0);
 }
 
-int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels)
+int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels)
 {
 	unsigned long flags_old =
 	    __sync_fetch_and_or(&line6pcm->flags, channels);
 	unsigned long flags_new = flags_old | channels;
+	unsigned long flags_final = flags_old;
 	int err = 0;
 	
 	line6pcm->prev_fbuf = NULL;
 
-	if (test_flags(flags_old, flags_new, MASK_CAPTURE)) {
+	if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) {
+		/* We may be invoked multiple times in a row so allocate once only */
+		if (!line6pcm->buffer_in) {
+			line6pcm->buffer_in =
+				kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
+					line6pcm->max_packet_size, GFP_KERNEL);
+
+			if (!line6pcm->buffer_in) {
+				dev_err(line6pcm->line6->ifcdev,
+					"cannot malloc capture buffer\n");
+				err = -ENOMEM;
+				goto pcm_acquire_error;
+			}
+
+			flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER;
+		}
+	}
+
+	if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) {
 		/*
 		   Waiting for completion of active URBs in the stop handler is
 		   a bug, we therefore report an error if capturing is restarted
 		   too soon.
 		 */
-		if (line6pcm->active_urb_in | line6pcm->unlink_urb_in)
+		if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) {
+			dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
 			return -EBUSY;
-
-		if (!(flags_new & MASK_PCM_ALSA_CAPTURE)) {
-			err = line6_alloc_capture_buffer(line6pcm);
-
-			if (err < 0)
-				goto pcm_start_error;
 		}
 
 		line6pcm->count_in = 0;
@@ -122,55 +136,78 @@
 		err = line6_submit_audio_in_all_urbs(line6pcm);
 
 		if (err < 0)
-			goto pcm_start_error;
+			goto pcm_acquire_error;
+
+		flags_final |= channels & LINE6_BITS_CAPTURE_STREAM;
 	}
 
-	if (test_flags(flags_old, flags_new, MASK_PLAYBACK)) {
+	if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) {
+		/* We may be invoked multiple times in a row so allocate once only */
+		if (!line6pcm->buffer_out) {
+			line6pcm->buffer_out =
+				kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
+					line6pcm->max_packet_size, GFP_KERNEL);
+
+			if (!line6pcm->buffer_out) {
+				dev_err(line6pcm->line6->ifcdev,
+					"cannot malloc playback buffer\n");
+				err = -ENOMEM;
+				goto pcm_acquire_error;
+			}
+
+			flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER;
+		}
+	}
+
+	if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) {
 		/*
-		   See comment above regarding PCM restart.
-		 */
-		if (line6pcm->active_urb_out | line6pcm->unlink_urb_out)
+		  See comment above regarding PCM restart.
+		*/
+		if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) {
+			dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
 			return -EBUSY;
-
-		if (!(flags_new & MASK_PCM_ALSA_PLAYBACK)) {
-			err = line6_alloc_playback_buffer(line6pcm);
-
-			if (err < 0)
-				goto pcm_start_error;
 		}
 
 		line6pcm->count_out = 0;
 		err = line6_submit_audio_out_all_urbs(line6pcm);
 
 		if (err < 0)
-			goto pcm_start_error;
+			goto pcm_acquire_error;
+
+		flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM;
 	}
 
 	return 0;
 
-pcm_start_error:
-	__sync_fetch_and_and(&line6pcm->flags, ~channels);
+pcm_acquire_error:
+	/*
+	   If not all requested resources/streams could be obtained, release
+	   those which were successfully obtained (if any).
+	*/
+	line6_pcm_release(line6pcm, flags_final & channels);
 	return err;
 }
 
-int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels)
+int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels)
 {
 	unsigned long flags_old =
 	    __sync_fetch_and_and(&line6pcm->flags, ~channels);
 	unsigned long flags_new = flags_old & ~channels;
 
-	if (test_flags(flags_new, flags_old, MASK_CAPTURE)) {
+	if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM))
 		line6_unlink_audio_in_urbs(line6pcm);
 
-		if (!(flags_old & MASK_PCM_ALSA_CAPTURE))
-			line6_free_capture_buffer(line6pcm);
+	if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) {
+		line6_wait_clear_audio_in_urbs(line6pcm);
+		line6_free_capture_buffer(line6pcm);
 	}
 
-	if (test_flags(flags_new, flags_old, MASK_PLAYBACK)) {
+	if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM))
 		line6_unlink_audio_out_urbs(line6pcm);
 
-		if (!(flags_old & MASK_PCM_ALSA_PLAYBACK))
-			line6_free_playback_buffer(line6pcm);
+	if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) {
+		line6_wait_clear_audio_out_urbs(line6pcm);
+		line6_free_playback_buffer(line6pcm);
 	}
 
 	return 0;
@@ -185,7 +222,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&line6pcm->lock_trigger, flags);
-	clear_bit(BIT_PREPARED, &line6pcm->flags);
+	clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags);
 
 	snd_pcm_group_for_each_entry(s, substream) {
 		switch (s->stream) {
@@ -498,13 +535,13 @@
 
 	switch (substream->stream) {
 	case SNDRV_PCM_STREAM_PLAYBACK:
-		if ((line6pcm->flags & MASK_PLAYBACK) == 0)
+		if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0)
 			line6_unlink_wait_clear_audio_out_urbs(line6pcm);
 
 		break;
 
 	case SNDRV_PCM_STREAM_CAPTURE:
-		if ((line6pcm->flags & MASK_CAPTURE) == 0)
+		if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0)
 			line6_unlink_wait_clear_audio_in_urbs(line6pcm);
 
 		break;
@@ -513,7 +550,7 @@
 		MISSING_CASE;
 	}
 
-	if (!test_and_set_bit(BIT_PREPARED, &line6pcm->flags)) {
+	if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) {
 		line6pcm->count_out = 0;
 		line6pcm->pos_out = 0;
 		line6pcm->pos_out_done = 0;
diff --git a/drivers/staging/line6/pcm.h b/drivers/staging/line6/pcm.h
index 55d8297..5210ec8 100644
--- a/drivers/staging/line6/pcm.h
+++ b/drivers/staging/line6/pcm.h
@@ -46,57 +46,131 @@
 		(line6pcm->pcm->streams[stream].substream)
 
 /*
-	PCM mode bits and masks.
-	"ALSA": operations triggered by applications via ALSA
-	"MONITOR": software monitoring
-	"IMPULSE": optional impulse response operation
+	PCM mode bits.
+
+	There are several features of the Line6 USB driver which require PCM
+	data to be exchanged with the device:
+	*) PCM playback and capture via ALSA
+	*) software monitoring (for devices without hardware monitoring)
+	*) optional impulse response measurement
+	However, from the device's point of view, there is just a single
+	capture and playback stream, which must be shared between these
+	subsystems. It is therefore necessary to maintain the state of the
+	subsystems with respect to PCM usage. We define several constants of
+	the form LINE6_BIT_PCM_<subsystem>_<direction>_<resource> with the
+	following meanings:
+	*) <subsystem> is one of
+	-) ALSA: PCM playback and capture via ALSA
+	-) MONITOR: software monitoring
+	-) IMPULSE: optional impulse response measurement
+	*) <direction> is one of
+	-) PLAYBACK: audio output (from host to device)
+	-) CAPTURE: audio input (from device to host)
+	*) <resource> is one of
+	-) BUFFER: buffer required by PCM data stream
+	-) STREAM: actual PCM data stream
+
+	The subsystems call line6_pcm_acquire() to acquire the (shared)
+	resources needed for a particular operation (e.g., allocate the buffer
+	for ALSA playback or start the capture stream for software monitoring).
+	When a resource is no longer needed, it is released by calling
+	line6_pcm_release(). Buffer allocation and stream startup are handled
+	separately to allow the ALSA kernel driver to perform them at
+	appropriate places (since the callback which starts a PCM stream is not
+	allowed to sleep).
 */
 enum {
-	/* individual bits: */
-	BIT_PCM_ALSA_PLAYBACK,
-	BIT_PCM_ALSA_CAPTURE,
-	BIT_PCM_MONITOR_PLAYBACK,
-	BIT_PCM_MONITOR_CAPTURE,
+	/* individual bit indices: */
+	LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER,
+	LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM,
+	LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER,
+	LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
+	LINE6_INDEX_PCM_MONITOR_PLAYBACK_BUFFER,
+	LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM,
+	LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER,
+	LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM,
 #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-	BIT_PCM_IMPULSE_PLAYBACK,
-	BIT_PCM_IMPULSE_CAPTURE,
+	LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER,
+	LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM,
+	LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER,
+	LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM,
 #endif
-	BIT_PAUSE_PLAYBACK,
-	BIT_PREPARED,
+	LINE6_INDEX_PAUSE_PLAYBACK,
+	LINE6_INDEX_PREPARED,
 
-	/* individual masks: */
-/* *INDENT-OFF* */
-	MASK_PCM_ALSA_PLAYBACK    = 1 << BIT_PCM_ALSA_PLAYBACK,
-	MASK_PCM_ALSA_CAPTURE     = 1 << BIT_PCM_ALSA_CAPTURE,
-	MASK_PCM_MONITOR_PLAYBACK = 1 << BIT_PCM_MONITOR_PLAYBACK,
-	MASK_PCM_MONITOR_CAPTURE  = 1 << BIT_PCM_MONITOR_CAPTURE,
+	/* individual bit masks: */
+	LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER),
+	LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM),
+	LINE6_BIT(PCM_ALSA_CAPTURE_BUFFER),
+	LINE6_BIT(PCM_ALSA_CAPTURE_STREAM),
+	LINE6_BIT(PCM_MONITOR_PLAYBACK_BUFFER),
+	LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM),
+	LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER),
+	LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM),
 #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-	MASK_PCM_IMPULSE_PLAYBACK = 1 << BIT_PCM_IMPULSE_PLAYBACK,
-	MASK_PCM_IMPULSE_CAPTURE  = 1 << BIT_PCM_IMPULSE_CAPTURE,
+	LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER),
+	LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM),
+	LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER),
+	LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM),
 #endif
-	MASK_PAUSE_PLAYBACK       = 1 << BIT_PAUSE_PLAYBACK,
-	MASK_PREPARED             = 1 << BIT_PREPARED,
-/* *INDENT-ON* */
+	LINE6_BIT(PAUSE_PLAYBACK),
+	LINE6_BIT(PREPARED),
 
-	/* combined masks (by operation): */
-	MASK_PCM_ALSA = MASK_PCM_ALSA_PLAYBACK | MASK_PCM_ALSA_CAPTURE,
-	MASK_PCM_MONITOR = MASK_PCM_MONITOR_PLAYBACK | MASK_PCM_MONITOR_CAPTURE,
+	/* combined bit masks (by operation): */
+	LINE6_BITS_PCM_ALSA_BUFFER =
+	    LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
+	    LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER,
+
+	LINE6_BITS_PCM_ALSA_STREAM =
+	    LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
+	    LINE6_BIT_PCM_ALSA_CAPTURE_STREAM,
+
+	LINE6_BITS_PCM_MONITOR =
+	    LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER |
+	    LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM |
+	    LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER |
+	    LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
+
 #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-	MASK_PCM_IMPULSE = MASK_PCM_IMPULSE_PLAYBACK | MASK_PCM_IMPULSE_CAPTURE,
+	LINE6_BITS_PCM_IMPULSE =
+	    LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
+	    LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
+	    LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
+	    LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM,
 #endif
 
-	/* combined masks (by direction): */
+	/* combined bit masks (by direction): */
+	LINE6_BITS_PLAYBACK_BUFFER =
 #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-	MASK_PLAYBACK =
-	    MASK_PCM_ALSA_PLAYBACK | MASK_PCM_MONITOR_PLAYBACK |
-	    MASK_PCM_IMPULSE_PLAYBACK,
-	MASK_CAPTURE =
-	    MASK_PCM_ALSA_CAPTURE | MASK_PCM_MONITOR_CAPTURE |
-	    MASK_PCM_IMPULSE_CAPTURE
-#else
-	MASK_PLAYBACK = MASK_PCM_ALSA_PLAYBACK | MASK_PCM_MONITOR_PLAYBACK,
-	MASK_CAPTURE = MASK_PCM_ALSA_CAPTURE | MASK_PCM_MONITOR_CAPTURE
+	    LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
 #endif
+	    LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
+	    LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER ,
+
+	LINE6_BITS_PLAYBACK_STREAM =
+#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
+	    LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
+#endif
+	    LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
+	    LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM ,
+
+	LINE6_BITS_CAPTURE_BUFFER =
+#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
+	    LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
+#endif
+	    LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER |
+	    LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER ,
+
+	LINE6_BITS_CAPTURE_STREAM =
+#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
+	    LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM |
+#endif
+	    LINE6_BIT_PCM_ALSA_CAPTURE_STREAM |
+	    LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
+	
+	LINE6_BITS_STREAM =
+	    LINE6_BITS_PLAYBACK_STREAM |
+	    LINE6_BITS_CAPTURE_STREAM
 };
 
 struct line6_pcm_properties {
@@ -290,7 +364,7 @@
 #endif
 
 	/**
-		 Several status bits (see BIT_*).
+		 Several status bits (see LINE6_BIT_*).
 	*/
 	unsigned long flags;
 
@@ -302,16 +376,7 @@
 extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd);
 extern int snd_line6_prepare(struct snd_pcm_substream *substream);
 extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm);
-extern int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels);
-extern int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels);
-
-#define PRINT_FRAME_DIFF(op) {						\
-	static int diff_prev = 1000;					\
-	int diff = line6pcm->last_frame_out - line6pcm->last_frame_in;	\
-	if ((diff != diff_prev) && (abs(diff) < 100)) {			\
-		printk(KERN_INFO "%s frame diff = %d\n", op, diff);	\
-		diff_prev = diff;					\
-	}								\
-}
+extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels);
+extern int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels);
 
 #endif
diff --git a/drivers/staging/line6/playback.c b/drivers/staging/line6/playback.c
index 4152db2..a0ab9d0 100644
--- a/drivers/staging/line6/playback.c
+++ b/drivers/staging/line6/playback.c
@@ -166,7 +166,7 @@
 		struct usb_iso_packet_descriptor *fout =
 		    &urb_out->iso_frame_desc[i];
 
-		if (line6pcm->flags & MASK_CAPTURE)
+		if (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM)
 			fsize = line6pcm->prev_fsize;
 
 		if (fsize == 0) {
@@ -196,8 +196,8 @@
 	urb_out->transfer_buffer_length = urb_size;
 	urb_out->context = line6pcm;
 
-	if (test_bit(BIT_PCM_ALSA_PLAYBACK, &line6pcm->flags) &&
-	    !test_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags)) {
+	if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags) &&
+	    !test_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags)) {
 		struct snd_pcm_runtime *runtime =
 		    get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime;
 
@@ -238,10 +238,10 @@
 
 	if (line6pcm->prev_fbuf != NULL) {
 #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-		if (line6pcm->flags & MASK_PCM_IMPULSE) {
+		if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) {
 			create_impulse_test_signal(line6pcm, urb_out,
 						   bytes_per_frame);
-			if (line6pcm->flags & MASK_PCM_ALSA_CAPTURE) {
+			if (line6pcm->flags & LINE6_BIT_PCM_ALSA_CAPTURE_STREAM) {
 				line6_capture_copy(line6pcm,
 						   urb_out->transfer_buffer,
 						   urb_out->
@@ -254,8 +254,8 @@
 			if (!
 			    (line6pcm->line6->
 			     properties->capabilities & LINE6_BIT_HWMON)
-&& (line6pcm->flags & MASK_PLAYBACK)
-&& (line6pcm->flags & MASK_CAPTURE))
+			    && (line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM)
+			    && (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM))
 				add_monitor_signal(urb_out, line6pcm->prev_fbuf,
 						   line6pcm->volume_monitor,
 						   bytes_per_frame);
@@ -321,7 +321,7 @@
 /*
 	Wait until unlinking of all currently active playback URBs has been finished.
 */
-static void wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
+void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
 {
 	int timeout = HZ;
 	unsigned int i;
@@ -348,26 +348,7 @@
 void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
 {
 	line6_unlink_audio_out_urbs(line6pcm);
-	wait_clear_audio_out_urbs(line6pcm);
-}
-
-int line6_alloc_playback_buffer(struct snd_line6_pcm *line6pcm)
-{
-	/* We may be invoked multiple times in a row so allocate once only */
-	if (line6pcm->buffer_out)
-		return 0;
-
-	line6pcm->buffer_out =
-		kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
-			line6pcm->max_packet_size, GFP_KERNEL);
-
-	if (!line6pcm->buffer_out) {
-		dev_err(line6pcm->line6->ifcdev,
-			"cannot malloc playback buffer\n");
-		return -ENOMEM;
-	}
-
-	return 0;
+	line6_wait_clear_audio_out_urbs(line6pcm);
 }
 
 void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm)
@@ -407,7 +388,7 @@
 
 	spin_lock_irqsave(&line6pcm->lock_audio_out, flags);
 
-	if (test_bit(BIT_PCM_ALSA_PLAYBACK, &line6pcm->flags)) {
+	if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) {
 		struct snd_pcm_runtime *runtime = substream->runtime;
 		line6pcm->pos_out_done +=
 		    length / line6pcm->properties->bytes_per_frame;
@@ -432,7 +413,7 @@
 	if (!shutdown) {
 		submit_audio_out_urb(line6pcm);
 
-		if (test_bit(BIT_PCM_ALSA_PLAYBACK, &line6pcm->flags)) {
+		if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) {
 			line6pcm->bytes_out += length;
 			if (line6pcm->bytes_out >= line6pcm->period_out) {
 				line6pcm->bytes_out %= line6pcm->period_out;
@@ -484,17 +465,17 @@
 	}
 	/* -- [FD] end */
 
-	if ((line6pcm->flags & MASK_PLAYBACK) == 0) {
-		ret = line6_alloc_playback_buffer(line6pcm);
+	ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
 
-		if (ret < 0)
-			return ret;
-	}
+	if (ret < 0)
+		return ret;
 
 	ret = snd_pcm_lib_malloc_pages(substream,
 				       params_buffer_bytes(hw_params));
-	if (ret < 0)
+	if (ret < 0) {
+		line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
 		return ret;
+	}
 
 	line6pcm->period_out = params_period_bytes(hw_params);
 	return 0;
@@ -504,12 +485,7 @@
 static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream)
 {
 	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-	if ((line6pcm->flags & MASK_PLAYBACK) == 0) {
-		line6_unlink_wait_clear_audio_out_urbs(line6pcm);
-		line6_free_playback_buffer(line6pcm);
-	}
-
+	line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
 	return snd_pcm_lib_free_pages(substream);
 }
 
@@ -523,7 +499,7 @@
 #ifdef CONFIG_PM
 	case SNDRV_PCM_TRIGGER_RESUME:
 #endif
-		err = line6_pcm_start(line6pcm, MASK_PCM_ALSA_PLAYBACK);
+		err = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
 
 		if (err < 0)
 			return err;
@@ -534,7 +510,7 @@
 #ifdef CONFIG_PM
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 #endif
-		err = line6_pcm_stop(line6pcm, MASK_PCM_ALSA_PLAYBACK);
+		err = line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
 
 		if (err < 0)
 			return err;
@@ -542,11 +518,11 @@
 		break;
 
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		set_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags);
+		set_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
 		break;
 
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		clear_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags);
+		clear_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
 		break;
 
 	default:
diff --git a/drivers/staging/line6/playback.h b/drivers/staging/line6/playback.h
index 02487ff..743bd6f 100644
--- a/drivers/staging/line6/playback.h
+++ b/drivers/staging/line6/playback.h
@@ -29,13 +29,13 @@
 
 extern struct snd_pcm_ops snd_line6_playback_ops;
 
-extern int line6_alloc_playback_buffer(struct snd_line6_pcm *line6pcm);
 extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm);
 extern void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm);
 extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm);
 extern void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm);
 extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm
 						   *line6pcm);
+extern void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm);
 extern int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd);
 
 #endif
diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c
index f310578..b754f69 100644
--- a/drivers/staging/line6/toneport.c
+++ b/drivers/staging/line6/toneport.c
@@ -207,9 +207,9 @@
 	line6pcm->volume_monitor = ucontrol->value.integer.value[0];
 
 	if (line6pcm->volume_monitor > 0)
-		line6_pcm_start(line6pcm, MASK_PCM_MONITOR);
+		line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR);
 	else
-		line6_pcm_stop(line6pcm, MASK_PCM_MONITOR);
+		line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
 
 	return 1;
 }
@@ -264,7 +264,7 @@
 {
 	struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg;
 	struct usb_line6 *line6 = &toneport->line6;
-	line6_pcm_start(line6->line6pcm, MASK_PCM_MONITOR);
+	line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR);
 }
 
 /* control definition */
@@ -320,7 +320,9 @@
 	/* initialize source select: */
 	switch (usbdev->descriptor.idProduct) {
 	case LINE6_DEVID_TONEPORT_UX1:
+	case LINE6_DEVID_TONEPORT_UX2:
 	case LINE6_DEVID_PODSTUDIO_UX1:
+	case LINE6_DEVID_PODSTUDIO_UX2:
 		toneport_send_cmd(usbdev,
 				  toneport_source_info[toneport->source].code,
 				  0x0000);
@@ -363,7 +365,9 @@
 	/* register source select control: */
 	switch (usbdev->descriptor.idProduct) {
 	case LINE6_DEVID_TONEPORT_UX1:
+	case LINE6_DEVID_TONEPORT_UX2:
 	case LINE6_DEVID_PODSTUDIO_UX1:
+	case LINE6_DEVID_PODSTUDIO_UX2:
 		err =
 		    snd_ctl_add(line6->card,
 				snd_ctl_new1(&toneport_control_source,
@@ -442,7 +446,7 @@
 		struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm;
 
 		if (line6pcm != NULL) {
-			line6_pcm_stop(line6pcm, MASK_PCM_MONITOR);
+			line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
 			line6_pcm_disconnect(line6pcm);
 		}
 	}
diff --git a/drivers/staging/line6/usbdefs.h b/drivers/staging/line6/usbdefs.h
index aff9e5c..353d59d 100644
--- a/drivers/staging/line6/usbdefs.h
+++ b/drivers/staging/line6/usbdefs.h
@@ -39,31 +39,29 @@
 #define LINE6_DEVID_TONEPORT_UX2  0x4142
 #define LINE6_DEVID_VARIAX        0x534d
 
-enum {
-	LINE6_ID_BASSPODXT,
-	LINE6_ID_BASSPODXTLIVE,
-	LINE6_ID_BASSPODXTPRO,
-	LINE6_ID_GUITARPORT,
-	LINE6_ID_POCKETPOD,
-	LINE6_ID_PODHD300,
-	LINE6_ID_PODHD500,
-	LINE6_ID_PODSTUDIO_GX,
-	LINE6_ID_PODSTUDIO_UX1,
-	LINE6_ID_PODSTUDIO_UX2,
-	LINE6_ID_PODX3,
-	LINE6_ID_PODX3LIVE,
-	LINE6_ID_PODXT,
-	LINE6_ID_PODXTLIVE,
-	LINE6_ID_PODXTPRO,
-	LINE6_ID_TONEPORT_GX,
-	LINE6_ID_TONEPORT_UX1,
-	LINE6_ID_TONEPORT_UX2,
-	LINE6_ID_VARIAX
-};
-
-#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_ID_ ## x
+#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x
 
 enum {
+	LINE6_INDEX_BASSPODXT,
+	LINE6_INDEX_BASSPODXTLIVE,
+	LINE6_INDEX_BASSPODXTPRO,
+	LINE6_INDEX_GUITARPORT,
+	LINE6_INDEX_POCKETPOD,
+	LINE6_INDEX_PODHD300,
+	LINE6_INDEX_PODHD500,
+	LINE6_INDEX_PODSTUDIO_GX,
+	LINE6_INDEX_PODSTUDIO_UX1,
+	LINE6_INDEX_PODSTUDIO_UX2,
+	LINE6_INDEX_PODX3,
+	LINE6_INDEX_PODX3LIVE,
+	LINE6_INDEX_PODXT,
+	LINE6_INDEX_PODXTLIVE,
+	LINE6_INDEX_PODXTPRO,
+	LINE6_INDEX_TONEPORT_GX,
+	LINE6_INDEX_TONEPORT_UX1,
+	LINE6_INDEX_TONEPORT_UX2,
+	LINE6_INDEX_VARIAX,
+
 	LINE6_BIT(BASSPODXT),
 	LINE6_BIT(BASSPODXTLIVE),
 	LINE6_BIT(BASSPODXTPRO),
diff --git a/drivers/staging/media/easycap/easycap_main.c b/drivers/staging/media/easycap/easycap_main.c
index 8ff5f38..3d439b7 100644
--- a/drivers/staging/media/easycap/easycap_main.c
+++ b/drivers/staging/media/easycap/easycap_main.c
@@ -3825,6 +3825,7 @@
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 			pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
 			if (!pdata_urb) {
+				usb_free_urb(purb);
 				SAM("ERROR: Could not allocate struct data_urb.\n");
 				return -ENOMEM;
 			}
diff --git a/drivers/staging/media/lirc/lirc_sasem.c b/drivers/staging/media/lirc/lirc_sasem.c
index 7855baa..7442104 100644
--- a/drivers/staging/media/lirc/lirc_sasem.c
+++ b/drivers/staging/media/lirc/lirc_sasem.c
@@ -90,11 +90,11 @@
 struct sasem_context {
 
 	struct usb_device *dev;
-	int vfd_isopen;			/* VFD port has been opened       */
-	unsigned int vfd_contrast;	/* VFD contrast		   */
-	int ir_isopen;			/* IR port has been opened	*/
-	int dev_present;		/* USB device presence	    */
-	struct mutex ctx_lock;		/* to lock this object	    */
+	int vfd_isopen;			/* VFD port has been opened */
+	unsigned int vfd_contrast;	/* VFD contrast */
+	int ir_isopen;			/* IR port has been opened */
+	int dev_present;		/* USB device presence */
+	struct mutex ctx_lock;		/* to lock this object */
 	wait_queue_head_t remove_ok;	/* For unexpected USB disconnects */
 
 	struct lirc_driver *driver;
@@ -106,10 +106,11 @@
 	unsigned char usb_tx_buf[8];
 
 	struct tx_t {
-		unsigned char data_buf[SASEM_DATA_BUF_SZ]; /* user data buffer */
+		unsigned char data_buf[SASEM_DATA_BUF_SZ]; /* user data
+							    * buffer */
 		struct completion finished;  /* wait for write to finish  */
-		atomic_t busy;		     /* write in progress	 */
-		int status;		     /* status of tx completion   */
+		atomic_t busy;		     /* write in progress */
+		int status;		     /* status of tx completion */
 	} tx;
 
 	/* for dealing with repeat codes (wish there was a toggle bit!) */
diff --git a/drivers/staging/mei/TODO b/drivers/staging/mei/TODO
index 7d9a13b..fc26601 100644
--- a/drivers/staging/mei/TODO
+++ b/drivers/staging/mei/TODO
@@ -3,5 +3,8 @@
 Upon Unstaging:
 	- move mei.h to include/linux/mei.h
 	- Documentation/ioctl/ioctl-number.txt
+	- move mei.txt under Documentation/mei/
+	- move mei-amt-version.c under Documentation/mei
+	- add hostprogs-y for mei-amt-version.c
 	- drop mei_version.h
 	- Updated MAINTAINERS
diff --git a/drivers/staging/mei/hw.h b/drivers/staging/mei/hw.h
index 9b9008c..24c4c96 100644
--- a/drivers/staging/mei/hw.h
+++ b/drivers/staging/mei/hw.h
@@ -1,7 +1,7 @@
 /*
  *
  * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2011, Intel Corporation.
+ * Copyright (c) 2003-2012, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -141,6 +141,11 @@
 #define HBM_MAJOR_VERSION                   1
 #define HBM_TIMEOUT                         1	/* 1 second */
 
+/* Host bus message command opcode */
+#define MEI_HBM_CMD_OP_MSK                  0x7f
+/* Host bus message command RESPONSE */
+#define MEI_HBM_CMD_RES_MSK                 0x80
+
 /*
  * MEI Bus Message Command IDs
  */
@@ -164,7 +169,7 @@
 #define CLIENT_DISCONNECT_REQ_CMD           0x07
 #define CLIENT_DISCONNECT_RES_CMD           0x87
 
-#define MEI_FLOW_CONTROL_CMD               0x08
+#define MEI_FLOW_CONTROL_CMD                0x08
 
 /*
  * MEI Stop Reason
@@ -213,15 +218,9 @@
 } __packed;
 
 
-struct hbm_cmd {
-	u8 cmd:7;
-	u8 is_response:1;
-} __packed;
-
-
 struct mei_bus_message {
-	struct hbm_cmd cmd;
-	u8 command_specific_data[];
+	u8 hbm_cmd;
+	u8 data[0];
 } __packed;
 
 struct hbm_version {
@@ -230,41 +229,41 @@
 } __packed;
 
 struct hbm_host_version_request {
-	struct hbm_cmd cmd;
+	u8 hbm_cmd;
 	u8 reserved;
 	struct hbm_version host_version;
 } __packed;
 
 struct hbm_host_version_response {
-	struct hbm_cmd cmd;
-	int host_version_supported;
+	u8 hbm_cmd;
+	u8 host_version_supported;
 	struct hbm_version me_max_version;
 } __packed;
 
 struct hbm_host_stop_request {
-	struct hbm_cmd cmd;
+	u8 hbm_cmd;
 	u8 reason;
 	u8 reserved[2];
 } __packed;
 
 struct hbm_host_stop_response {
-	struct hbm_cmd cmd;
+	u8 hbm_cmd;
 	u8 reserved[3];
 } __packed;
 
 struct hbm_me_stop_request {
-	struct hbm_cmd cmd;
+	u8 hbm_cmd;
 	u8 reason;
 	u8 reserved[2];
 } __packed;
 
 struct hbm_host_enum_request {
-	struct hbm_cmd cmd;
+	u8 hbm_cmd;
 	u8 reserved[3];
 } __packed;
 
 struct hbm_host_enum_response {
-	struct hbm_cmd cmd;
+	u8 hbm_cmd;
 	u8 reserved[3];
 	u8 valid_addresses[32];
 } __packed;
@@ -279,14 +278,14 @@
 } __packed;
 
 struct hbm_props_request {
-	struct hbm_cmd cmd;
+	u8 hbm_cmd;
 	u8 address;
 	u8 reserved[2];
 } __packed;
 
 
 struct hbm_props_response {
-	struct hbm_cmd cmd;
+	u8 hbm_cmd;
 	u8 address;
 	u8 status;
 	u8 reserved[1];
@@ -294,21 +293,21 @@
 } __packed;
 
 struct hbm_client_connect_request {
-	struct hbm_cmd cmd;
+	u8 hbm_cmd;
 	u8 me_addr;
 	u8 host_addr;
 	u8 reserved;
 } __packed;
 
 struct hbm_client_connect_response {
-	struct hbm_cmd cmd;
+	u8 hbm_cmd;
 	u8 me_addr;
 	u8 host_addr;
 	u8 status;
 } __packed;
 
 struct hbm_client_disconnect_request {
-	struct hbm_cmd cmd;
+	u8 hbm_cmd;
 	u8 me_addr;
 	u8 host_addr;
 	u8 reserved[1];
@@ -317,7 +316,7 @@
 #define MEI_FC_MESSAGE_RESERVED_LENGTH           5
 
 struct hbm_flow_control {
-	struct hbm_cmd cmd;
+	u8 hbm_cmd;
 	u8 me_addr;
 	u8 host_addr;
 	u8 reserved[MEI_FC_MESSAGE_RESERVED_LENGTH];
diff --git a/drivers/staging/mei/init.c b/drivers/staging/mei/init.c
index 4ac3696..eab711f 100644
--- a/drivers/staging/mei/init.c
+++ b/drivers/staging/mei/init.c
@@ -1,7 +1,7 @@
 /*
  *
  * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2011, Intel Corporation.
+ * Copyright (c) 2003-2012, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -362,11 +362,11 @@
 	host_start_req =
 	    (struct hbm_host_version_request *) &dev->wr_msg_buf[1];
 	memset(host_start_req, 0, sizeof(struct hbm_host_version_request));
-	host_start_req->cmd.cmd = HOST_START_REQ_CMD;
+	host_start_req->hbm_cmd = HOST_START_REQ_CMD;
 	host_start_req->host_version.major_version = HBM_MAJOR_VERSION;
 	host_start_req->host_version.minor_version = HBM_MINOR_VERSION;
 	dev->recvd_msg = false;
-	if (!mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req,
+	if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req,
 				       mei_hdr->length)) {
 		dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
 		dev->mei_state = MEI_RESETING;
@@ -398,8 +398,8 @@
 
 	host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1];
 	memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request));
-	host_enum_req->cmd.cmd = HOST_ENUM_REQ_CMD;
-	if (!mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req,
+	host_enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
+	if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req,
 				mei_hdr->length)) {
 		dev->mei_state = MEI_RESETING;
 		dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
@@ -407,7 +407,7 @@
 	}
 	dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE;
 	dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
-	return ;
+	return;
 }
 
 
@@ -482,10 +482,10 @@
 
 		memset(host_cli_req, 0, sizeof(struct hbm_props_request));
 
-		host_cli_req->cmd.cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
+		host_cli_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
 		host_cli_req->address = b;
 
-		if (!mei_write_message(dev, mei_header,
+		if (mei_write_message(dev, mei_header,
 				(unsigned char *)host_cli_req,
 				mei_header->length)) {
 			dev->mei_state = MEI_RESETING;
@@ -608,7 +608,7 @@
 
 	dev->iamthif_msg_buf = msg_buf;
 
-	if (!mei_connect(dev, &dev->iamthif_cl)) {
+	if (mei_connect(dev, &dev->iamthif_cl)) {
 		dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n");
 		dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
 		dev->iamthif_cl.host_client_id = 0;
@@ -670,14 +670,12 @@
 	if (dev->mei_host_buffer_is_empty) {
 		dev->mei_host_buffer_is_empty = false;
 		if (mei_disconnect(dev, cl)) {
-			mdelay(10); /* Wait for hardware disconnection ready */
-			list_add_tail(&cb->cb_list,
-				&dev->ctrl_rd_list.mei_cb.cb_list);
-		} else {
 			rets = -ENODEV;
 			dev_dbg(&dev->pdev->dev, "failed to call mei_disconnect.\n");
 			goto free;
 		}
+		mdelay(10); /* Wait for hardware disconnection ready */
+		list_add_tail(&cb->cb_list, &dev->ctrl_rd_list.mei_cb.cb_list);
 	} else {
 		dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n");
 		list_add_tail(&cb->cb_list,
diff --git a/drivers/staging/mei/interface.c b/drivers/staging/mei/interface.c
index eb5df7f..9a2cfaf 100644
--- a/drivers/staging/mei/interface.c
+++ b/drivers/staging/mei/interface.c
@@ -1,7 +1,7 @@
 /*
  *
  * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2011, Intel Corporation.
+ * Copyright (c) 2003-2012, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -125,7 +125,7 @@
  * @write_buffer: message buffer will be written
  * @write_length: message size will be written
  *
- * returns 1 if success, 0 - otherwise.
+ * This function returns -EIO if write has failed
  */
 int mei_write_message(struct mei_device *dev,
 		      struct mei_msg_hdr *header,
@@ -157,7 +157,7 @@
 	dw_to_write = ((write_length + 3) / 4);
 
 	if (dw_to_write > empty_slots)
-		return 0;
+		return -EIO;
 
 	mei_reg_write(dev, H_CB_WW, *((u32 *) header));
 
@@ -177,9 +177,9 @@
 	mei_hcsr_set(dev);
 	dev->me_hw_state = mei_mecsr_read(dev);
 	if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
-		return 0;
+		return -EIO;
 
-	return 1;
+	return 0;
 }
 
 /**
@@ -215,26 +215,17 @@
  * @buffer: message buffer will be written
  * @buffer_length: message size will be read
  */
-void mei_read_slots(struct mei_device *dev,
-		    unsigned char *buffer, unsigned long buffer_length)
+void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
+		    unsigned long buffer_length)
 {
-	u32 i = 0;
-	unsigned char temp_buf[sizeof(u32)];
+	u32 *reg_buf = (u32 *)buffer;
 
-	while (buffer_length >= sizeof(u32)) {
-		((u32 *) buffer)[i] = mei_mecbrw_read(dev);
-
-		dev_dbg(&dev->pdev->dev,
-				"buffer[%d]= %d\n",
-				i, ((u32 *) buffer)[i]);
-
-		i++;
-		buffer_length -= sizeof(u32);
-	}
+	for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32))
+		*reg_buf++ = mei_mecbrw_read(dev);
 
 	if (buffer_length > 0) {
-		*((u32 *) &temp_buf) = mei_mecbrw_read(dev);
-		memcpy(&buffer[i * 4], temp_buf, buffer_length);
+		u32 reg = mei_mecbrw_read(dev);
+		memcpy(reg_buf, &reg, buffer_length);
 	}
 
 	dev->host_hw_state |= H_IG;
@@ -284,7 +275,7 @@
  * @returns
  *	0 on success
  *	-ENOENT when me client is not found
- *	-EINVAL wehn ctrl credits are <= 0
+ *	-EINVAL when ctrl credits are <= 0
  */
 int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl)
 {
@@ -317,7 +308,7 @@
  * @dev: the device structure
  * @cl: private data of the file object
  *
- * returns 1 if success, 0 - otherwise.
+ * This function returns -EIO on write failure
  */
 int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl)
 {
@@ -335,18 +326,15 @@
 	memset(mei_flow_control, 0, sizeof(*mei_flow_control));
 	mei_flow_control->host_addr = cl->host_client_id;
 	mei_flow_control->me_addr = cl->me_client_id;
-	mei_flow_control->cmd.cmd = MEI_FLOW_CONTROL_CMD;
+	mei_flow_control->hbm_cmd = MEI_FLOW_CONTROL_CMD;
 	memset(mei_flow_control->reserved, 0,
 			sizeof(mei_flow_control->reserved));
 	dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
-	    cl->host_client_id, cl->me_client_id);
-	if (!mei_write_message(dev, mei_hdr,
+		cl->host_client_id, cl->me_client_id);
+
+	return mei_write_message(dev, mei_hdr,
 				(unsigned char *) mei_flow_control,
-				sizeof(struct hbm_flow_control)))
-		return 0;
-
-	return 1;
-
+				sizeof(struct hbm_flow_control));
 }
 
 /**
@@ -380,7 +368,7 @@
  * @dev: the device structure
  * @cl: private data of the file object
  *
- * returns 1 if success, 0 - otherwise.
+ * This function returns -EIO on write failure
  */
 int mei_disconnect(struct mei_device *dev, struct mei_cl *cl)
 {
@@ -399,15 +387,12 @@
 	memset(mei_cli_disconnect, 0, sizeof(*mei_cli_disconnect));
 	mei_cli_disconnect->host_addr = cl->host_client_id;
 	mei_cli_disconnect->me_addr = cl->me_client_id;
-	mei_cli_disconnect->cmd.cmd = CLIENT_DISCONNECT_REQ_CMD;
+	mei_cli_disconnect->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD;
 	mei_cli_disconnect->reserved[0] = 0;
 
-	if (!mei_write_message(dev, mei_hdr,
+	return mei_write_message(dev, mei_hdr,
 				(unsigned char *) mei_cli_disconnect,
-				sizeof(struct hbm_client_disconnect_request)))
-		return 0;
-
-	return 1;
+				sizeof(struct hbm_client_disconnect_request));
 }
 
 /**
@@ -416,7 +401,7 @@
  * @dev: the device structure
  * @cl: private data of the file object
  *
- * returns 1 if success, 0 - otherwise.
+ * This function returns -EIO on write failure
  */
 int mei_connect(struct mei_device *dev, struct mei_cl *cl)
 {
@@ -434,13 +419,10 @@
 	    (struct hbm_client_connect_request *) &dev->wr_msg_buf[1];
 	mei_cli_connect->host_addr = cl->host_client_id;
 	mei_cli_connect->me_addr = cl->me_client_id;
-	mei_cli_connect->cmd.cmd = CLIENT_CONNECT_REQ_CMD;
+	mei_cli_connect->hbm_cmd = CLIENT_CONNECT_REQ_CMD;
 	mei_cli_connect->reserved = 0;
 
-	if (!mei_write_message(dev, mei_hdr,
+	return mei_write_message(dev, mei_hdr,
 				(unsigned char *) mei_cli_connect,
-				sizeof(struct hbm_client_connect_request)))
-		return 0;
-
-	return 1;
+				sizeof(struct hbm_client_connect_request));
 }
diff --git a/drivers/staging/mei/interface.h b/drivers/staging/mei/interface.h
index aeae511..fb90c6f 100644
--- a/drivers/staging/mei/interface.h
+++ b/drivers/staging/mei/interface.h
@@ -1,7 +1,7 @@
 /*
  *
  * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2011, Intel Corporation.
+ * Copyright (c) 2003-2012, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -33,7 +33,8 @@
 
 
 void mei_read_slots(struct mei_device *dev,
-		     unsigned char *buffer, unsigned long buffer_length);
+		     unsigned char *buffer,
+		     unsigned long buffer_length);
 
 int mei_write_message(struct mei_device *dev,
 			     struct mei_msg_hdr *header,
@@ -59,7 +60,7 @@
  */
 void mei_watchdog_register(struct mei_device *dev);
 /*
- * mei_watchdog_unregister  - Uegistering watchdog interface
+ * mei_watchdog_unregister  - Unregistering watchdog interface
  * @dev - mei device
  */
 void mei_watchdog_unregister(struct mei_device *dev);
diff --git a/drivers/staging/mei/interrupt.c b/drivers/staging/mei/interrupt.c
index 3544fee..2007d24 100644
--- a/drivers/staging/mei/interrupt.c
+++ b/drivers/staging/mei/interrupt.c
@@ -1,7 +1,7 @@
 /*
  *
  * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2011, Intel Corporation.
+ * Copyright (c) 2003-2012, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -123,8 +123,7 @@
 	BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id);
 	BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING);
 
-	buffer = (unsigned char *) (dev->iamthif_msg_buf +
-			dev->iamthif_msg_buf_index);
+	buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index;
 	BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length);
 
 	mei_read_slots(dev, buffer, mei_hdr->length);
@@ -206,9 +205,7 @@
 		cl = (struct mei_cl *)cb_pos->file_private;
 		if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) {
 			cl->reading_state = MEI_READING;
-			buffer = (unsigned char *)
-				(cb_pos->response_buffer.data +
-				cb_pos->information);
+			buffer = cb_pos->response_buffer.data + cb_pos->information;
 
 			if (cb_pos->response_buffer.size <
 					mei_hdr->length + cb_pos->information) {
@@ -247,8 +244,7 @@
 quit:
 	dev_dbg(&dev->pdev->dev, "message read\n");
 	if (!buffer) {
-		mei_read_slots(dev, (unsigned char *) dev->rd_msg_buf,
-						mei_hdr->length);
+		mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
 		dev_dbg(&dev->pdev->dev, "discarding message, header =%08x.\n",
 				*(u32 *) dev->rd_msg_buf);
 	}
@@ -267,26 +263,25 @@
 static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots)
 {
 
-	if (((*slots) * sizeof(u32)) >= (sizeof(struct mei_msg_hdr)
+	if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr)
 			+ sizeof(struct hbm_flow_control))) {
-		*slots -= (sizeof(struct mei_msg_hdr) +
-				sizeof(struct hbm_flow_control) + 3) / 4;
-		if (!mei_send_flow_control(dev, &dev->iamthif_cl)) {
-			dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
-		} else {
-			dev_dbg(&dev->pdev->dev, "iamthif flow control success\n");
-			dev->iamthif_state = MEI_IAMTHIF_READING;
-			dev->iamthif_flow_control_pending = false;
-			dev->iamthif_msg_buf_index = 0;
-			dev->iamthif_msg_buf_size = 0;
-			dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER;
-			dev->mei_host_buffer_is_empty =
-					mei_host_buffer_is_empty(dev);
-		}
-		return 0;
-	} else {
 		return -EMSGSIZE;
 	}
+	*slots -= (sizeof(struct mei_msg_hdr) +
+				sizeof(struct hbm_flow_control) + 3) / 4;
+	if (mei_send_flow_control(dev, &dev->iamthif_cl)) {
+		dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
+		return -EIO;
+	}
+
+	dev_dbg(&dev->pdev->dev, "iamthif flow control success\n");
+	dev->iamthif_state = MEI_IAMTHIF_READING;
+	dev->iamthif_flow_control_pending = false;
+	dev->iamthif_msg_buf_index = 0;
+	dev->iamthif_msg_buf_size = 0;
+	dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER;
+	dev->mei_host_buffer_is_empty = mei_host_buffer_is_empty(dev);
+	return 0;
 }
 
 /**
@@ -310,7 +305,7 @@
 		*slots -= (sizeof(struct mei_msg_hdr) +
 			sizeof(struct hbm_client_disconnect_request) + 3) / 4;
 
-		if (!mei_disconnect(dev, cl)) {
+		if (mei_disconnect(dev, cl)) {
 			cl->status = 0;
 			cb_pos->information = 0;
 			list_move_tail(&cb_pos->cb_list,
@@ -601,8 +596,7 @@
 				&dev->ext_msg_buf[1];
 			disconnect_res->host_addr = cl_pos->host_client_id;
 			disconnect_res->me_addr = cl_pos->me_client_id;
-			*(u8 *) (&disconnect_res->cmd) =
-				CLIENT_DISCONNECT_RES_CMD;
+			disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD;
 			disconnect_res->status = 0;
 			dev->extra_write_index = 2;
 			break;
@@ -632,15 +626,13 @@
 	struct hbm_host_stop_request *host_stop_req;
 	int res;
 
-	unsigned char *buffer;
 
 	/* read the message to our buffer */
-	buffer = (unsigned char *) dev->rd_msg_buf;
 	BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf));
-	mei_read_slots(dev, buffer, mei_hdr->length);
-	mei_msg = (struct mei_bus_message *) buffer;
+	mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
+	mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
 
-	switch (*(u8 *) mei_msg) {
+	switch (mei_msg->hbm_cmd) {
 	case HOST_START_RES_CMD:
 		version_res = (struct hbm_host_version_response *) mei_msg;
 		if (version_res->host_version_supported) {
@@ -659,6 +651,7 @@
 		} else {
 			dev->version = version_res->me_max_version;
 			/* send stop message */
+			mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0];
 			mei_hdr->host_addr = 0;
 			mei_hdr->me_addr = 0;
 			mei_hdr->length = sizeof(struct hbm_host_stop_request);
@@ -671,7 +664,7 @@
 			memset(host_stop_req,
 					0,
 					sizeof(struct hbm_host_stop_request));
-			host_stop_req->cmd.cmd = HOST_STOP_REQ_CMD;
+			host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
 			host_stop_req->reason = DRIVER_STOP_REQUEST;
 			mei_write_message(dev, mei_hdr,
 					   (unsigned char *) (host_stop_req),
@@ -725,7 +718,7 @@
 				dev->me_client_index++;
 				dev->me_client_presentation_num++;
 
-				/** Send Client Propeties request **/
+				/** Send Client Properties request **/
 				res = mei_host_client_properties(dev);
 				if (res < 0) {
 					dev_dbg(&dev->pdev->dev, "mei_host_client_properties() failed");
@@ -811,7 +804,7 @@
 		host_stop_req =
 			(struct hbm_host_stop_request *) &dev->ext_msg_buf[1];
 		memset(host_stop_req, 0, sizeof(struct hbm_host_stop_request));
-		host_stop_req->cmd.cmd = HOST_STOP_REQ_CMD;
+		host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
 		host_stop_req->reason = DRIVER_STOP_REQUEST;
 		host_stop_req->reserved[0] = 0;
 		host_stop_req->reserved[1] = 0;
@@ -844,24 +837,21 @@
 {
 	if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
 			sizeof(struct hbm_flow_control))) {
-		*slots -= (sizeof(struct mei_msg_hdr) +
-			sizeof(struct hbm_flow_control) + 3) / 4;
-		if (!mei_send_flow_control(dev, cl)) {
-			cl->status = -ENODEV;
-			cb_pos->information = 0;
-			list_move_tail(&cb_pos->cb_list,
-					&cmpl_list->mei_cb.cb_list);
-			return -ENODEV;
-		} else {
-			list_move_tail(&cb_pos->cb_list,
-					&dev->read_list.mei_cb.cb_list);
-		}
-	} else {
 		/* return the cancel routine */
 		list_del(&cb_pos->cb_list);
 		return -EBADMSG;
 	}
 
+	*slots -= (sizeof(struct mei_msg_hdr) +
+			sizeof(struct hbm_flow_control) + 3) / 4;
+	if (mei_send_flow_control(dev, cl)) {
+		cl->status = -ENODEV;
+		cb_pos->information = 0;
+		list_move_tail(&cb_pos->cb_list, &cmpl_list->mei_cb.cb_list);
+		return -ENODEV;
+	}
+	list_move_tail(&cb_pos->cb_list, &dev->read_list.mei_cb.cb_list);
+
 	return 0;
 }
 
@@ -887,7 +877,7 @@
 		cl->state = MEI_FILE_CONNECTING;
 		*slots -= (sizeof(struct mei_msg_hdr) +
 			sizeof(struct hbm_client_connect_request) + 3) / 4;
-		if (!mei_connect(dev, cl)) {
+		if (mei_connect(dev, cl)) {
 			cl->status = -ENODEV;
 			cb_pos->information = 0;
 			list_del(&cb_pos->cb_list);
@@ -944,7 +934,7 @@
 				mei_hdr->length);
 		*slots -= (sizeof(struct mei_msg_hdr) +
 				mei_hdr->length + 3) / 4;
-		if (!mei_write_message(dev, mei_hdr,
+		if (mei_write_message(dev, mei_hdr,
 				(unsigned char *)
 				(cb_pos->request_buffer.data +
 				cb_pos->information),
@@ -973,7 +963,7 @@
 
 		(*slots) -= (sizeof(struct mei_msg_hdr) +
 				mei_hdr->length + 3) / 4;
-		if (!mei_write_message(dev, mei_hdr,
+		if (mei_write_message(dev, mei_hdr,
 					(unsigned char *)
 					(cb_pos->request_buffer.data +
 					cb_pos->information),
@@ -1034,7 +1024,7 @@
 		*slots -= (sizeof(struct mei_msg_hdr) +
 				mei_hdr->length + 3) / 4;
 
-		if (!mei_write_message(dev, mei_hdr,
+		if (mei_write_message(dev, mei_hdr,
 					(dev->iamthif_msg_buf +
 					dev->iamthif_msg_buf_index),
 					mei_hdr->length)) {
@@ -1069,7 +1059,7 @@
 		*slots -= (sizeof(struct mei_msg_hdr) +
 				mei_hdr->length + 3) / 4;
 
-		if (!mei_write_message(dev, mei_hdr,
+		if (mei_write_message(dev, mei_hdr,
 					(dev->iamthif_msg_buf +
 					dev->iamthif_msg_buf_index),
 					mei_hdr->length)) {
@@ -1286,7 +1276,7 @@
 		}
 	}
 	if (dev->stop)
-		return ~ENODEV;
+		return -ENODEV;
 
 	/* complete control write list CB */
 	dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
@@ -1423,7 +1413,7 @@
 
 	if (dev->iamthif_stall_timer) {
 		if (--dev->iamthif_stall_timer == 0) {
-			dev_dbg(&dev->pdev->dev, "reseting because of hang to amthi.\n");
+			dev_dbg(&dev->pdev->dev, "resetting because of hang to amthi.\n");
 			mei_reset(dev, 1);
 			dev->iamthif_msg_buf_size = 0;
 			dev->iamthif_msg_buf_index = 0;
@@ -1513,7 +1503,7 @@
 	dev->host_hw_state = mei_hcsr_read(dev);
 
 	/* Ack the interrupt here
-	 * In case of MSI we don't go throuhg the quick handler */
+	 * In case of MSI we don't go through the quick handler */
 	if (pci_dev_msi_enabled(dev->pdev))
 		mei_reg_write(dev, H_CSR, dev->host_hw_state);
 
@@ -1549,7 +1539,7 @@
 			return IRQ_HANDLED;
 		}
 	}
-	/* check slots avalable for reading */
+	/* check slots available for reading */
 	slots = mei_count_full_read_slots(dev);
 	dev_dbg(&dev->pdev->dev, "slots =%08x  extra_write_index =%08x.\n",
 		slots, dev->extra_write_index);
diff --git a/drivers/staging/mei/iorw.c b/drivers/staging/mei/iorw.c
index 0752ead..0a80dc4 100644
--- a/drivers/staging/mei/iorw.c
+++ b/drivers/staging/mei/iorw.c
@@ -1,7 +1,7 @@
 /*
  *
  * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2011, Intel Corporation.
+ * Copyright (c) 2003-2012, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -37,7 +37,6 @@
 #include "hw.h"
 #include "mei.h"
 #include "interface.h"
-#include "mei_version.h"
 
 
 
@@ -109,8 +108,8 @@
 	dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n",
 			dev->me_clients[i].props.max_msg_length);
 
-	/* if we're connecting to amthi client so we will use the exist
-	 * connection
+	/* if we're connecting to amthi client then we will use the
+	 * existing connection
 	 */
 	if (uuid_le_cmp(data->in_client_uuid, mei_amthi_guid) == 0) {
 		dev_dbg(&dev->pdev->dev, "FW Client is amthi\n");
@@ -162,7 +161,7 @@
 	    && !mei_other_client_is_connecting(dev, cl)) {
 		dev_dbg(&dev->pdev->dev, "Sending Connect Message\n");
 		dev->mei_host_buffer_is_empty = false;
-		if (!mei_connect(dev, cl)) {
+		if (mei_connect(dev, cl)) {
 			dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n");
 			rets = -ENODEV;
 			goto end;
@@ -434,13 +433,11 @@
 	cl->read_cb = cb;
 	if (dev->mei_host_buffer_is_empty) {
 		dev->mei_host_buffer_is_empty = false;
-		if (!mei_send_flow_control(dev, cl)) {
+		if (mei_send_flow_control(dev, cl)) {
 			rets = -ENODEV;
 			goto unlock;
-		} else {
-			list_add_tail(&cb->cb_list,
-				      &dev->read_list.mei_cb.cb_list);
 		}
+		list_add_tail(&cb->cb_list, &dev->read_list.mei_cb.cb_list);
 	} else {
 		list_add_tail(&cb->cb_list, &dev->ctrl_wr_list.mei_cb.cb_list);
 	}
@@ -500,7 +497,7 @@
 		mei_hdr.me_addr = dev->iamthif_cl.me_client_id;
 		mei_hdr.reserved = 0;
 		dev->iamthif_msg_buf_index += mei_hdr.length;
-		if (!mei_write_message(dev, &mei_hdr,
+		if (mei_write_message(dev, &mei_hdr,
 					(unsigned char *)(dev->iamthif_msg_buf),
 					mei_hdr.length))
 			return -ENODEV;
diff --git a/drivers/staging/mei/main.c b/drivers/staging/mei/main.c
index 1e1a9f9..7c9321f 100644
--- a/drivers/staging/mei/main.c
+++ b/drivers/staging/mei/main.c
@@ -1,7 +1,7 @@
 /*
  *
  * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2011, Intel Corporation.
+ * Copyright (c) 2003-2012, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -38,7 +38,6 @@
 #include "mei_dev.h"
 #include "mei.h"
 #include "interface.h"
-#include "mei_version.h"
 
 
 #define MEI_READ_TIMEOUT 45
@@ -50,7 +49,6 @@
  */
 static char mei_driver_name[] = MEI_DRIVER_NAME;
 static const char mei_driver_string[] = "Intel(R) Management Engine Interface";
-static const char mei_driver_version[] = MEI_DRIVER_VERSION;
 
 /* The device pointer */
 /* Currently this driver works as long as there is only a single AMT device. */
@@ -430,7 +428,7 @@
 		goto free;
 	} else if ((!cl->read_cb || !cl->read_cb->information) &&
 		    *offset > 0) {
-		/*Offset needs to be cleaned for contingous reads*/
+		/*Offset needs to be cleaned for contiguous reads*/
 		*offset = 0;
 		rets = 0;
 		goto out;
@@ -493,7 +491,7 @@
 		goto free;
 	}
 
-	/* length is being turncated to PAGE_SIZE, however, */
+	/* length is being truncated to PAGE_SIZE, however, */
 	/* information size may be longer */
 	length = min_t(size_t, length, (cb->information - *offset));
 
@@ -740,7 +738,7 @@
 		mei_hdr.reserved = 0;
 		dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n",
 		    *((u32 *) &mei_hdr));
-		if (!mei_write_message(dev, &mei_hdr,
+		if (mei_write_message(dev, &mei_hdr,
 			(unsigned char *) (write_cb->request_buffer.data),
 			mei_hdr.length)) {
 			rets = -ENODEV;
@@ -1206,8 +1204,7 @@
 {
 	int ret;
 
-	pr_debug("mei: %s - version %s\n",
-		mei_driver_string, mei_driver_version);
+	pr_debug("mei: %s\n", mei_driver_string);
 	/* init pci module */
 	ret = pci_register_driver(&mei_driver);
 	if (ret < 0)
@@ -1238,4 +1235,3 @@
 MODULE_AUTHOR("Intel Corporation");
 MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
 MODULE_LICENSE("GPL v2");
-MODULE_VERSION(MEI_DRIVER_VERSION);
diff --git a/drivers/staging/mei/mei-amt-version.c b/drivers/staging/mei/mei-amt-version.c
new file mode 100644
index 0000000..ac2a507
--- /dev/null
+++ b/drivers/staging/mei/mei-amt-version.c
@@ -0,0 +1,481 @@
+/******************************************************************************
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Intel MEI Interface Header
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *	Intel Corporation.
+ *	linux-mei@linux.intel.com
+ *	http://www.intel.com
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <bits/wordsize.h>
+#include "mei.h"
+
+/*****************************************************************************
+ * Intel Management Engine Interface
+ *****************************************************************************/
+
+#define mei_msg(_me, fmt, ARGS...) do {         \
+	if (_me->verbose)                       \
+		fprintf(stderr, fmt, ##ARGS);	\
+} while (0)
+
+#define mei_err(_me, fmt, ARGS...) do {         \
+	fprintf(stderr, "Error: " fmt, ##ARGS); \
+} while (0)
+
+struct mei {
+	uuid_le guid;
+	bool initialized;
+	bool verbose;
+	unsigned int buf_size;
+	unsigned char prot_ver;
+	int fd;
+};
+
+static void mei_deinit(struct mei *cl)
+{
+	if (cl->fd != -1)
+		close(cl->fd);
+	cl->fd = -1;
+	cl->buf_size = 0;
+	cl->prot_ver = 0;
+	cl->initialized = false;
+}
+
+static bool mei_init(struct mei *me, const uuid_le *guid,
+		unsigned char req_protocol_version, bool verbose)
+{
+	int result;
+	struct mei_client *cl;
+	struct mei_connect_client_data data;
+
+	mei_deinit(me);
+
+	me->verbose = verbose;
+
+	me->fd = open("/dev/mei", O_RDWR);
+	if (me->fd == -1) {
+		mei_err(me, "Cannot establish a handle to the Intel MEI driver\n");
+		goto err;
+	}
+	memcpy(&me->guid, guid, sizeof(*guid));
+	memset(&data, 0, sizeof(data));
+	me->initialized = true;
+
+	memcpy(&data.in_client_uuid, &me->guid, sizeof(me->guid));
+	result = ioctl(me->fd, IOCTL_MEI_CONNECT_CLIENT, &data);
+	if (result) {
+		mei_err(me, "IOCTL_MEI_CONNECT_CLIENT receive message. err=%d\n", result);
+		goto err;
+	}
+	cl = &data.out_client_properties;
+	mei_msg(me, "max_message_length %d\n", cl->max_msg_length);
+	mei_msg(me, "protocol_version %d\n", cl->protocol_version);
+
+	if ((req_protocol_version > 0) &&
+	     (cl->protocol_version != req_protocol_version)) {
+		mei_err(me, "Intel MEI protocol version not supported\n");
+		goto err;
+	}
+
+	me->buf_size = cl->max_msg_length;
+	me->prot_ver = cl->protocol_version;
+
+	return true;
+err:
+	mei_deinit(me);
+	return false;
+}
+
+static ssize_t mei_recv_msg(struct mei *me, unsigned char *buffer,
+			ssize_t len, unsigned long timeout)
+{
+	ssize_t rc;
+
+	mei_msg(me, "call read length = %zd\n", len);
+
+	rc = read(me->fd, buffer, len);
+	if (rc < 0) {
+		mei_err(me, "read failed with status %zd %s\n",
+				rc, strerror(errno));
+		mei_deinit(me);
+	} else {
+		mei_msg(me, "read succeeded with result %zd\n", rc);
+	}
+	return rc;
+}
+
+static ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer,
+			ssize_t len, unsigned long timeout)
+{
+	struct timeval tv;
+	ssize_t written;
+	ssize_t rc;
+	fd_set set;
+
+	tv.tv_sec = timeout / 1000;
+	tv.tv_usec = (timeout % 1000) * 1000000;
+
+	mei_msg(me, "call write length = %zd\n", len);
+
+	written = write(me->fd, buffer, len);
+	if (written < 0) {
+		rc = -errno;
+		mei_err(me, "write failed with status %zd %s\n",
+			written, strerror(errno));
+		goto out;
+	}
+
+	FD_ZERO(&set);
+	FD_SET(me->fd, &set);
+	rc = select(me->fd + 1 , &set, NULL, NULL, &tv);
+	if (rc > 0 && FD_ISSET(me->fd, &set)) {
+		mei_msg(me, "write success\n");
+	} else if (rc == 0) {
+		mei_err(me, "write failed on timeout with status\n");
+		goto out;
+	} else { /* rc < 0 */
+		mei_err(me, "write failed on select with status %zd\n", rc);
+		goto out;
+	}
+
+	rc = written;
+out:
+	if (rc < 0)
+		mei_deinit(me);
+
+	return rc;
+}
+
+/***************************************************************************
+ * Intel Advanced Management Technolgy ME Client
+ ***************************************************************************/
+
+#define AMT_MAJOR_VERSION 1
+#define AMT_MINOR_VERSION 1
+
+#define AMT_STATUS_SUCCESS                0x0
+#define AMT_STATUS_INTERNAL_ERROR         0x1
+#define AMT_STATUS_NOT_READY              0x2
+#define AMT_STATUS_INVALID_AMT_MODE       0x3
+#define AMT_STATUS_INVALID_MESSAGE_LENGTH 0x4
+
+#define AMT_STATUS_HOST_IF_EMPTY_RESPONSE  0x4000
+#define AMT_STATUS_SDK_RESOURCES      0x1004
+
+
+#define AMT_BIOS_VERSION_LEN   65
+#define AMT_VERSIONS_NUMBER    50
+#define AMT_UNICODE_STRING_LEN 20
+
+struct amt_unicode_string {
+	uint16_t length;
+	char string[AMT_UNICODE_STRING_LEN];
+} __attribute__((packed));
+
+struct amt_version_type {
+	struct amt_unicode_string description;
+	struct amt_unicode_string version;
+} __attribute__((packed));
+
+struct amt_version {
+	uint8_t major;
+	uint8_t minor;
+} __attribute__((packed));
+
+struct amt_code_versions {
+	uint8_t bios[AMT_BIOS_VERSION_LEN];
+	uint32_t count;
+	struct amt_version_type versions[AMT_VERSIONS_NUMBER];
+} __attribute__((packed));
+
+/***************************************************************************
+ * Intel Advanced Management Technolgy Host Interface
+ ***************************************************************************/
+
+struct amt_host_if_msg_header {
+	struct amt_version version;
+	uint16_t _reserved;
+	uint32_t command;
+	uint32_t length;
+} __attribute__((packed));
+
+struct amt_host_if_resp_header {
+	struct amt_host_if_msg_header header;
+	uint32_t status;
+	unsigned char data[0];
+} __attribute__((packed));
+
+const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,  \
+				0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c);
+
+#define AMT_HOST_IF_CODE_VERSIONS_REQUEST  0x0400001A
+#define AMT_HOST_IF_CODE_VERSIONS_RESPONSE 0x0480001A
+
+const struct amt_host_if_msg_header CODE_VERSION_REQ = {
+	.version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
+	._reserved = 0,
+	.command = AMT_HOST_IF_CODE_VERSIONS_REQUEST,
+	.length = 0
+};
+
+
+struct amt_host_if {
+	struct mei mei_cl;
+	unsigned long send_timeout;
+	bool initialized;
+};
+
+
+static bool amt_host_if_init(struct amt_host_if *acmd,
+		      unsigned long send_timeout, bool verbose)
+{
+	acmd->send_timeout = (send_timeout) ? send_timeout : 20000;
+	acmd->initialized = mei_init(&acmd->mei_cl, &MEI_IAMTHIF, 0, verbose);
+	return acmd->initialized;
+}
+
+static void amt_host_if_deinit(struct amt_host_if *acmd)
+{
+	mei_deinit(&acmd->mei_cl);
+	acmd->initialized = false;
+}
+
+static uint32_t amt_verify_code_versions(const struct amt_host_if_resp_header *resp)
+{
+	uint32_t status = AMT_STATUS_SUCCESS;
+	struct amt_code_versions *code_ver;
+	size_t code_ver_len;
+	uint32_t ver_type_cnt;
+	uint32_t len;
+	uint32_t i;
+
+	code_ver = (struct amt_code_versions *)resp->data;
+	/* length - sizeof(status) */
+	code_ver_len = resp->header.length - sizeof(uint32_t);
+	ver_type_cnt = code_ver_len -
+			sizeof(code_ver->bios) -
+			sizeof(code_ver->count);
+	if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) {
+		status = AMT_STATUS_INTERNAL_ERROR;
+		goto out;
+	}
+
+	for (i = 0; i < code_ver->count; i++) {
+		len = code_ver->versions[i].description.length;
+
+		if (len > AMT_UNICODE_STRING_LEN) {
+			status = AMT_STATUS_INTERNAL_ERROR;
+			goto out;
+		}
+
+		len = code_ver->versions[i].version.length;
+		if (code_ver->versions[i].version.string[len] != '\0' ||
+		    len != strlen(code_ver->versions[i].version.string)) {
+			status = AMT_STATUS_INTERNAL_ERROR;
+			goto out;
+		}
+	}
+out:
+	return status;
+}
+
+static uint32_t amt_verify_response_header(uint32_t command,
+				const struct amt_host_if_msg_header *resp_hdr,
+				uint32_t response_size)
+{
+	if (response_size < sizeof(struct amt_host_if_resp_header)) {
+		return AMT_STATUS_INTERNAL_ERROR;
+	} else if (response_size != (resp_hdr->length +
+				sizeof(struct amt_host_if_msg_header))) {
+		return AMT_STATUS_INTERNAL_ERROR;
+	} else if (resp_hdr->command != command) {
+		return AMT_STATUS_INTERNAL_ERROR;
+	} else if (resp_hdr->_reserved != 0) {
+		return AMT_STATUS_INTERNAL_ERROR;
+	} else if (resp_hdr->version.major != AMT_MAJOR_VERSION ||
+		   resp_hdr->version.minor < AMT_MINOR_VERSION) {
+		return AMT_STATUS_INTERNAL_ERROR;
+	}
+	return AMT_STATUS_SUCCESS;
+}
+
+static uint32_t amt_host_if_call(struct amt_host_if *acmd,
+			const unsigned char *command, ssize_t command_sz,
+			uint8_t **read_buf, uint32_t rcmd,
+			unsigned int expected_sz)
+{
+	uint32_t in_buf_sz;
+	uint32_t out_buf_sz;
+	ssize_t written;
+	uint32_t status;
+	struct amt_host_if_resp_header *msg_hdr;
+
+	in_buf_sz = acmd->mei_cl.buf_size;
+	*read_buf = (uint8_t *)malloc(sizeof(uint8_t) * in_buf_sz);
+	if (*read_buf == NULL)
+		return AMT_STATUS_SDK_RESOURCES;
+	memset(*read_buf, 0, in_buf_sz);
+	msg_hdr = (struct amt_host_if_resp_header *)*read_buf;
+
+	written = mei_send_msg(&acmd->mei_cl,
+				command, command_sz, acmd->send_timeout);
+	if (written != command_sz)
+		return AMT_STATUS_INTERNAL_ERROR;
+
+	out_buf_sz = mei_recv_msg(&acmd->mei_cl, *read_buf, in_buf_sz, 2000);
+	if (out_buf_sz <= 0)
+		return AMT_STATUS_HOST_IF_EMPTY_RESPONSE;
+
+	status = msg_hdr->status;
+	if (status != AMT_STATUS_SUCCESS)
+		return status;
+
+	status = amt_verify_response_header(rcmd,
+				&msg_hdr->header, out_buf_sz);
+	if (status != AMT_STATUS_SUCCESS)
+		return status;
+
+	if (expected_sz && expected_sz != out_buf_sz)
+		return AMT_STATUS_INTERNAL_ERROR;
+
+	return AMT_STATUS_SUCCESS;
+}
+
+
+static uint32_t amt_get_code_versions(struct amt_host_if *cmd,
+			       struct amt_code_versions *versions)
+{
+	struct amt_host_if_resp_header *response = NULL;
+	uint32_t status;
+
+	status = amt_host_if_call(cmd,
+			(const unsigned char *)&CODE_VERSION_REQ,
+			sizeof(CODE_VERSION_REQ),
+			(uint8_t **)&response,
+			AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0);
+
+	if (status != AMT_STATUS_SUCCESS)
+		goto out;
+
+	status = amt_verify_code_versions(response);
+	if (status != AMT_STATUS_SUCCESS)
+		goto out;
+
+	memcpy(versions, response->data, sizeof(struct amt_code_versions));
+out:
+	if (response != NULL)
+		free(response);
+
+	return status;
+}
+
+/************************** end of amt_host_if_command ***********************/
+int main(int argc, char **argv)
+{
+	struct amt_code_versions ver;
+	struct amt_host_if acmd;
+	unsigned int i;
+	uint32_t status;
+	int ret;
+	bool verbose;
+
+	verbose = (argc > 1 && strcmp(argv[1], "-v") == 0);
+
+	if (!amt_host_if_init(&acmd, 5000, verbose)) {
+		ret = 1;
+		goto out;
+	}
+
+	status = amt_get_code_versions(&acmd, &ver);
+
+	amt_host_if_deinit(&acmd);
+
+	switch (status) {
+	case AMT_STATUS_HOST_IF_EMPTY_RESPONSE:
+		printf("Intel AMT: DISABLED\n");
+		ret = 0;
+		break;
+	case AMT_STATUS_SUCCESS:
+		printf("Intel AMT: ENABLED\n");
+		for (i = 0; i < ver.count; i++) {
+			printf("%s:\t%s\n", ver.versions[i].description.string,
+				ver.versions[i].version.string);
+		}
+		ret = 0;
+		break;
+	default:
+		printf("An error has occurred\n");
+		ret = 1;
+		break;
+	}
+
+out:
+	return ret;
+}
diff --git a/drivers/staging/mei/mei.h b/drivers/staging/mei/mei.h
index 6da7c4f..bc0d8b6 100644
--- a/drivers/staging/mei/mei.h
+++ b/drivers/staging/mei/mei.h
@@ -1,63 +1,68 @@
-/*
-
-  Intel Management Engine Interface (Intel MEI) Linux driver
-  Intel MEI Interface Header
-
-  This file is provided under a dual BSD/GPLv2 license.  When using or
-  redistributing this file, you may do so under either license.
-
-  GPL LICENSE SUMMARY
-
-  Copyright(c) 2003-2011 Intel Corporation. All rights reserved.
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of version 2 of the GNU General Public License as
-  published by the Free Software Foundation.
-
-  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.
-
-  Contact Information:
-	  Intel Corporation.
-	  linux-mei@linux.intel.com
-	  http://www.intel.com
-
-
-  BSD LICENSE
-
-  Copyright(c) 2003-2011 Intel Corporation. All rights reserved.
-  All rights reserved.
-
-  Redistribution and use in source and binary forms, with or without
-  modification, are permitted provided that the following conditions
-  are met:
-
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in
-      the documentation and/or other materials provided with the
-      distribution.
-    * Neither the name of Intel Corporation nor the names of its
-      contributors may be used to endorse or promote products derived
-      from this software without specific prior written permission.
-
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
+/******************************************************************************
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Intel MEI Interface Header
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *	Intel Corporation.
+ *	linux-mei@linux.intel.com
+ *	http://www.intel.com
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
 
 #ifndef _LINUX_MEI_H
 #define _LINUX_MEI_H
@@ -72,7 +77,7 @@
  * Only in close() (file_operation release()) the communication between
  * the clients is disconnected
  *
- * The IOCTL argument is a struct with a union the contains
+ * The IOCTL argument is a struct with a union that contains
  * the input parameter and the output parameter for this IOCTL.
  *
  * The input parameter is UUID of the FW Client.
diff --git a/drivers/staging/mei/mei.txt b/drivers/staging/mei/mei.txt
index 516bfe7..2785697 100644
--- a/drivers/staging/mei/mei.txt
+++ b/drivers/staging/mei/mei.txt
@@ -4,7 +4,7 @@
 Introduction
 =======================
 
-The Intel Management Engine (Intel ME) is an isolated andprotected computing
+The Intel Management Engine (Intel ME) is an isolated and protected computing
 resource (Co-processor) residing inside certain Intel chipsets. The Intel ME
 provides support for computer/IT management features. The feature set
 depends on the Intel chipset SKU.
@@ -176,8 +176,8 @@
 =============================
 The Intel AMT Watchdog is an OS Health (Hang/Crash) watchdog.
 Whenever the OS hangs or crashes, Intel AMT will send an event
-to any subsciber to this event. This mechanism means that
-IT knows when a platform crashes even when there is a hard failureon the host.
+to any subscriber to this event. This mechanism means that
+IT knows when a platform crashes even when there is a hard failure on the host.
 
 The Intel AMT Watchdog is composed of two parts:
 	1) Firmware feature - receives the heartbeats
diff --git a/drivers/staging/mei/mei_dev.h b/drivers/staging/mei/mei_dev.h
index 82bacfc..10b1b4e 100644
--- a/drivers/staging/mei/mei_dev.h
+++ b/drivers/staging/mei/mei_dev.h
@@ -1,7 +1,7 @@
 /*
  *
  * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2011, Intel Corporation.
+ * Copyright (c) 2003-2012, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -30,6 +30,8 @@
 #define MEI_WD_PARAMS_SIZE             4
 #define MEI_WD_STATE_INDEPENDENCE_MSG_SENT       (1 << 0)
 
+#define MEI_RD_MSG_BUF_SIZE           (128 * sizeof(u32))
+
 /*
  * MEI PCI Device object
  */
@@ -87,7 +89,7 @@
 	MEI_POWER_UP
 };
 
-/* init clients  states*/
+/* init clients states*/
 enum mei_init_clients_states {
 	MEI_START_MESSAGE = 0,
 	MEI_ENUM_CLIENTS_MESSAGE,
@@ -125,7 +127,7 @@
  */
 struct mei_message_data {
 	u32 size;
-	char *data;
+	unsigned char *data;
 } __packed;
 
 
@@ -219,7 +221,7 @@
 	bool need_reset;
 
 	u32 extra_write_index;
-	u32 rd_msg_buf[128];	/* used for control messages */
+	unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE];	/* control messages */
 	u32 wr_msg_buf[128];	/* used for control messages */
 	u32 ext_msg_buf[8];	/* for control responses */
 	u32 rd_msg_hdr;
diff --git a/drivers/staging/mei/mei_version.h b/drivers/staging/mei/mei_version.h
deleted file mode 100644
index 075bad8..0000000
--- a/drivers/staging/mei/mei_version.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2011, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- */
-
-
-#ifndef MEI_VERSION_H
-#define MEI_VERSION_H
-
-#define MAJOR_VERSION		7
-#define MINOR_VERSION		1
-#define QUICK_FIX_NUMBER	20
-#define VER_BUILD		1
-
-#define MEI_DRV_VER1 __stringify(MAJOR_VERSION) "." __stringify(MINOR_VERSION)
-#define MEI_DRV_VER2 __stringify(QUICK_FIX_NUMBER) "." __stringify(VER_BUILD)
-
-#define MEI_DRIVER_VERSION	MEI_DRV_VER1 "." MEI_DRV_VER2
-
-#endif
diff --git a/drivers/staging/mei/wd.c b/drivers/staging/mei/wd.c
index 8094941..a6910da 100644
--- a/drivers/staging/mei/wd.c
+++ b/drivers/staging/mei/wd.c
@@ -1,7 +1,7 @@
 /*
  *
  * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2011, Intel Corporation.
+ * Copyright (c) 2003-2012, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -74,7 +74,7 @@
 
 	dev_dbg(&dev->pdev->dev, "check wd_cl\n");
 	if (MEI_FILE_CONNECTING == dev->wd_cl.state) {
-		if (!mei_connect(dev, &dev->wd_cl)) {
+		if (mei_connect(dev, &dev->wd_cl)) {
 			dev_dbg(&dev->pdev->dev, "Failed to connect to WD client\n");
 			dev->wd_cl.state = MEI_FILE_DISCONNECTED;
 			dev->wd_cl.host_client_id = 0;
@@ -119,9 +119,7 @@
 	else
 		return -EINVAL;
 
-	if (mei_write_message(dev, mei_hdr, dev->wd_data, mei_hdr->length))
-		return 0;
-	return -EIO;
+	return mei_write_message(dev, mei_hdr, dev->wd_data, mei_hdr->length);
 }
 
 /**
diff --git a/drivers/staging/nvec/Kconfig b/drivers/staging/nvec/Kconfig
index 86a8b8c..731301f 100644
--- a/drivers/staging/nvec/Kconfig
+++ b/drivers/staging/nvec/Kconfig
@@ -7,21 +7,21 @@
 
 config KEYBOARD_NVEC
 	bool "Keyboard on nVidia compliant EC"
-	depends on MFD_NVEC && INPUT=y
+	depends on MFD_NVEC && INPUT
 	help
 	  Say Y here to enable support for a keyboard connected to 
 	  a nVidia compliant embedded controller.
 
 config SERIO_NVEC_PS2
 	bool "PS2 on nVidia EC"
-	depends on MFD_NVEC && MOUSE_PS2
+	depends on MFD_NVEC && SERIO
 	help
 	  Say Y here to enable support for a Touchpad / Mouse connected
 	  to a nVidia compliant embedded controller.
 
 config NVEC_POWER
 	bool "NVEC charger and battery"
-	depends on MFD_NVEC && POWER_SUPPLY=y
+	depends on MFD_NVEC && POWER_SUPPLY
 	help
 	  Say Y to enable support for battery and charger interface for
 	  nVidia compliant embedded controllers.
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index fafdfa2..3c60088 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -49,7 +49,7 @@
 #define I2C_CNFG_DEBOUNCE_CNT_SHIFT	12
 
 #define I2C_SL_CNFG		0x20
-#define I2C_SL_NEWL		(1<<2)
+#define I2C_SL_NEWSL		(1<<2)
 #define I2C_SL_NACK		(1<<1)
 #define I2C_SL_RESP		(1<<0)
 #define I2C_SL_IRQ		(1<<3)
@@ -687,7 +687,7 @@
 
 	clk_set_rate(nvec->i2c_clk, 8 * 80000);
 
-	writel(I2C_SL_NEWL, nvec->base + I2C_SL_CNFG);
+	writel(I2C_SL_NEWSL, nvec->base + I2C_SL_CNFG);
 	writel(0x1E, nvec->base + I2C_SL_DELAY_COUNT);
 
 	writel(nvec->i2c_addr>>1, nvec->base + I2C_SL_ADDR1);
@@ -701,7 +701,7 @@
 static void nvec_disable_i2c_slave(struct nvec_chip *nvec)
 {
 	disable_irq(nvec->irq);
-	writel(I2C_SL_NEWL | I2C_SL_NACK, nvec->base + I2C_SL_CNFG);
+	writel(I2C_SL_NEWSL | I2C_SL_NACK, nvec->base + I2C_SL_CNFG);
 	clk_disable(nvec->i2c_clk);
 }
 
@@ -784,11 +784,6 @@
 	nvec->i2c_clk = i2c_clk;
 	nvec->rx = &nvec->msg_pool[0];
 
-	/* Set the gpio to low when we've got something to say */
-	err = gpio_request(nvec->gpio, "nvec gpio");
-	if (err < 0)
-		dev_err(nvec->dev, "couldn't request gpio\n");
-
 	ATOMIC_INIT_NOTIFIER_HEAD(&nvec->notifier_list);
 
 	init_completion(&nvec->sync_write);
@@ -802,6 +797,12 @@
 	INIT_WORK(&nvec->tx_work, nvec_request_master);
 	nvec->wq = alloc_workqueue("nvec", WQ_NON_REENTRANT, 2);
 
+	err = gpio_request_one(nvec->gpio, GPIOF_OUT_INIT_HIGH, "nvec gpio");
+	if (err < 0) {
+		dev_err(nvec->dev, "couldn't request gpio\n");
+		goto failed;
+	}
+
 	err = request_irq(nvec->irq, nvec_interrupt, 0, "nvec", nvec);
 	if (err) {
 		dev_err(nvec->dev, "couldn't request irq\n");
@@ -813,8 +814,6 @@
 
 	clk_enable(i2c_clk);
 
-	gpio_direction_output(nvec->gpio, 1);
-	gpio_set_value(nvec->gpio, 1);
 
 	/* enable event reporting */
 	nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING,
diff --git a/drivers/staging/nvec/nvec_ps2.c b/drivers/staging/nvec/nvec_ps2.c
index 742f5cc..14a6f68 100644
--- a/drivers/staging/nvec/nvec_ps2.c
+++ b/drivers/staging/nvec/nvec_ps2.c
@@ -21,10 +21,18 @@
 
 #include "nvec.h"
 
-#define START_STREAMING	{'\x06', '\x03', '\x04'}
+#define START_STREAMING	{'\x06', '\x03', '\x06'}
 #define STOP_STREAMING	{'\x06', '\x04'}
 #define SEND_COMMAND	{'\x06', '\x01', '\xf4', '\x01'}
 
+#ifdef NVEC_PS2_DEBUG
+#define NVEC_PHD(str, buf, len) \
+	print_hex_dump(KERN_DEBUG, str, DUMP_PREFIX_NONE, \
+			16, 1, buf, len, false)
+#else
+#define NVEC_PHD(str, buf, len)
+#endif
+
 static const unsigned char MOUSE_RESET[] = {'\x06', '\x01', '\xff', '\x03'};
 
 struct nvec_ps2 {
@@ -67,18 +75,18 @@
 	case NVEC_PS2_EVT:
 		for (i = 0; i < msg[1]; i++)
 			serio_interrupt(ps2_dev.ser_dev, msg[2 + i], 0);
+		NVEC_PHD("ps/2 mouse event: ", &msg[2], msg[1]);
 		return NOTIFY_STOP;
 
 	case NVEC_PS2:
-		if (msg[2] == 1)
+		if (msg[2] == 1) {
 			for (i = 0; i < (msg[1] - 2); i++)
 				serio_interrupt(ps2_dev.ser_dev, msg[i + 4], 0);
-		else if (msg[1] != 2) {	/* !ack */
-			print_hex_dump(KERN_WARNING, "unhandled mouse event: ",
-				DUMP_PREFIX_NONE, 16, 1,
-				msg, msg[1] + 2, true);
+			NVEC_PHD("ps/2 mouse reply: ", &msg[4], msg[1] - 2);
 		}
 
+		else if (msg[1] != 2) /* !ack */
+			NVEC_PHD("unhandled mouse event: ", msg, msg[1] + 2);
 		return NOTIFY_STOP;
 	}
 
@@ -90,10 +98,10 @@
 	struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
 	struct serio *ser_dev = kzalloc(sizeof(struct serio), GFP_KERNEL);
 
-	ser_dev->id.type = SERIO_8042;
+	ser_dev->id.type = SERIO_PS_PSTHRU;
 	ser_dev->write = ps2_sendcommand;
-	ser_dev->open = ps2_startstreaming;
-	ser_dev->close = ps2_stopstreaming;
+	ser_dev->start = ps2_startstreaming;
+	ser_dev->stop = ps2_stopstreaming;
 
 	strlcpy(ser_dev->name, "nvec mouse", sizeof(ser_dev->name));
 	strlcpy(ser_dev->phys, "nvec", sizeof(ser_dev->phys));
@@ -111,8 +119,35 @@
 	return 0;
 }
 
+static int nvec_mouse_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
+
+	/* disable mouse */
+	nvec_write_async(nvec, "\x06\xf4", 2);
+
+	/* send cancel autoreceive */
+	nvec_write_async(nvec, "\x06\x04", 2);
+
+	return 0;
+}
+
+static int nvec_mouse_resume(struct platform_device *pdev)
+{
+	struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
+
+	ps2_startstreaming(ps2_dev.ser_dev);
+
+	/* enable mouse */
+	nvec_write_async(nvec, "\x06\xf5", 2);
+
+	return 0;
+}
+
 static struct platform_driver nvec_mouse_driver = {
 	.probe  = nvec_mouse_probe,
+	.suspend = nvec_mouse_suspend,
+	.resume = nvec_mouse_resume,
 	.driver = {
 		.name = "nvec-mouse",
 		.owner = THIS_MODULE,
diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c
index 63800ba..e31949c 100644
--- a/drivers/staging/octeon/ethernet-mdio.c
+++ b/drivers/staging/octeon/ethernet-mdio.c
@@ -164,9 +164,9 @@
 
 	int phy_addr = cvmx_helper_board_get_mii_address(priv->port);
 	if (phy_addr != -1) {
-		char phy_id[20];
+		char phy_id[MII_BUS_ID_SIZE + 3];
 
-		snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "0", phy_addr);
+		snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "mdio-octeon-0", phy_addr);
 
 		priv->phydev = phy_connect(dev, phy_id, cvm_oct_adjust_link, 0,
 					PHY_INTERFACE_MODE_GMII);
diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c
index 17ca163..490a7f1 100644
--- a/drivers/staging/omapdrm/omap_crtc.c
+++ b/drivers/staging/omapdrm/omap_crtc.c
@@ -118,29 +118,35 @@
 {
 }
 
-static void page_flip_cb(void *arg)
+static void vblank_cb(void *arg)
 {
+	static uint32_t sequence = 0;
 	struct drm_crtc *crtc = arg;
 	struct drm_device *dev = crtc->dev;
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 	struct drm_pending_vblank_event *event = omap_crtc->event;
-	struct drm_framebuffer *old_fb = omap_crtc->old_fb;
-	struct timeval now;
 	unsigned long flags;
+	struct timeval now;
 
 	WARN_ON(!event);
 
 	omap_crtc->event = NULL;
-	omap_crtc->old_fb = NULL;
-
-	omap_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb);
 
 	/* wakeup userspace */
-	/* TODO: this should happen *after* flip in vsync IRQ handler */
 	if (event) {
+		do_gettimeofday(&now);
+
 		spin_lock_irqsave(&dev->event_lock, flags);
+		/* TODO: we can't yet use the vblank time accounting,
+		 * because omapdss lower layer is the one that knows
+		 * the irq # and registers the handler, which more or
+		 * less defeats how drm_irq works.. for now just fake
+		 * the sequence number and use gettimeofday..
+		 *
 		event->event.sequence = drm_vblank_count_and_time(
 				dev, omap_crtc->id, &now);
+		 */
+		event->event.sequence = sequence++;
 		event->event.tv_sec = now.tv_sec;
 		event->event.tv_usec = now.tv_usec;
 		list_add_tail(&event->base.link,
@@ -150,6 +156,23 @@
 	}
 }
 
+static void page_flip_cb(void *arg)
+{
+	struct drm_crtc *crtc = arg;
+	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+	struct drm_framebuffer *old_fb = omap_crtc->old_fb;
+
+	omap_crtc->old_fb = NULL;
+
+	omap_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb);
+
+	/* really we'd like to setup the callback atomically w/ setting the
+	 * new scanout buffer to avoid getting stuck waiting an extra vblank
+	 * cycle.. for now go for correctness and later figure out speed..
+	 */
+	omap_plane_on_endwin(omap_crtc->plane, vblank_cb, crtc);
+}
+
 static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
 		 struct drm_framebuffer *fb,
 		 struct drm_pending_vblank_event *event)
diff --git a/drivers/staging/omapdrm/omap_debugfs.c b/drivers/staging/omapdrm/omap_debugfs.c
index da920df..2f122e0 100644
--- a/drivers/staging/omapdrm/omap_debugfs.c
+++ b/drivers/staging/omapdrm/omap_debugfs.c
@@ -20,23 +20,118 @@
 #include "omap_drv.h"
 #include "omap_dmm_tiler.h"
 
+#include "drm_fb_helper.h"
+
+
 #ifdef CONFIG_DEBUG_FS
 
+static int gem_show(struct seq_file *m, void *arg)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct omap_drm_private *priv = dev->dev_private;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
+
+	seq_printf(m, "All Objects:\n");
+	omap_gem_describe_objects(&priv->obj_list, m);
+
+	mutex_unlock(&dev->struct_mutex);
+
+	return 0;
+}
+
+static int mm_show(struct seq_file *m, void *arg)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	return drm_mm_dump_table(m, dev->mm_private);
+}
+
+static int fb_show(struct seq_file *m, void *arg)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct omap_drm_private *priv = dev->dev_private;
+	struct drm_framebuffer *fb;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
+	if (ret)
+		return ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret) {
+		mutex_unlock(&dev->mode_config.mutex);
+		return ret;
+	}
+
+	seq_printf(m, "fbcon ");
+	omap_framebuffer_describe(priv->fbdev->fb, m);
+
+	list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
+		if (fb == priv->fbdev->fb)
+			continue;
+
+		seq_printf(m, "user ");
+		omap_framebuffer_describe(fb, m);
+	}
+
+	mutex_unlock(&dev->struct_mutex);
+	mutex_unlock(&dev->mode_config.mutex);
+
+	return 0;
+}
+
+/* list of debufs files that are applicable to all devices */
 static struct drm_info_list omap_debugfs_list[] = {
+	{"gem", gem_show, 0},
+	{"mm", mm_show, 0},
+	{"fb", fb_show, 0},
+};
+
+/* list of debugfs files that are specific to devices with dmm/tiler */
+static struct drm_info_list omap_dmm_debugfs_list[] = {
 	{"tiler_map", tiler_map_show, 0},
 };
 
 int omap_debugfs_init(struct drm_minor *minor)
 {
-	return drm_debugfs_create_files(omap_debugfs_list,
+	struct drm_device *dev = minor->dev;
+	int ret;
+
+	ret = drm_debugfs_create_files(omap_debugfs_list,
 			ARRAY_SIZE(omap_debugfs_list),
 			minor->debugfs_root, minor);
+
+	if (ret) {
+		dev_err(dev->dev, "could not install omap_debugfs_list\n");
+		return ret;
+	}
+
+	if (dmm_is_available())
+		ret = drm_debugfs_create_files(omap_dmm_debugfs_list,
+				ARRAY_SIZE(omap_dmm_debugfs_list),
+				minor->debugfs_root, minor);
+
+	if (ret) {
+		dev_err(dev->dev, "could not install omap_dmm_debugfs_list\n");
+		return ret;
+	}
+
+	return ret;
 }
 
 void omap_debugfs_cleanup(struct drm_minor *minor)
 {
 	drm_debugfs_remove_files(omap_debugfs_list,
 			ARRAY_SIZE(omap_debugfs_list), minor);
+	if (dmm_is_available())
+		drm_debugfs_remove_files(omap_dmm_debugfs_list,
+				ARRAY_SIZE(omap_dmm_debugfs_list), minor);
 }
 
 #endif
diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.c b/drivers/staging/omapdrm/omap_dmm_tiler.c
index 852d944..1ecb6a7 100644
--- a/drivers/staging/omapdrm/omap_dmm_tiler.c
+++ b/drivers/staging/omapdrm/omap_dmm_tiler.c
@@ -34,6 +34,8 @@
 #include "omap_dmm_tiler.h"
 #include "omap_dmm_priv.h"
 
+#define DMM_DRIVER_NAME "dmm"
+
 /* mappings for associating views to luts */
 static struct tcm *containers[TILFMT_NFORMATS];
 static struct dmm *omap_dmm;
@@ -465,7 +467,12 @@
 	return round_up(geom[fmt].cpp * w, PAGE_SIZE) * h;
 }
 
-int omap_dmm_remove(void)
+bool dmm_is_initialized(void)
+{
+	return omap_dmm ? true : false;
+}
+
+static int omap_dmm_remove(struct platform_device *dev)
 {
 	struct tiler_block *block, *_block;
 	int i;
@@ -499,40 +506,49 @@
 		if (omap_dmm->irq != -1)
 			free_irq(omap_dmm->irq, omap_dmm);
 
+		iounmap(omap_dmm->base);
 		kfree(omap_dmm);
+		omap_dmm = NULL;
 	}
 
 	return 0;
 }
 
-int omap_dmm_init(struct drm_device *dev)
+static int omap_dmm_probe(struct platform_device *dev)
 {
 	int ret = -EFAULT, i;
 	struct tcm_area area = {0};
 	u32 hwinfo, pat_geom, lut_table_size;
-	struct omap_drm_platform_data *pdata = dev->dev->platform_data;
-
-	if (!pdata || !pdata->dmm_pdata) {
-		dev_err(dev->dev, "dmm platform data not present, skipping\n");
-		return ret;
-	}
+	struct resource *mem;
 
 	omap_dmm = kzalloc(sizeof(*omap_dmm), GFP_KERNEL);
 	if (!omap_dmm) {
-		dev_err(dev->dev, "failed to allocate driver data section\n");
+		dev_err(&dev->dev, "failed to allocate driver data section\n");
 		goto fail;
 	}
 
 	/* lookup hwmod data - base address and irq */
-	omap_dmm->base = pdata->dmm_pdata->base;
-	omap_dmm->irq = pdata->dmm_pdata->irq;
-	omap_dmm->dev = dev->dev;
-
-	if (!omap_dmm->base) {
-		dev_err(dev->dev, "failed to get dmm base address\n");
+	mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&dev->dev, "failed to get base address resource\n");
 		goto fail;
 	}
 
+	omap_dmm->base = ioremap(mem->start, SZ_2K);
+
+	if (!omap_dmm->base) {
+		dev_err(&dev->dev, "failed to get dmm base address\n");
+		goto fail;
+	}
+
+	omap_dmm->irq = platform_get_irq(dev, 0);
+	if (omap_dmm->irq < 0) {
+		dev_err(&dev->dev, "failed to get IRQ resource\n");
+		goto fail;
+	}
+
+	omap_dmm->dev = &dev->dev;
+
 	hwinfo = readl(omap_dmm->base + DMM_PAT_HWINFO);
 	omap_dmm->num_engines = (hwinfo >> 24) & 0x1F;
 	omap_dmm->num_lut = (hwinfo >> 16) & 0x1F;
@@ -556,7 +572,7 @@
 				"omap_dmm_irq_handler", omap_dmm);
 
 	if (ret) {
-		dev_err(dev->dev, "couldn't register IRQ %d, error %d\n",
+		dev_err(&dev->dev, "couldn't register IRQ %d, error %d\n",
 			omap_dmm->irq, ret);
 		omap_dmm->irq = -1;
 		goto fail;
@@ -575,25 +591,30 @@
 
 	omap_dmm->lut = vmalloc(lut_table_size * sizeof(*omap_dmm->lut));
 	if (!omap_dmm->lut) {
-		dev_err(dev->dev, "could not allocate lut table\n");
+		dev_err(&dev->dev, "could not allocate lut table\n");
 		ret = -ENOMEM;
 		goto fail;
 	}
 
 	omap_dmm->dummy_page = alloc_page(GFP_KERNEL | __GFP_DMA32);
 	if (!omap_dmm->dummy_page) {
-		dev_err(dev->dev, "could not allocate dummy page\n");
+		dev_err(&dev->dev, "could not allocate dummy page\n");
 		ret = -ENOMEM;
 		goto fail;
 	}
+
+	/* set dma mask for device */
+	/* NOTE: this is a workaround for the hwmod not initializing properly */
+	dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
 	omap_dmm->dummy_pa = page_to_phys(omap_dmm->dummy_page);
 
 	/* alloc refill memory */
-	omap_dmm->refill_va = dma_alloc_coherent(dev->dev,
+	omap_dmm->refill_va = dma_alloc_coherent(&dev->dev,
 				REFILL_BUFFER_SIZE * omap_dmm->num_engines,
 				&omap_dmm->refill_pa, GFP_KERNEL);
 	if (!omap_dmm->refill_va) {
-		dev_err(dev->dev, "could not allocate refill memory\n");
+		dev_err(&dev->dev, "could not allocate refill memory\n");
 		goto fail;
 	}
 
@@ -602,7 +623,7 @@
 			omap_dmm->num_engines * sizeof(struct refill_engine),
 			GFP_KERNEL);
 	if (!omap_dmm->engines) {
-		dev_err(dev->dev, "could not allocate engines\n");
+		dev_err(&dev->dev, "could not allocate engines\n");
 		ret = -ENOMEM;
 		goto fail;
 	}
@@ -624,7 +645,7 @@
 	omap_dmm->tcm = kzalloc(omap_dmm->num_lut * sizeof(*omap_dmm->tcm),
 				GFP_KERNEL);
 	if (!omap_dmm->tcm) {
-		dev_err(dev->dev, "failed to allocate lut ptrs\n");
+		dev_err(&dev->dev, "failed to allocate lut ptrs\n");
 		ret = -ENOMEM;
 		goto fail;
 	}
@@ -636,7 +657,7 @@
 						NULL);
 
 		if (!omap_dmm->tcm[i]) {
-			dev_err(dev->dev, "failed to allocate container\n");
+			dev_err(&dev->dev, "failed to allocate container\n");
 			ret = -ENOMEM;
 			goto fail;
 		}
@@ -676,7 +697,7 @@
 	return 0;
 
 fail:
-	omap_dmm_remove();
+	omap_dmm_remove(dev);
 	return ret;
 }
 
@@ -766,10 +787,18 @@
 	const char *a2d = special;
 	const char *m2dp = m2d, *a2dp = a2d;
 	char nice[128];
-	int h_adj = omap_dmm->lut_height / ydiv;
-	int w_adj = omap_dmm->lut_width / xdiv;
+	int h_adj;
+	int w_adj;
 	unsigned long flags;
 
+	if (!omap_dmm) {
+		/* early return if dmm/tiler device is not initialized */
+		return 0;
+	}
+
+	h_adj = omap_dmm->lut_height / ydiv;
+	w_adj = omap_dmm->lut_width / xdiv;
+
 	map = kzalloc(h_adj * sizeof(*map), GFP_KERNEL);
 	global_map = kzalloc((w_adj + 1) * h_adj, GFP_KERNEL);
 
@@ -828,3 +857,17 @@
 	return 0;
 }
 #endif
+
+struct platform_driver omap_dmm_driver = {
+	.probe = omap_dmm_probe,
+	.remove = omap_dmm_remove,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = DMM_DRIVER_NAME,
+	},
+};
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Andy Gross <andy.gross@ti.com>");
+MODULE_DESCRIPTION("OMAP DMM/Tiler Driver");
+MODULE_ALIAS("platform:" DMM_DRIVER_NAME);
diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.h b/drivers/staging/omapdrm/omap_dmm_tiler.h
index f87cb65..7b1052a 100644
--- a/drivers/staging/omapdrm/omap_dmm_tiler.h
+++ b/drivers/staging/omapdrm/omap_dmm_tiler.h
@@ -16,6 +16,7 @@
 #ifndef OMAP_DMM_TILER_H
 #define OMAP_DMM_TILER_H
 
+#include <plat/cpu.h>
 #include "omap_drv.h"
 #include "tcm.h"
 
@@ -72,10 +73,6 @@
 #define TIL_ADDR(x, orient, a)\
 	((u32) (x) | (orient) | ((a) << SHIFT_ACC_MODE))
 
-/* externally accessible functions */
-int omap_dmm_init(struct drm_device *dev);
-int omap_dmm_remove(void);
-
 #ifdef CONFIG_DEBUG_FS
 int tiler_map_show(struct seq_file *s, void *arg);
 #endif
@@ -97,7 +94,9 @@
 size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h);
 size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h);
 void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h);
+bool dmm_is_initialized(void);
 
+extern struct platform_driver omap_dmm_driver;
 
 /* GEM bo flags -> tiler fmt */
 static inline enum tiler_fmt gem2fmt(uint32_t flags)
@@ -127,9 +126,9 @@
 	}
 }
 
-struct omap_dmm_platform_data {
-	void __iomem *base;
-	int irq;
-};
+static inline int dmm_is_available(void)
+{
+	return cpu_is_omap44xx();
+}
 
 #endif
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c
index 3bbea9a..3df5b4c 100644
--- a/drivers/staging/omapdrm/omap_drv.c
+++ b/drivers/staging/omapdrm/omap_drv.c
@@ -21,6 +21,7 @@
 
 #include "drm_crtc_helper.h"
 #include "drm_fb_helper.h"
+#include "omap_dmm_tiler.h"
 
 #define DRIVER_NAME		MODULE_NAME
 #define DRIVER_DESC		"OMAP DRM"
@@ -570,6 +571,11 @@
 
 	dev->dev_private = priv;
 
+	priv->wq = alloc_workqueue("omapdrm",
+			WQ_UNBOUND | WQ_NON_REENTRANT, 1);
+
+	INIT_LIST_HEAD(&priv->obj_list);
+
 	omap_gem_init(dev);
 
 	ret = omap_modeset_init(dev);
@@ -598,6 +604,8 @@
 
 static int dev_unload(struct drm_device *dev)
 {
+	struct omap_drm_private *priv = dev->dev_private;
+
 	DBG("unload: dev=%p", dev);
 
 	drm_vblank_cleanup(dev);
@@ -607,6 +615,9 @@
 	omap_modeset_free(dev);
 	omap_gem_deinit(dev);
 
+	flush_workqueue(priv->wq);
+	destroy_workqueue(priv->wq);
+
 	kfree(dev->dev_private);
 	dev->dev_private = NULL;
 
@@ -792,6 +803,9 @@
 static int pdev_probe(struct platform_device *device)
 {
 	DBG("%s", device->name);
+	if (platform_driver_register(&omap_dmm_driver))
+		dev_err(&device->dev, "DMM registration failed\n");
+
 	return drm_platform_init(&omap_drm_driver, device);
 }
 
@@ -799,6 +813,8 @@
 {
 	DBG("");
 	drm_platform_exit(&omap_drm_driver, device);
+
+	platform_driver_unregister(&omap_dmm_driver);
 	return 0;
 }
 
diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h
index 61fe022..b7e0f07 100644
--- a/drivers/staging/omapdrm/omap_drv.h
+++ b/drivers/staging/omapdrm/omap_drv.h
@@ -42,21 +42,31 @@
 struct omap_drm_private {
 	unsigned int num_crtcs;
 	struct drm_crtc *crtcs[8];
+
 	unsigned int num_planes;
 	struct drm_plane *planes[8];
+
 	unsigned int num_encoders;
 	struct drm_encoder *encoders[8];
+
 	unsigned int num_connectors;
 	struct drm_connector *connectors[8];
 
 	struct drm_fb_helper *fbdev;
 
+	struct workqueue_struct *wq;
+
+	struct list_head obj_list;
+
 	bool has_dmm;
 };
 
 #ifdef CONFIG_DEBUG_FS
 int omap_debugfs_init(struct drm_minor *minor);
 void omap_debugfs_cleanup(struct drm_minor *minor);
+void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m);
+void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m);
+void omap_gem_describe_objects(struct list_head *list, struct seq_file *m);
 #endif
 
 struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev);
@@ -75,6 +85,8 @@
 		unsigned int crtc_w, unsigned int crtc_h,
 		uint32_t src_x, uint32_t src_y,
 		uint32_t src_w, uint32_t src_h);
+void omap_plane_on_endwin(struct drm_plane *plane,
+		void (*fxn)(void *), void *arg);
 
 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
 		struct omap_overlay_manager *mgr);
@@ -92,13 +104,16 @@
 void omap_connector_flush(struct drm_connector *connector,
 		int x, int y, int w, int h);
 
+uint32_t omap_framebuffer_get_formats(uint32_t *pixel_formats,
+		uint32_t max_formats, enum omap_color_mode supported_modes);
 struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
 		struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd);
 struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
 		struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
 struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p);
-int omap_framebuffer_pin(struct drm_framebuffer *fb);
-void omap_framebuffer_unpin(struct drm_framebuffer *fb);
+int omap_framebuffer_replace(struct drm_framebuffer *a,
+		struct drm_framebuffer *b, void *arg,
+		void (*unpin)(void *arg, struct drm_gem_object *bo));
 void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y,
 		struct omap_overlay_info *info);
 struct drm_connector *omap_framebuffer_get_next_connector(
diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c
index d021a7e..04b235b 100644
--- a/drivers/staging/omapdrm/omap_fb.c
+++ b/drivers/staging/omapdrm/omap_fb.c
@@ -59,6 +59,20 @@
 	{ OMAP_DSS_COLOR_UYVY,        DRM_FORMAT_UYVY,     {{2, 1}}, true },
 };
 
+/* convert from overlay's pixel formats bitmask to an array of fourcc's */
+uint32_t omap_framebuffer_get_formats(uint32_t *pixel_formats,
+		uint32_t max_formats, enum omap_color_mode supported_modes)
+{
+	uint32_t nformats = 0;
+	int i = 0;
+
+	for (i = 0; i < ARRAY_SIZE(formats) && nformats < max_formats; i++)
+		if (formats[i].dss_format & supported_modes)
+			pixel_formats[nformats++] = formats[i].pixel_format;
+
+	return nformats;
+}
+
 /* per-plane info for the fb: */
 struct plane {
 	struct drm_gem_object *bo;
@@ -87,7 +101,7 @@
 static void omap_framebuffer_destroy(struct drm_framebuffer *fb)
 {
 	struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
-	int i, n = drm_format_num_planes(omap_fb->format->pixel_format);
+	int i, n = drm_format_num_planes(fb->pixel_format);
 
 	DBG("destroy: FB ID: %d (%p)", fb->base.id, fb);
 
@@ -123,41 +137,6 @@
 	.dirty = omap_framebuffer_dirty,
 };
 
-/* pins buffer in preparation for scanout */
-int omap_framebuffer_pin(struct drm_framebuffer *fb)
-{
-	struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
-	int ret, i, n = drm_format_num_planes(omap_fb->format->pixel_format);
-
-	for (i = 0; i < n; i++) {
-		struct plane *plane = &omap_fb->planes[i];
-		ret = omap_gem_get_paddr(plane->bo, &plane->paddr, true);
-		if (ret)
-			goto fail;
-	}
-
-	return 0;
-
-fail:
-	while (--i > 0) {
-		struct plane *plane = &omap_fb->planes[i];
-		omap_gem_put_paddr(plane->bo);
-	}
-	return ret;
-}
-
-/* releases buffer when done with scanout */
-void omap_framebuffer_unpin(struct drm_framebuffer *fb)
-{
-	struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
-	int i, n = drm_format_num_planes(omap_fb->format->pixel_format);
-
-	for (i = 0; i < n; i++) {
-		struct plane *plane = &omap_fb->planes[i];
-		omap_gem_put_paddr(plane->bo);
-	}
-}
-
 /* update ovl info for scanout, handles cases of multi-planar fb's, etc.
  */
 void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y,
@@ -187,10 +166,59 @@
 	}
 }
 
+/* Call for unpin 'a' (if not NULL), and pin 'b' (if not NULL).  Although
+ * buffers to unpin are just just pushed to the unpin fifo so that the
+ * caller can defer unpin until vblank.
+ *
+ * Note if this fails (ie. something went very wrong!), all buffers are
+ * unpinned, and the caller disables the overlay.  We could have tried
+ * to revert back to the previous set of pinned buffers but if things are
+ * hosed there is no guarantee that would succeed.
+ */
+int omap_framebuffer_replace(struct drm_framebuffer *a,
+		struct drm_framebuffer *b, void *arg,
+		void (*unpin)(void *arg, struct drm_gem_object *bo))
+{
+	int ret = 0, i, na, nb;
+	struct omap_framebuffer *ofba = to_omap_framebuffer(a);
+	struct omap_framebuffer *ofbb = to_omap_framebuffer(b);
+
+	na = a ? drm_format_num_planes(a->pixel_format) : 0;
+	nb = b ? drm_format_num_planes(b->pixel_format) : 0;
+
+	for (i = 0; i < max(na, nb); i++) {
+		struct plane *pa, *pb;
+
+		pa = (i < na) ? &ofba->planes[i] : NULL;
+		pb = (i < nb) ? &ofbb->planes[i] : NULL;
+
+		if (pa) {
+			unpin(arg, pa->bo);
+			pa->paddr = 0;
+		}
+
+		if (pb && !ret)
+			ret = omap_gem_get_paddr(pb->bo, &pb->paddr, true);
+	}
+
+	if (ret) {
+		/* something went wrong.. unpin what has been pinned */
+		for (i = 0; i < nb; i++) {
+			struct plane *pb = &ofba->planes[i];
+			if (pb->paddr) {
+				unpin(arg, pb->bo);
+				pb->paddr = 0;
+			}
+		}
+	}
+
+	return ret;
+}
+
 struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p)
 {
 	struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
-	if (p >= drm_format_num_planes(omap_fb->format->pixel_format))
+	if (p >= drm_format_num_planes(fb->pixel_format))
 		return NULL;
 	return omap_fb->planes[p].bo;
 }
@@ -249,6 +277,24 @@
 	}
 }
 
+#ifdef CONFIG_DEBUG_FS
+void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
+{
+	struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
+	int i, n = drm_format_num_planes(fb->pixel_format);
+
+	seq_printf(m, "fb: %dx%d@%4.4s\n", fb->width, fb->height,
+			(char *)&fb->pixel_format);
+
+	for (i = 0; i < n; i++) {
+		struct plane *plane = &omap_fb->planes[i];
+		seq_printf(m, "   %d: offset=%d pitch=%d, obj: ",
+				i, plane->offset, plane->pitch);
+		omap_gem_describe(plane->bo, m);
+	}
+}
+#endif
+
 struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
 		struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd)
 {
@@ -337,8 +383,8 @@
 
 		plane->bo     = bos[i];
 		plane->offset = mode_cmd->offsets[i];
-		plane->pitch  = mode_cmd->pitches[i];
-		plane->paddr  = pitch;
+		plane->pitch  = pitch;
+		plane->paddr  = 0;
 	}
 
 	drm_helper_mode_fill_fb_struct(fb, mode_cmd);
diff --git a/drivers/staging/omapdrm/omap_fbdev.c b/drivers/staging/omapdrm/omap_fbdev.c
index 96940bb..11acd4c 100644
--- a/drivers/staging/omapdrm/omap_fbdev.c
+++ b/drivers/staging/omapdrm/omap_fbdev.c
@@ -37,6 +37,9 @@
 	struct drm_framebuffer *fb;
 	struct drm_gem_object *bo;
 	bool ywrap_enabled;
+
+	/* for deferred dmm roll when getting called in atomic ctx */
+	struct work_struct work;
 };
 
 static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h);
@@ -75,12 +78,22 @@
 				image->width, image->height);
 }
 
+static void pan_worker(struct work_struct *work)
+{
+	struct omap_fbdev *fbdev = container_of(work, struct omap_fbdev, work);
+	struct fb_info *fbi = fbdev->base.fbdev;
+	int npages;
+
+	/* DMM roll shifts in 4K pages: */
+	npages = fbi->fix.line_length >> PAGE_SHIFT;
+	omap_gem_roll(fbdev->bo, fbi->var.yoffset * npages);
+}
+
 static int omap_fbdev_pan_display(struct fb_var_screeninfo *var,
 		struct fb_info *fbi)
 {
 	struct drm_fb_helper *helper = get_fb(fbi);
 	struct omap_fbdev *fbdev = to_omap_fbdev(helper);
-	int npages;
 
 	if (!helper)
 		goto fallback;
@@ -88,9 +101,12 @@
 	if (!fbdev->ywrap_enabled)
 		goto fallback;
 
-	/* DMM roll shifts in 4K pages: */
-	npages = fbi->fix.line_length >> PAGE_SHIFT;
-	omap_gem_roll(fbdev->bo, var->yoffset * npages);
+	if (drm_can_sleep()) {
+		pan_worker(&fbdev->work);
+	} else {
+		struct omap_drm_private *priv = helper->dev->dev_private;
+		queue_work(priv->wq, &fbdev->work);
+	}
 
 	return 0;
 
@@ -336,6 +352,8 @@
 		goto fail;
 	}
 
+	INIT_WORK(&fbdev->work, pan_worker);
+
 	helper = &fbdev->base;
 
 	helper->funcs = &omap_fb_helper_funcs;
diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c
index b7d6f88..921f058 100644
--- a/drivers/staging/omapdrm/omap_gem.c
+++ b/drivers/staging/omapdrm/omap_gem.c
@@ -45,6 +45,8 @@
 struct omap_gem_object {
 	struct drm_gem_object base;
 
+	struct list_head mm_list;
+
 	uint32_t flags;
 
 	/** width/height for tiled formats (rounded up to slot boundaries) */
@@ -151,10 +153,23 @@
 		enum tiler_fmt fmt, struct usergart_entry *entry)
 {
 	if (obj->dev->dev_mapping) {
-		size_t size = PAGE_SIZE * usergart[fmt].height;
+		struct omap_gem_object *omap_obj = to_omap_bo(obj);
+		int n = usergart[fmt].height;
+		size_t size = PAGE_SIZE * n;
 		loff_t off = mmap_offset(obj) +
 				(entry->obj_pgoff << PAGE_SHIFT);
-		unmap_mapping_range(obj->dev->dev_mapping, off, size, 1);
+		const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE);
+		if (m > 1) {
+			int i;
+			/* if stride > than PAGE_SIZE then sparse mapping: */
+			for (i = n; i > 0; i--) {
+				unmap_mapping_range(obj->dev->dev_mapping,
+						off, PAGE_SIZE, 1);
+				off += PAGE_SIZE * m;
+			}
+		} else {
+			unmap_mapping_range(obj->dev->dev_mapping, off, size, 1);
+		}
 	}
 
 	entry->obj = NULL;
@@ -254,13 +269,17 @@
 /** get mmap offset */
 static uint64_t mmap_offset(struct drm_gem_object *obj)
 {
+	struct drm_device *dev = obj->dev;
+
+	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
 	if (!obj->map_list.map) {
 		/* Make it mmapable */
 		size_t size = omap_gem_mmap_size(obj);
 		int ret = _drm_gem_create_mmap_offset_size(obj, size);
 
 		if (ret) {
-			dev_err(obj->dev->dev, "could not allocate mmap offset");
+			dev_err(dev->dev, "could not allocate mmap offset\n");
 			return 0;
 		}
 	}
@@ -336,26 +355,39 @@
 	void __user *vaddr;
 	int i, ret, slots;
 
-	if (!usergart)
-		return -EFAULT;
-
-	/* TODO: this fxn might need a bit tweaking to deal w/ tiled buffers
-	 * that are wider than 4kb
+	/*
+	 * Note the height of the slot is also equal to the number of pages
+	 * that need to be mapped in to fill 4kb wide CPU page.  If the slot
+	 * height is 64, then 64 pages fill a 4kb wide by 64 row region.
 	 */
+	const int n = usergart[fmt].height;
+	const int n_shift = usergart[fmt].height_shift;
+
+	/*
+	 * If buffer width in bytes > PAGE_SIZE then the virtual stride is
+	 * rounded up to next multiple of PAGE_SIZE.. this need to be taken
+	 * into account in some of the math, so figure out virtual stride
+	 * in pages
+	 */
+	const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE);
 
 	/* We don't use vmf->pgoff since that has the fake offset: */
 	pgoff = ((unsigned long)vmf->virtual_address -
 			vma->vm_start) >> PAGE_SHIFT;
 
-	/* actual address we start mapping at is rounded down to previous slot
+	/*
+	 * Actual address we start mapping at is rounded down to previous slot
 	 * boundary in the y direction:
 	 */
-	base_pgoff = round_down(pgoff, usergart[fmt].height);
-	vaddr = vmf->virtual_address - ((pgoff - base_pgoff) << PAGE_SHIFT);
-	entry = &usergart[fmt].entry[usergart[fmt].last];
+	base_pgoff = round_down(pgoff, m << n_shift);
 
+	/* figure out buffer width in slots */
 	slots = omap_obj->width >> usergart[fmt].slot_shift;
 
+	vaddr = vmf->virtual_address - ((pgoff - base_pgoff) << PAGE_SHIFT);
+
+	entry = &usergart[fmt].entry[usergart[fmt].last];
+
 	/* evict previous buffer using this usergart entry, if any: */
 	if (entry->obj)
 		evict_entry(entry->obj, fmt, entry);
@@ -363,23 +395,30 @@
 	entry->obj = obj;
 	entry->obj_pgoff = base_pgoff;
 
-	/* now convert base_pgoff to phys offset from virt offset:
-	 */
-	base_pgoff = (base_pgoff >> usergart[fmt].height_shift) * slots;
+	/* now convert base_pgoff to phys offset from virt offset: */
+	base_pgoff = (base_pgoff >> n_shift) * slots;
 
-	/* map in pages.  Note the height of the slot is also equal to the
-	 * number of pages that need to be mapped in to fill 4kb wide CPU page.
-	 * If the height is 64, then 64 pages fill a 4kb wide by 64 row region.
-	 * Beyond the valid pixel part of the buffer, we set pages[i] to NULL to
-	 * get a dummy page mapped in.. if someone reads/writes it they will get
-	 * random/undefined content, but at least it won't be corrupting
-	 * whatever other random page used to be mapped in, or other undefined
-	 * behavior.
+	/* for wider-than 4k.. figure out which part of the slot-row we want: */
+	if (m > 1) {
+		int off = pgoff % m;
+		entry->obj_pgoff += off;
+		base_pgoff /= m;
+		slots = min(slots - (off << n_shift), n);
+		base_pgoff += off << n_shift;
+		vaddr += off << PAGE_SHIFT;
+	}
+
+	/*
+	 * Map in pages. Beyond the valid pixel part of the buffer, we set
+	 * pages[i] to NULL to get a dummy page mapped in.. if someone
+	 * reads/writes it they will get random/undefined content, but at
+	 * least it won't be corrupting whatever other random page used to
+	 * be mapped in, or other undefined behavior.
 	 */
 	memcpy(pages, &omap_obj->pages[base_pgoff],
 			sizeof(struct page *) * slots);
 	memset(pages + slots, 0,
-			sizeof(struct page *) * (usergart[fmt].height - slots));
+			sizeof(struct page *) * (n - slots));
 
 	ret = tiler_pin(entry->block, pages, ARRAY_SIZE(pages), 0, true);
 	if (ret) {
@@ -387,16 +426,15 @@
 		return ret;
 	}
 
-	i = usergart[fmt].height;
 	pfn = entry->paddr >> PAGE_SHIFT;
 
 	VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address,
 			pfn, pfn << PAGE_SHIFT);
 
-	while (i--) {
+	for (i = n; i > 0; i--) {
 		vm_insert_mixed(vma, (unsigned long)vaddr, pfn);
 		pfn += usergart[fmt].stride_pfn;
-		vaddr += PAGE_SIZE;
+		vaddr += PAGE_SIZE * m;
 	}
 
 	/* simple round-robin: */
@@ -566,6 +604,8 @@
 
 /* Set scrolling position.  This allows us to implement fast scrolling
  * for console.
+ *
+ * Call only from non-atomic contexts.
  */
 int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll)
 {
@@ -580,18 +620,6 @@
 
 	omap_obj->roll = roll;
 
-	if (in_atomic() || mutex_is_locked(&obj->dev->struct_mutex)) {
-		/* this can get called from fbcon in atomic context.. so
-		 * just ignore it and wait for next time called from
-		 * interruptible context to update the PAT.. the result
-		 * may be that user sees wrap-around instead of scrolling
-		 * momentarily on the screen.  If we wanted to be fancier
-		 * we could perhaps schedule some workqueue work at this
-		 * point.
-		 */
-		return 0;
-	}
-
 	mutex_lock(&obj->dev->struct_mutex);
 
 	/* if we aren't mapped yet, we don't need to do anything */
@@ -774,6 +802,56 @@
 	return omap_obj->vaddr;
 }
 
+#ifdef CONFIG_DEBUG_FS
+void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
+{
+	struct drm_device *dev = obj->dev;
+	struct omap_gem_object *omap_obj = to_omap_bo(obj);
+	uint64_t off = 0;
+
+	WARN_ON(! mutex_is_locked(&dev->struct_mutex));
+
+	if (obj->map_list.map)
+		off = (uint64_t)obj->map_list.hash.key;
+
+	seq_printf(m, "%08x: %2d (%2d) %08llx %08Zx (%2d) %p %4d",
+			omap_obj->flags, obj->name, obj->refcount.refcount.counter,
+			off, omap_obj->paddr, omap_obj->paddr_cnt,
+			omap_obj->vaddr, omap_obj->roll);
+
+	if (omap_obj->flags & OMAP_BO_TILED) {
+		seq_printf(m, " %dx%d", omap_obj->width, omap_obj->height);
+		if (omap_obj->block) {
+			struct tcm_area *area = &omap_obj->block->area;
+			seq_printf(m, " (%dx%d, %dx%d)",
+					area->p0.x, area->p0.y,
+					area->p1.x, area->p1.y);
+		}
+	} else {
+		seq_printf(m, " %d", obj->size);
+	}
+
+	seq_printf(m, "\n");
+}
+
+void omap_gem_describe_objects(struct list_head *list, struct seq_file *m)
+{
+	struct omap_gem_object *omap_obj;
+	int count = 0;
+	size_t size = 0;
+
+	list_for_each_entry(omap_obj, list, mm_list) {
+		struct drm_gem_object *obj = &omap_obj->base;
+		seq_printf(m, "   ");
+		omap_gem_describe(obj, m);
+		count++;
+		size += obj->size;
+	}
+
+	seq_printf(m, "Total %d objects, %zu bytes\n", count, size);
+}
+#endif
+
 /* Buffer Synchronization:
  */
 
@@ -1040,6 +1118,10 @@
 
 	evict(obj);
 
+	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+	list_del(&omap_obj->mm_list);
+
 	if (obj->map_list.map) {
 		drm_gem_free_mmap_offset(obj);
 	}
@@ -1140,6 +1222,8 @@
 		goto fail;
 	}
 
+	list_add(&omap_obj->mm_list, &priv->obj_list);
+
 	obj = &omap_obj->base;
 
 	if ((flags & OMAP_BO_SCANOUT) && !priv->has_dmm) {
@@ -1186,12 +1270,11 @@
 	const enum tiler_fmt fmts[] = {
 			TILFMT_8BIT, TILFMT_16BIT, TILFMT_32BIT
 	};
-	int i, j, ret;
+	int i, j;
 
-	ret = omap_dmm_init(dev);
-	if (ret) {
+	if (!dmm_is_initialized()) {
 		/* DMM only supported on OMAP4 and later, so this isn't fatal */
-		dev_warn(dev->dev, "omap_dmm_init failed, disabling DMM\n");
+		dev_warn(dev->dev, "DMM not available, disable DMM support\n");
 		return;
 	}
 
@@ -1241,6 +1324,5 @@
 	/* I believe we can rely on there being no more outstanding GEM
 	 * objects which could depend on usergart/dmm at this point.
 	 */
-	omap_dmm_remove();
 	kfree(usergart);
 }
diff --git a/drivers/staging/omapdrm/omap_gem_helpers.c b/drivers/staging/omapdrm/omap_gem_helpers.c
index 29275c7..f895363 100644
--- a/drivers/staging/omapdrm/omap_gem_helpers.c
+++ b/drivers/staging/omapdrm/omap_gem_helpers.c
@@ -84,7 +84,7 @@
 		page_cache_release(pages[i]);
 	}
 	drm_free_large(pages);
-	return ERR_PTR(PTR_ERR(p));
+	return ERR_CAST(p);
 }
 
 /**
diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c
index 9790912..7997be7 100644
--- a/drivers/staging/omapdrm/omap_plane.c
+++ b/drivers/staging/omapdrm/omap_plane.c
@@ -17,6 +17,8 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/kfifo.h>
+
 #include "omap_drv.h"
 
 /* some hackery because omapdss has an 'enum omap_plane' (which would be
@@ -29,6 +31,11 @@
  * plane funcs
  */
 
+struct callback {
+	void (*fxn)(void *);
+	void *arg;
+};
+
 #define to_omap_plane(x) container_of(x, struct omap_plane, base)
 
 struct omap_plane {
@@ -43,8 +50,84 @@
 
 	/* last fb that we pinned: */
 	struct drm_framebuffer *pinned_fb;
+
+	uint32_t nformats;
+	uint32_t formats[32];
+
+	/* for synchronizing access to unpins fifo */
+	struct mutex unpin_mutex;
+
+	/* set of bo's pending unpin until next END_WIN irq */
+	DECLARE_KFIFO_PTR(unpin_fifo, struct drm_gem_object *);
+	int num_unpins, pending_num_unpins;
+
+	/* for deferred unpin when we need to wait for scanout complete irq */
+	struct work_struct work;
+
+	/* callback on next endwin irq */
+	struct callback endwin;
 };
 
+/* map from ovl->id to the irq we are interested in for scanout-done */
+static const uint32_t id2irq[] = {
+		[OMAP_DSS_GFX]    = DISPC_IRQ_GFX_END_WIN,
+		[OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_END_WIN,
+		[OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_END_WIN,
+		[OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_END_WIN,
+};
+
+static void dispc_isr(void *arg, uint32_t mask)
+{
+	struct drm_plane *plane = arg;
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+	struct omap_drm_private *priv = plane->dev->dev_private;
+
+	omap_dispc_unregister_isr(dispc_isr, plane,
+			id2irq[omap_plane->ovl->id]);
+
+	queue_work(priv->wq, &omap_plane->work);
+}
+
+static void unpin_worker(struct work_struct *work)
+{
+	struct omap_plane *omap_plane =
+			container_of(work, struct omap_plane, work);
+	struct callback endwin;
+
+	mutex_lock(&omap_plane->unpin_mutex);
+	DBG("unpinning %d of %d", omap_plane->num_unpins,
+			omap_plane->num_unpins + omap_plane->pending_num_unpins);
+	while (omap_plane->num_unpins > 0) {
+		struct drm_gem_object *bo = NULL;
+		int ret = kfifo_get(&omap_plane->unpin_fifo, &bo);
+		WARN_ON(!ret);
+		omap_gem_put_paddr(bo);
+		drm_gem_object_unreference_unlocked(bo);
+		omap_plane->num_unpins--;
+	}
+	endwin = omap_plane->endwin;
+	omap_plane->endwin.fxn = NULL;
+	mutex_unlock(&omap_plane->unpin_mutex);
+
+	if (endwin.fxn)
+		endwin.fxn(endwin.arg);
+}
+
+static void install_irq(struct drm_plane *plane)
+{
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+	struct omap_overlay *ovl = omap_plane->ovl;
+	int ret;
+
+	ret = omap_dispc_register_isr(dispc_isr, plane, id2irq[ovl->id]);
+
+	/*
+	 * omapdss has upper limit on # of registered irq handlers,
+	 * which we shouldn't hit.. but if we do the limit should
+	 * be raised or bad things happen:
+	 */
+	WARN_ON(ret == -EBUSY);
+}
 
 /* push changes down to dss2 */
 static int commit(struct drm_plane *plane)
@@ -71,6 +154,11 @@
 		return ret;
 	}
 
+	mutex_lock(&omap_plane->unpin_mutex);
+	omap_plane->num_unpins += omap_plane->pending_num_unpins;
+	omap_plane->pending_num_unpins = 0;
+	mutex_unlock(&omap_plane->unpin_mutex);
+
 	/* our encoder doesn't necessarily get a commit() after this, in
 	 * particular in the dpms() and mode_set_base() cases, so force the
 	 * manager to update:
@@ -83,8 +171,20 @@
 			dev_err(dev->dev, "could not apply settings\n");
 			return ret;
 		}
+
+		/*
+		 * NOTE: really this should be atomic w/ mgr->apply() but
+		 * omapdss does not expose such an API
+		 */
+		if (omap_plane->num_unpins > 0)
+			install_irq(plane);
+
+	} else {
+		struct omap_drm_private *priv = dev->dev_private;
+		queue_work(priv->wq, &omap_plane->work);
 	}
 
+
 	if (ovl->is_enabled(ovl)) {
 		omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
 				info->out_width, info->out_height);
@@ -137,21 +237,48 @@
 	}
 }
 
+static void unpin(void *arg, struct drm_gem_object *bo)
+{
+	struct drm_plane *plane = arg;
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+
+	if (kfifo_put(&omap_plane->unpin_fifo,
+			(const struct drm_gem_object **)&bo)) {
+		omap_plane->pending_num_unpins++;
+		/* also hold a ref so it isn't free'd while pinned */
+		drm_gem_object_reference(bo);
+	} else {
+		dev_err(plane->dev->dev, "unpin fifo full!\n");
+		omap_gem_put_paddr(bo);
+	}
+}
+
 /* update which fb (if any) is pinned for scanout */
 static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb)
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
-	int ret = 0;
+	struct drm_framebuffer *pinned_fb = omap_plane->pinned_fb;
 
-	if (omap_plane->pinned_fb != fb) {
-		if (omap_plane->pinned_fb)
-			omap_framebuffer_unpin(omap_plane->pinned_fb);
+	if (pinned_fb != fb) {
+		int ret;
+
+		DBG("%p -> %p", pinned_fb, fb);
+
+		mutex_lock(&omap_plane->unpin_mutex);
+		ret = omap_framebuffer_replace(pinned_fb, fb, plane, unpin);
+		mutex_unlock(&omap_plane->unpin_mutex);
+
+		if (ret) {
+			dev_err(plane->dev->dev, "could not swap %p -> %p\n",
+					omap_plane->pinned_fb, fb);
+			omap_plane->pinned_fb = NULL;
+			return ret;
+		}
+
 		omap_plane->pinned_fb = fb;
-		if (fb)
-			ret = omap_framebuffer_pin(fb);
 	}
 
-	return ret;
+	return 0;
 }
 
 /* update parameters that are dependent on the framebuffer dimensions and
@@ -241,6 +368,8 @@
 	DBG("%s", omap_plane->ovl->name);
 	omap_plane_disable(plane);
 	drm_plane_cleanup(plane);
+	WARN_ON(omap_plane->pending_num_unpins + omap_plane->num_unpins > 0);
+	kfifo_free(&omap_plane->unpin_fifo);
 	kfree(omap_plane);
 }
 
@@ -258,37 +387,34 @@
 		if (!r)
 			r = ovl->enable(ovl);
 	} else {
+		struct omap_drm_private *priv = plane->dev->dev_private;
 		r = ovl->disable(ovl);
 		update_pin(plane, NULL);
+		queue_work(priv->wq, &omap_plane->work);
 	}
 
 	return r;
 }
 
+void omap_plane_on_endwin(struct drm_plane *plane,
+		void (*fxn)(void *), void *arg)
+{
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+
+	mutex_lock(&omap_plane->unpin_mutex);
+	omap_plane->endwin.fxn = fxn;
+	omap_plane->endwin.arg = arg;
+	mutex_unlock(&omap_plane->unpin_mutex);
+
+	install_irq(plane);
+}
+
 static const struct drm_plane_funcs omap_plane_funcs = {
 		.update_plane = omap_plane_update,
 		.disable_plane = omap_plane_disable,
 		.destroy = omap_plane_destroy,
 };
 
-static const uint32_t formats[] = {
-		DRM_FORMAT_RGB565,
-		DRM_FORMAT_RGBX4444,
-		DRM_FORMAT_XRGB4444,
-		DRM_FORMAT_RGBA4444,
-		DRM_FORMAT_ABGR4444,
-		DRM_FORMAT_XRGB1555,
-		DRM_FORMAT_ARGB1555,
-		DRM_FORMAT_RGB888,
-		DRM_FORMAT_RGBX8888,
-		DRM_FORMAT_XRGB8888,
-		DRM_FORMAT_RGBA8888,
-		DRM_FORMAT_ARGB8888,
-		DRM_FORMAT_NV12,
-		DRM_FORMAT_YUYV,
-		DRM_FORMAT_UYVY,
-};
-
 /* initialize plane */
 struct drm_plane *omap_plane_init(struct drm_device *dev,
 		struct omap_overlay *ovl, unsigned int possible_crtcs,
@@ -296,21 +422,38 @@
 {
 	struct drm_plane *plane = NULL;
 	struct omap_plane *omap_plane;
+	int ret;
 
 	DBG("%s: possible_crtcs=%08x, priv=%d", ovl->name,
 			possible_crtcs, priv);
 
+	/* friendly reminder to update table for future hw: */
+	WARN_ON(ovl->id >= ARRAY_SIZE(id2irq));
+
 	omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
 	if (!omap_plane) {
 		dev_err(dev->dev, "could not allocate plane\n");
 		goto fail;
 	}
 
+	mutex_init(&omap_plane->unpin_mutex);
+
+	ret = kfifo_alloc(&omap_plane->unpin_fifo, 16, GFP_KERNEL);
+	if (ret) {
+		dev_err(dev->dev, "could not allocate unpin FIFO\n");
+		goto fail;
+	}
+
+	INIT_WORK(&omap_plane->work, unpin_worker);
+
+	omap_plane->nformats = omap_framebuffer_get_formats(
+			omap_plane->formats, ARRAY_SIZE(omap_plane->formats),
+			ovl->supported_modes);
 	omap_plane->ovl = ovl;
 	plane = &omap_plane->base;
 
 	drm_plane_init(dev, plane, possible_crtcs, &omap_plane_funcs,
-			formats, ARRAY_SIZE(formats), priv);
+			omap_plane->formats, omap_plane->nformats, priv);
 
 	/* get our starting configuration, set defaults for parameters
 	 * we don't currently use, etc:
@@ -330,7 +473,7 @@
 	if (priv)
 		omap_plane->info.zorder = 0;
 	else
-		omap_plane->info.zorder = 1;
+		omap_plane->info.zorder = ovl->id;
 
 	update_manager(plane);
 
diff --git a/drivers/staging/ozwpan/Kbuild b/drivers/staging/ozwpan/Kbuild
new file mode 100644
index 0000000..6cc84cb
--- /dev/null
+++ b/drivers/staging/ozwpan/Kbuild
@@ -0,0 +1,19 @@
+# -----------------------------------------------------------------------------
+# Copyright (c) 2011 Ozmo Inc
+# Released under the GNU General Public License Version 2 (GPLv2).
+# -----------------------------------------------------------------------------
+obj-$(CONFIG_USB_WPAN_HCD) += ozwpan.o
+ozwpan-y := \
+	ozmain.o \
+	ozpd.o \
+	ozusbsvc.o \
+	ozusbsvc1.o \
+	ozhcd.o \
+	ozeltbuf.o \
+	ozproto.o \
+	ozcdev.o \
+	ozurbparanoia.o \
+	oztrace.o \
+	ozevent.o
+
+
diff --git a/drivers/staging/ozwpan/Kconfig b/drivers/staging/ozwpan/Kconfig
new file mode 100644
index 0000000..7904cae
--- /dev/null
+++ b/drivers/staging/ozwpan/Kconfig
@@ -0,0 +1,9 @@
+config USB_WPAN_HCD
+	tristate "USB over WiFi Host Controller"
+	depends on USB && NET
+	help
+	  A driver for USB Host Controllers that are compatible with
+	  Ozmo Devices USB over WiFi technology.
+
+	  To compile this driver a module, choose M here: the module
+	  will be called "ozwpan".
diff --git a/drivers/staging/ozwpan/README b/drivers/staging/ozwpan/README
new file mode 100644
index 0000000..bb1a69b
--- /dev/null
+++ b/drivers/staging/ozwpan/README
@@ -0,0 +1,25 @@
+OZWPAN USB Host Controller Driver
+---------------------------------
+This driver is a USB HCD driver that does not have an associated a physical
+device but instead uses Wi-Fi to communicate with the wireless peripheral.
+The USB requests are converted into a layer 2 network protocol and transmitted
+on the network using an ethertype (0x892e) regestered to Ozmo Device Inc.
+This driver is compatible with existing wireless devices that use Ozmo Devices
+technology.
+
+To operate the driver must be bound to a suitable network interface. This can
+be done when the module is loaded (specifying the name of the network interface
+as a paramter - e.g. 'insmod ozwpan g_net_dev=go0') or can be bound after
+loading using an ioctl call. See the ozappif.h file and the ioctls
+OZ_IOCTL_ADD_BINDING and OZ_IOCTL_REMOVE_BINDING.
+
+The devices connect to the host use Wi-Fi Direct so a network card that supports
+Wi-Fi direct is required. A recent version (0.8.x or later) version of the
+wpa_supplicant can be used to setup the network interface to create a persistent
+autonomous group (for older pre-WFD peripherals) or put in a listen state to
+allow group negotiation to occur for more recent devices that support WFD.
+
+The protocol used over the network does not directly mimic the USB bus
+transactions as this would be rather busy and inefficient. Instead the chapter 9
+requests are converted into a request/response pair of messages. (See
+ozprotocol.h for data structures used in the protocol).
diff --git a/drivers/staging/ozwpan/TODO b/drivers/staging/ozwpan/TODO
new file mode 100644
index 0000000..f7a9c12
--- /dev/null
+++ b/drivers/staging/ozwpan/TODO
@@ -0,0 +1,12 @@
+TODO:
+	- review user mode interface and determine if ioctls can be replaced
+	  with something better. correctly export data structures to user mode
+	  if ioctls are still required and allocate ioctl numbers from
+	  ioctl-number.txt.
+	- check USB HCD implementation is complete and correct.
+	- remove any debug and trace code.
+	- code review by USB developer community.
+	- testing with as many devices as possible.
+
+Please send any patches for this driver to Chris Kelly <ckelly@ozmodevices.com>
+and Greg Kroah-Hartman <gregkh@linuxfoundation.org>.
diff --git a/drivers/staging/ozwpan/ozappif.h b/drivers/staging/ozwpan/ozappif.h
new file mode 100644
index 0000000..af02732
--- /dev/null
+++ b/drivers/staging/ozwpan/ozappif.h
@@ -0,0 +1,46 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#ifndef _OZAPPIF_H
+#define _OZAPPIF_H
+
+#include "ozeventdef.h"
+
+#define OZ_IOCTL_MAGIC	0xf4
+
+struct oz_mac_addr {
+	unsigned char a[6];
+};
+
+#define OZ_MAX_PDS	8
+
+struct oz_pd_list {
+	int count;
+	struct oz_mac_addr addr[OZ_MAX_PDS];
+};
+
+#define OZ_MAX_BINDING_LEN	32
+
+struct oz_binding_info {
+	char name[OZ_MAX_BINDING_LEN];
+};
+
+struct oz_test {
+	int action;
+};
+
+#define OZ_IOCTL_GET_PD_LIST	_IOR(OZ_IOCTL_MAGIC, 0, struct oz_pd_list)
+#define OZ_IOCTL_SET_ACTIVE_PD	_IOW(OZ_IOCTL_MAGIC, 1, struct oz_mac_addr)
+#define OZ_IOCTL_GET_ACTIVE_PD	_IOR(OZ_IOCTL_MAGIC, 2, struct oz_mac_addr)
+#define OZ_IOCTL_CLEAR_EVENTS	_IO(OZ_IOCTL_MAGIC, 3)
+#define OZ_IOCTL_GET_EVENTS	_IOR(OZ_IOCTL_MAGIC, 4, struct oz_evtlist)
+#define OZ_IOCTL_ADD_BINDING	_IOW(OZ_IOCTL_MAGIC, 5, struct oz_binding_info)
+#define OZ_IOCTL_TEST		_IOWR(OZ_IOCTL_MAGIC, 6, struct oz_test)
+#define OZ_IOCTL_SET_EVENT_MASK	_IOW(OZ_IOCTL_MAGIC, 7, unsigned long)
+#define OZ_IOCTL_REMOVE_BINDING	_IOW(OZ_IOCTL_MAGIC, 8, struct oz_binding_info)
+#define OZ_IOCTL_MAX		9
+
+
+#endif /* _OZAPPIF_H */
diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c
new file mode 100644
index 0000000..1c380d6
--- /dev/null
+++ b/drivers/staging/ozwpan/ozcdev.c
@@ -0,0 +1,521 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+#include <linux/netdevice.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include "ozconfig.h"
+#include "ozprotocol.h"
+#include "oztrace.h"
+#include "ozappif.h"
+#include "ozeltbuf.h"
+#include "ozpd.h"
+#include "ozproto.h"
+#include "ozevent.h"
+/*------------------------------------------------------------------------------
+ */
+#define OZ_RD_BUF_SZ	256
+struct oz_cdev {
+	dev_t devnum;
+	struct cdev cdev;
+	wait_queue_head_t rdq;
+	spinlock_t lock;
+	u8 active_addr[ETH_ALEN];
+	struct oz_pd *active_pd;
+};
+
+/* Per PD context for the serial service stored in the PD. */
+struct oz_serial_ctx {
+	atomic_t ref_count;
+	u8 tx_seq_num;
+	u8 rx_seq_num;
+	u8 rd_buf[OZ_RD_BUF_SZ];
+	int rd_in;
+	int rd_out;
+};
+/*------------------------------------------------------------------------------
+ */
+int g_taction;
+/*------------------------------------------------------------------------------
+ */
+static struct oz_cdev g_cdev;
+/*------------------------------------------------------------------------------
+ * Context: process and softirq
+ */
+static struct oz_serial_ctx *oz_cdev_claim_ctx(struct oz_pd *pd)
+{
+	struct oz_serial_ctx *ctx;
+	spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]);
+	ctx = (struct oz_serial_ctx *)pd->app_ctx[OZ_APPID_SERIAL-1];
+	if (ctx)
+		atomic_inc(&ctx->ref_count);
+	spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]);
+	return ctx;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+static void oz_cdev_release_ctx(struct oz_serial_ctx *ctx)
+{
+	if (atomic_dec_and_test(&ctx->ref_count)) {
+		oz_trace("Dealloc serial context.\n");
+		kfree(ctx);
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_cdev_open(struct inode *inode, struct file *filp)
+{
+	struct oz_cdev *dev;
+	oz_trace("oz_cdev_open()\n");
+	oz_trace("major = %d minor = %d\n", imajor(inode), iminor(inode));
+	dev = container_of(inode->i_cdev, struct oz_cdev, cdev);
+	filp->private_data = dev;
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_cdev_release(struct inode *inode, struct file *filp)
+{
+	oz_trace("oz_cdev_release()\n");
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+ssize_t oz_cdev_read(struct file *filp, char __user *buf, size_t count,
+		loff_t *fpos)
+{
+	int n;
+	int ix;
+
+	struct oz_pd *pd;
+	struct oz_serial_ctx *ctx = 0;
+
+	spin_lock_bh(&g_cdev.lock);
+	pd = g_cdev.active_pd;
+	if (pd)
+		oz_pd_get(pd);
+	spin_unlock_bh(&g_cdev.lock);
+	if (pd == 0)
+		return -1;
+	ctx = oz_cdev_claim_ctx(pd);
+	if (ctx == 0)
+		goto out2;
+	n = ctx->rd_in - ctx->rd_out;
+	if (n < 0)
+		n += OZ_RD_BUF_SZ;
+	if (count > n)
+		count = n;
+	ix = ctx->rd_out;
+	n = OZ_RD_BUF_SZ - ix;
+	if (n > count)
+		n = count;
+	if (copy_to_user(buf, &ctx->rd_buf[ix], n)) {
+		count = 0;
+		goto out1;
+	}
+	ix += n;
+	if (ix == OZ_RD_BUF_SZ)
+		ix = 0;
+	if (n < count) {
+		if (copy_to_user(&buf[n], ctx->rd_buf, count-n)) {
+			count = 0;
+			goto out1;
+		}
+		ix = count-n;
+	}
+	ctx->rd_out = ix;
+out1:
+	oz_cdev_release_ctx(ctx);
+out2:
+	oz_pd_put(pd);
+	return count;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+ssize_t oz_cdev_write(struct file *filp, const char __user *buf, size_t count,
+		loff_t *fpos)
+{
+	struct oz_pd *pd;
+	struct oz_elt_buf *eb;
+	struct oz_elt_info *ei = 0;
+	struct oz_elt *elt;
+	struct oz_app_hdr *app_hdr;
+	struct oz_serial_ctx *ctx;
+
+	spin_lock_bh(&g_cdev.lock);
+	pd = g_cdev.active_pd;
+	if (pd)
+		oz_pd_get(pd);
+	spin_unlock_bh(&g_cdev.lock);
+	if (pd == 0)
+		return -1;
+	eb = &pd->elt_buff;
+	ei = oz_elt_info_alloc(eb);
+	if (ei == 0) {
+		count = 0;
+		goto out;
+	}
+	elt = (struct oz_elt *)ei->data;
+	app_hdr = (struct oz_app_hdr *)(elt+1);
+	elt->length = sizeof(struct oz_app_hdr) + count;
+	elt->type = OZ_ELT_APP_DATA;
+	ei->app_id = OZ_APPID_SERIAL;
+	ei->length = elt->length + sizeof(struct oz_elt);
+	app_hdr->app_id = OZ_APPID_SERIAL;
+	if (copy_from_user(app_hdr+1, buf, count))
+		goto out;
+	spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
+	ctx = (struct oz_serial_ctx *)pd->app_ctx[OZ_APPID_SERIAL-1];
+	if (ctx) {
+		app_hdr->elt_seq_num = ctx->tx_seq_num++;
+		if (ctx->tx_seq_num == 0)
+			ctx->tx_seq_num = 1;
+		spin_lock(&eb->lock);
+		if (oz_queue_elt_info(eb, 0, 0, ei) == 0)
+			ei = 0;
+		spin_unlock(&eb->lock);
+	}
+	spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
+out:
+	if (ei) {
+		count = 0;
+		spin_lock_bh(&eb->lock);
+		oz_elt_info_free(eb, ei);
+		spin_unlock_bh(&eb->lock);
+	}
+	oz_pd_put(pd);
+	return count;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+static int oz_set_active_pd(u8 *addr)
+{
+	int rc = 0;
+	struct oz_pd *pd;
+	struct oz_pd *old_pd;
+	pd = oz_pd_find(addr);
+	if (pd) {
+		spin_lock_bh(&g_cdev.lock);
+		memcpy(g_cdev.active_addr, addr, ETH_ALEN);
+		old_pd = g_cdev.active_pd;
+		g_cdev.active_pd = pd;
+		spin_unlock_bh(&g_cdev.lock);
+		if (old_pd)
+			oz_pd_put(old_pd);
+	} else {
+		if (!memcmp(addr, "\0\0\0\0\0\0", sizeof(addr))) {
+			spin_lock_bh(&g_cdev.lock);
+			pd = g_cdev.active_pd;
+			g_cdev.active_pd = 0;
+			memset(g_cdev.active_addr, 0,
+				sizeof(g_cdev.active_addr));
+			spin_unlock_bh(&g_cdev.lock);
+			if (pd)
+				oz_pd_put(pd);
+		} else {
+			rc = -1;
+		}
+	}
+	return rc;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+long oz_cdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	int rc = 0;
+	if (_IOC_TYPE(cmd) != OZ_IOCTL_MAGIC)
+		return -ENOTTY;
+	if (_IOC_NR(cmd) > OZ_IOCTL_MAX)
+		return -ENOTTY;
+	if (_IOC_DIR(cmd) & _IOC_READ)
+		rc = !access_ok(VERIFY_WRITE, (void __user *)arg,
+			_IOC_SIZE(cmd));
+	else if (_IOC_DIR(cmd) & _IOC_WRITE)
+		rc = !access_ok(VERIFY_READ, (void __user *)arg,
+			_IOC_SIZE(cmd));
+	if (rc)
+		return -EFAULT;
+	switch (cmd) {
+	case OZ_IOCTL_GET_PD_LIST: {
+			struct oz_pd_list list;
+			oz_trace("OZ_IOCTL_GET_PD_LIST\n");
+			list.count = oz_get_pd_list(list.addr, OZ_MAX_PDS);
+			if (copy_to_user((void __user *)arg, &list,
+				sizeof(list)))
+				return -EFAULT;
+		}
+		break;
+	case OZ_IOCTL_SET_ACTIVE_PD: {
+			u8 addr[ETH_ALEN];
+			oz_trace("OZ_IOCTL_SET_ACTIVE_PD\n");
+			if (copy_from_user(addr, (void __user *)arg, ETH_ALEN))
+				return -EFAULT;
+			rc = oz_set_active_pd(addr);
+		}
+		break;
+	case OZ_IOCTL_GET_ACTIVE_PD: {
+			u8 addr[ETH_ALEN];
+			oz_trace("OZ_IOCTL_GET_ACTIVE_PD\n");
+			spin_lock_bh(&g_cdev.lock);
+			memcpy(addr, g_cdev.active_addr, ETH_ALEN);
+			spin_unlock_bh(&g_cdev.lock);
+			if (copy_to_user((void __user *)arg, addr, ETH_ALEN))
+				return -EFAULT;
+		}
+		break;
+#ifdef WANT_EVENT_TRACE
+	case OZ_IOCTL_CLEAR_EVENTS:
+		oz_events_clear();
+		break;
+	case OZ_IOCTL_GET_EVENTS:
+		rc = oz_events_copy((void __user *)arg);
+		break;
+	case OZ_IOCTL_SET_EVENT_MASK:
+		if (copy_from_user(&g_evt_mask, (void __user *)arg,
+			sizeof(unsigned long))) {
+			return -EFAULT;
+		}
+		break;
+#endif /* WANT_EVENT_TRACE */
+	case OZ_IOCTL_ADD_BINDING:
+	case OZ_IOCTL_REMOVE_BINDING: {
+			struct oz_binding_info b;
+			if (copy_from_user(&b, (void __user *)arg,
+				sizeof(struct oz_binding_info))) {
+				return -EFAULT;
+			}
+			/* Make sure name is null terminated. */
+			b.name[OZ_MAX_BINDING_LEN-1] = 0;
+			if (cmd == OZ_IOCTL_ADD_BINDING)
+				oz_binding_add(b.name);
+			else
+				oz_binding_remove(b.name);
+		}
+		break;
+	}
+	return rc;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+unsigned int oz_cdev_poll(struct file *filp, poll_table *wait)
+{
+	unsigned int ret = 0;
+	struct oz_cdev *dev = filp->private_data;
+	oz_trace("Poll called wait = %p\n", wait);
+	spin_lock_bh(&dev->lock);
+	if (dev->active_pd) {
+		struct oz_serial_ctx *ctx = oz_cdev_claim_ctx(dev->active_pd);
+		if (ctx) {
+			if (ctx->rd_in != ctx->rd_out)
+				ret |= POLLIN | POLLRDNORM;
+			oz_cdev_release_ctx(ctx);
+		}
+	}
+	spin_unlock_bh(&dev->lock);
+	if (wait)
+		poll_wait(filp, &dev->rdq, wait);
+	return ret;
+}
+/*------------------------------------------------------------------------------
+ */
+const struct file_operations oz_fops = {
+	.owner =	THIS_MODULE,
+	.open =		oz_cdev_open,
+	.release =	oz_cdev_release,
+	.read =		oz_cdev_read,
+	.write =	oz_cdev_write,
+	.unlocked_ioctl = oz_cdev_ioctl,
+	.poll =		oz_cdev_poll
+};
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_cdev_register(void)
+{
+	int err;
+	memset(&g_cdev, 0, sizeof(g_cdev));
+	err = alloc_chrdev_region(&g_cdev.devnum, 0, 1, "ozwpan");
+	if (err < 0)
+		return err;
+	oz_trace("Alloc dev number %d:%d\n", MAJOR(g_cdev.devnum),
+			MINOR(g_cdev.devnum));
+	cdev_init(&g_cdev.cdev, &oz_fops);
+	g_cdev.cdev.owner = THIS_MODULE;
+	g_cdev.cdev.ops = &oz_fops;
+	spin_lock_init(&g_cdev.lock);
+	init_waitqueue_head(&g_cdev.rdq);
+	err = cdev_add(&g_cdev.cdev, g_cdev.devnum, 1);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_cdev_deregister(void)
+{
+	cdev_del(&g_cdev.cdev);
+	unregister_chrdev_region(g_cdev.devnum, 1);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_cdev_init(void)
+{
+	oz_event_log(OZ_EVT_SERVICE, 1, OZ_APPID_SERIAL, 0, 0);
+	oz_app_enable(OZ_APPID_SERIAL, 1);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_cdev_term(void)
+{
+	oz_event_log(OZ_EVT_SERVICE, 2, OZ_APPID_SERIAL, 0, 0);
+	oz_app_enable(OZ_APPID_SERIAL, 0);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+int oz_cdev_start(struct oz_pd *pd, int resume)
+{
+	struct oz_serial_ctx *ctx;
+	struct oz_serial_ctx *old_ctx = 0;
+	oz_event_log(OZ_EVT_SERVICE, 3, OZ_APPID_SERIAL, 0, resume);
+	if (resume) {
+		oz_trace("Serial service resumed.\n");
+		return 0;
+	}
+	ctx = kzalloc(sizeof(struct oz_serial_ctx), GFP_ATOMIC);
+	if (ctx == 0)
+		return -ENOMEM;
+	atomic_set(&ctx->ref_count, 1);
+	ctx->tx_seq_num = 1;
+	spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]);
+	old_ctx = pd->app_ctx[OZ_APPID_SERIAL-1];
+	if (old_ctx) {
+		spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]);
+		kfree(ctx);
+	} else {
+		pd->app_ctx[OZ_APPID_SERIAL-1] = ctx;
+		spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]);
+	}
+	spin_lock(&g_cdev.lock);
+	if ((g_cdev.active_pd == 0) &&
+		(memcmp(pd->mac_addr, g_cdev.active_addr, ETH_ALEN) == 0)) {
+		oz_pd_get(pd);
+		g_cdev.active_pd = pd;
+		oz_trace("Active PD arrived.\n");
+	}
+	spin_unlock(&g_cdev.lock);
+	oz_trace("Serial service started.\n");
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+void oz_cdev_stop(struct oz_pd *pd, int pause)
+{
+	struct oz_serial_ctx *ctx;
+	oz_event_log(OZ_EVT_SERVICE, 4, OZ_APPID_SERIAL, 0, pause);
+	if (pause) {
+		oz_trace("Serial service paused.\n");
+		return;
+	}
+	spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]);
+	ctx = (struct oz_serial_ctx *)pd->app_ctx[OZ_APPID_SERIAL-1];
+	pd->app_ctx[OZ_APPID_SERIAL-1] = 0;
+	spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]);
+	if (ctx)
+		oz_cdev_release_ctx(ctx);
+	spin_lock(&g_cdev.lock);
+	if (pd == g_cdev.active_pd)
+		g_cdev.active_pd = 0;
+	else
+		pd = 0;
+	spin_unlock(&g_cdev.lock);
+	if (pd) {
+		oz_pd_put(pd);
+		oz_trace("Active PD departed.\n");
+	}
+	oz_trace("Serial service stopped.\n");
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt)
+{
+	struct oz_serial_ctx *ctx;
+	struct oz_app_hdr *app_hdr;
+	u8 *data;
+	int len;
+	int space;
+	int copy_sz;
+	int ix;
+
+	ctx = oz_cdev_claim_ctx(pd);
+	if (ctx == 0) {
+		oz_trace("Cannot claim serial context.\n");
+		return;
+	}
+
+	app_hdr = (struct oz_app_hdr *)(elt+1);
+	/* If sequence number is non-zero then check it is not a duplicate.
+	 */
+	if (app_hdr->elt_seq_num != 0) {
+		if (((ctx->rx_seq_num - app_hdr->elt_seq_num) & 0x80) == 0) {
+			/* Reject duplicate element. */
+			oz_trace("Duplicate element:%02x %02x\n",
+				app_hdr->elt_seq_num, ctx->rx_seq_num);
+			goto out;
+		}
+	}
+	ctx->rx_seq_num = app_hdr->elt_seq_num;
+	len = elt->length - sizeof(struct oz_app_hdr);
+	data = ((u8 *)(elt+1)) + sizeof(struct oz_app_hdr);
+	if (len <= 0)
+		goto out;
+	space = ctx->rd_out - ctx->rd_in - 1;
+	if (space < 0)
+		space += OZ_RD_BUF_SZ;
+	if (len > space) {
+		oz_trace("Not enough space:%d %d\n", len, space);
+		len = space;
+	}
+	ix = ctx->rd_in;
+	copy_sz = OZ_RD_BUF_SZ - ix;
+	if (copy_sz > len)
+		copy_sz = len;
+	memcpy(&ctx->rd_buf[ix], data, copy_sz);
+	len -= copy_sz;
+	ix += copy_sz;
+	if (ix == OZ_RD_BUF_SZ)
+		ix = 0;
+	if (len) {
+		memcpy(ctx->rd_buf, data+copy_sz, len);
+		ix = len;
+	}
+	ctx->rd_in = ix;
+	wake_up(&g_cdev.rdq);
+out:
+	oz_cdev_release_ctx(ctx);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+void oz_cdev_heartbeat(struct oz_pd *pd)
+{
+}
diff --git a/drivers/staging/ozwpan/ozcdev.h b/drivers/staging/ozwpan/ozcdev.h
new file mode 100644
index 0000000..698014b
--- /dev/null
+++ b/drivers/staging/ozwpan/ozcdev.h
@@ -0,0 +1,18 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#ifndef _OZCDEV_H
+#define _OZCDEV_H
+
+int oz_cdev_register(void);
+int oz_cdev_deregister(void);
+int oz_cdev_init(void);
+void oz_cdev_term(void);
+int oz_cdev_start(struct oz_pd *pd, int resume);
+void oz_cdev_stop(struct oz_pd *pd, int pause);
+void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt);
+void oz_cdev_heartbeat(struct oz_pd *pd);
+
+#endif /* _OZCDEV_H */
diff --git a/drivers/staging/ozwpan/ozconfig.h b/drivers/staging/ozwpan/ozconfig.h
new file mode 100644
index 0000000..43e6373
--- /dev/null
+++ b/drivers/staging/ozwpan/ozconfig.h
@@ -0,0 +1,27 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * ---------------------------------------------------------------------------*/
+#ifndef _OZCONFIG_H
+#define _OZCONFIG_H
+
+/* #define WANT_TRACE */
+#ifdef WANT_TRACE
+#define WANT_VERBOSE_TRACE
+#endif /* #ifdef WANT_TRACE */
+/* #define WANT_URB_PARANOIA */
+
+/* #define WANT_PRE_2_6_39 */
+#define WANT_EVENT_TRACE
+
+/* These defines determine what verbose trace is displayed. */
+#ifdef WANT_VERBOSE_TRACE
+/* #define WANT_TRACE_STREAM */
+/* #define WANT_TRACE_URB */
+/* #define WANT_TRACE_CTRL_DETAIL */
+#define WANT_TRACE_HUB
+/* #define WANT_TRACE_RX_FRAMES */
+/* #define WANT_TRACE_TX_FRAMES */
+#endif /* WANT_VERBOSE_TRACE */
+
+#endif /* _OZCONFIG_H */
diff --git a/drivers/staging/ozwpan/ozeltbuf.c b/drivers/staging/ozwpan/ozeltbuf.c
new file mode 100644
index 0000000..988f522
--- /dev/null
+++ b/drivers/staging/ozwpan/ozeltbuf.c
@@ -0,0 +1,339 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include "ozconfig.h"
+#include "ozprotocol.h"
+#include "ozeltbuf.h"
+#include "ozpd.h"
+#include "oztrace.h"
+/*------------------------------------------------------------------------------
+ */
+#define OZ_ELT_INFO_MAGIC_USED	0x35791057
+#define OZ_ELT_INFO_MAGIC_FREE	0x78940102
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+int oz_elt_buf_init(struct oz_elt_buf *buf)
+{
+	memset(buf, 0, sizeof(struct oz_elt_buf));
+	INIT_LIST_HEAD(&buf->stream_list);
+	INIT_LIST_HEAD(&buf->order_list);
+	INIT_LIST_HEAD(&buf->isoc_list);
+	buf->max_free_elts = 32;
+	spin_lock_init(&buf->lock);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+void oz_elt_buf_term(struct oz_elt_buf *buf)
+{
+	struct list_head *e;
+	int i;
+	/* Free any elements in the order or isoc lists. */
+	for (i = 0; i < 2; i++) {
+		struct list_head *list;
+		if (i)
+			list = &buf->order_list;
+		else
+			list = &buf->isoc_list;
+		e = list->next;
+		while (e != list) {
+			struct oz_elt_info *ei =
+				container_of(e, struct oz_elt_info, link_order);
+			e = e->next;
+			kfree(ei);
+		}
+	}
+	/* Free any elelment in the pool. */
+	while (buf->elt_pool) {
+		struct oz_elt_info *ei =
+			container_of(buf->elt_pool, struct oz_elt_info, link);
+		buf->elt_pool = buf->elt_pool->next;
+		kfree(ei);
+	}
+	buf->free_elts = 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+struct oz_elt_info *oz_elt_info_alloc(struct oz_elt_buf *buf)
+{
+	struct oz_elt_info *ei = 0;
+	spin_lock_bh(&buf->lock);
+	if (buf->free_elts && buf->elt_pool) {
+		ei = container_of(buf->elt_pool, struct oz_elt_info, link);
+		buf->elt_pool = ei->link.next;
+		buf->free_elts--;
+		spin_unlock_bh(&buf->lock);
+		if (ei->magic != OZ_ELT_INFO_MAGIC_FREE) {
+			oz_trace("oz_elt_info_alloc: ei with bad magic: 0x%x\n",
+				ei->magic);
+		}
+	} else {
+		spin_unlock_bh(&buf->lock);
+		ei = kmalloc(sizeof(struct oz_elt_info), GFP_ATOMIC);
+	}
+	if (ei) {
+		ei->flags = 0;
+		ei->app_id = 0;
+		ei->callback = 0;
+		ei->context = 0;
+		ei->stream = 0;
+		ei->magic = OZ_ELT_INFO_MAGIC_USED;
+		INIT_LIST_HEAD(&ei->link);
+		INIT_LIST_HEAD(&ei->link_order);
+	}
+	return ei;
+}
+/*------------------------------------------------------------------------------
+ * Precondition: oz_elt_buf.lock must be held.
+ * Context: softirq or process
+ */
+void oz_elt_info_free(struct oz_elt_buf *buf, struct oz_elt_info *ei)
+{
+	if (ei) {
+		if (ei->magic == OZ_ELT_INFO_MAGIC_USED) {
+			buf->free_elts++;
+			ei->link.next = buf->elt_pool;
+			buf->elt_pool = &ei->link;
+			ei->magic = OZ_ELT_INFO_MAGIC_FREE;
+		} else {
+			oz_trace("oz_elt_info_free: bad magic ei: %p"
+				" magic: 0x%x\n",
+				ei, ei->magic);
+		}
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+void oz_elt_info_free_chain(struct oz_elt_buf *buf, struct list_head *list)
+{
+	struct list_head *e;
+	e = list->next;
+	spin_lock_bh(&buf->lock);
+	while (e != list) {
+		struct oz_elt_info *ei;
+		ei = container_of(e, struct oz_elt_info, link);
+		e = e->next;
+		oz_elt_info_free(buf, ei);
+	}
+	spin_unlock_bh(&buf->lock);
+}
+/*------------------------------------------------------------------------------
+ */
+int oz_elt_stream_create(struct oz_elt_buf *buf, u8 id, int max_buf_count)
+{
+	struct oz_elt_stream *st;
+
+	oz_trace("oz_elt_stream_create(0x%x)\n", id);
+
+	st = kzalloc(sizeof(struct oz_elt_stream), GFP_ATOMIC | __GFP_ZERO);
+	if (st == 0)
+		return -ENOMEM;
+	atomic_set(&st->ref_count, 1);
+	st->id = id;
+	st->max_buf_count = max_buf_count;
+	INIT_LIST_HEAD(&st->elt_list);
+	spin_lock_bh(&buf->lock);
+	list_add_tail(&st->link, &buf->stream_list);
+	spin_unlock_bh(&buf->lock);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ */
+int oz_elt_stream_delete(struct oz_elt_buf *buf, u8 id)
+{
+	struct list_head *e;
+	struct oz_elt_stream *st;
+	oz_trace("oz_elt_stream_delete(0x%x)\n", id);
+	spin_lock_bh(&buf->lock);
+	e = buf->stream_list.next;
+	while (e != &buf->stream_list) {
+		st = container_of(e, struct oz_elt_stream, link);
+		if (st->id == id) {
+			list_del(e);
+			break;
+		}
+		st = 0;
+	}
+	if (!st) {
+		spin_unlock_bh(&buf->lock);
+		return -1;
+	}
+	e = st->elt_list.next;
+	while (e != &st->elt_list) {
+		struct oz_elt_info *ei =
+			container_of(e, struct oz_elt_info, link);
+		e = e->next;
+		list_del_init(&ei->link);
+		list_del_init(&ei->link_order);
+		st->buf_count -= ei->length;
+		oz_trace2(OZ_TRACE_STREAM, "Stream down: %d  %d %d\n",
+			st->buf_count,
+			ei->length, atomic_read(&st->ref_count));
+		oz_elt_stream_put(st);
+		oz_elt_info_free(buf, ei);
+	}
+	spin_unlock_bh(&buf->lock);
+	oz_elt_stream_put(st);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ */
+void oz_elt_stream_get(struct oz_elt_stream *st)
+{
+	atomic_inc(&st->ref_count);
+}
+/*------------------------------------------------------------------------------
+ */
+void oz_elt_stream_put(struct oz_elt_stream *st)
+{
+	if (atomic_dec_and_test(&st->ref_count)) {
+		oz_trace("Stream destroyed\n");
+		kfree(st);
+	}
+}
+/*------------------------------------------------------------------------------
+ * Precondition: Element buffer lock must be held.
+ * If this function fails the caller is responsible for deallocating the elt
+ * info structure.
+ */
+int oz_queue_elt_info(struct oz_elt_buf *buf, u8 isoc, u8 id,
+	struct oz_elt_info *ei)
+{
+	struct oz_elt_stream *st = 0;
+	struct list_head *e;
+	if (id) {
+		list_for_each(e, &buf->stream_list) {
+			st = container_of(e, struct oz_elt_stream, link);
+			if (st->id == id)
+				break;
+		}
+		if (e == &buf->stream_list) {
+			/* Stream specified but stream not known so fail.
+			 * Caller deallocates element info. */
+			return -1;
+		}
+	}
+	if (st) {
+		/* If this is an ISOC fixed element that needs a frame number
+		 * then insert that now. Earlier we stored the unit count in
+		 * this field.
+		 */
+		struct oz_isoc_fixed *body = (struct oz_isoc_fixed *)
+			&ei->data[sizeof(struct oz_elt)];
+		if ((body->app_id == OZ_APPID_USB) && (body->type
+			== OZ_USB_ENDPOINT_DATA) &&
+			(body->format == OZ_DATA_F_ISOC_FIXED)) {
+			u8 unit_count = body->frame_number;
+			body->frame_number = st->frame_number;
+			st->frame_number += unit_count;
+		}
+		/* Claim stream and update accounts */
+		oz_elt_stream_get(st);
+		ei->stream = st;
+		st->buf_count += ei->length;
+		/* Add to list in stream. */
+		list_add_tail(&ei->link, &st->elt_list);
+		oz_trace2(OZ_TRACE_STREAM, "Stream up: %d  %d\n",
+			st->buf_count, ei->length);
+		/* Check if we have too much buffered for this stream. If so
+		 * start dropping elements until we are back in bounds.
+		 */
+		while ((st->buf_count > st->max_buf_count) &&
+			!list_empty(&st->elt_list)) {
+			struct oz_elt_info *ei2 =
+				list_first_entry(&st->elt_list,
+					struct oz_elt_info, link);
+			list_del_init(&ei2->link);
+			list_del_init(&ei2->link_order);
+			st->buf_count -= ei2->length;
+			oz_elt_info_free(buf, ei2);
+			oz_elt_stream_put(st);
+		}
+	}
+	list_add_tail(&ei->link_order, isoc ?
+		&buf->isoc_list : &buf->order_list);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ */
+int oz_select_elts_for_tx(struct oz_elt_buf *buf, u8 isoc, unsigned *len,
+		unsigned max_len, struct list_head *list)
+{
+	int count = 0;
+	struct list_head *e;
+	struct list_head *el;
+	struct oz_elt_info *ei;
+	spin_lock_bh(&buf->lock);
+	if (isoc)
+		el = &buf->isoc_list;
+	else
+		el = &buf->order_list;
+	e = el->next;
+	while (e != el) {
+		struct oz_app_hdr *app_hdr;
+		ei = container_of(e, struct oz_elt_info, link_order);
+		e = e->next;
+		if ((*len + ei->length) <= max_len) {
+			app_hdr = (struct oz_app_hdr *)
+				&ei->data[sizeof(struct oz_elt)];
+			app_hdr->elt_seq_num = buf->tx_seq_num[ei->app_id]++;
+			if (buf->tx_seq_num[ei->app_id] == 0)
+				buf->tx_seq_num[ei->app_id] = 1;
+			*len += ei->length;
+			list_del(&ei->link);
+			list_del(&ei->link_order);
+			if (ei->stream) {
+				ei->stream->buf_count -= ei->length;
+				oz_trace2(OZ_TRACE_STREAM,
+					"Stream down: %d  %d\n",
+					ei->stream->buf_count, ei->length);
+				oz_elt_stream_put(ei->stream);
+				ei->stream = 0;
+			}
+			INIT_LIST_HEAD(&ei->link_order);
+			list_add_tail(&ei->link, list);
+			count++;
+		} else {
+			break;
+		}
+	}
+	spin_unlock_bh(&buf->lock);
+	return count;
+}
+/*------------------------------------------------------------------------------
+ */
+int oz_are_elts_available(struct oz_elt_buf *buf)
+{
+	return buf->order_list.next != &buf->order_list;
+}
+/*------------------------------------------------------------------------------
+ */
+void oz_trim_elt_pool(struct oz_elt_buf *buf)
+{
+	struct list_head *free = 0;
+	struct list_head *e;
+	spin_lock_bh(&buf->lock);
+	while (buf->free_elts > buf->max_free_elts) {
+		e = buf->elt_pool;
+		buf->elt_pool = e->next;
+		e->next = free;
+		free = e;
+		buf->free_elts--;
+	}
+	spin_unlock_bh(&buf->lock);
+	while (free) {
+		struct oz_elt_info *ei =
+			container_of(free, struct oz_elt_info, link);
+		free = free->next;
+		kfree(ei);
+	}
+}
diff --git a/drivers/staging/ozwpan/ozeltbuf.h b/drivers/staging/ozwpan/ozeltbuf.h
new file mode 100644
index 0000000..03c12f5
--- /dev/null
+++ b/drivers/staging/ozwpan/ozeltbuf.h
@@ -0,0 +1,70 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#ifndef _OZELTBUF_H
+#define _OZELTBUF_H
+
+#include "ozprotocol.h"
+
+/*-----------------------------------------------------------------------------
+ */
+struct oz_pd;
+typedef void (*oz_elt_callback_t)(struct oz_pd *pd, long context);
+
+struct oz_elt_stream {
+	struct list_head link;
+	struct list_head elt_list;
+	atomic_t ref_count;
+	unsigned buf_count;
+	unsigned max_buf_count;
+	u8 frame_number;
+	u8 id;
+};
+
+#define OZ_MAX_ELT_PAYLOAD	255
+struct oz_elt_info {
+	struct list_head link;
+	struct list_head link_order;
+	u8 flags;
+	u8 app_id;
+	oz_elt_callback_t callback;
+	long context;
+	struct oz_elt_stream *stream;
+	u8 data[sizeof(struct oz_elt) + OZ_MAX_ELT_PAYLOAD];
+	int length;
+	unsigned magic;
+};
+/* Flags values */
+#define OZ_EI_F_MARKED		0x1
+
+struct oz_elt_buf {
+	spinlock_t lock;
+	struct list_head stream_list;
+	struct list_head order_list;
+	struct list_head isoc_list;
+	struct list_head *elt_pool;
+	int free_elts;
+	int max_free_elts;
+	u8 tx_seq_num[OZ_NB_APPS];
+};
+
+int oz_elt_buf_init(struct oz_elt_buf *buf);
+void oz_elt_buf_term(struct oz_elt_buf *buf);
+struct oz_elt_info *oz_elt_info_alloc(struct oz_elt_buf *buf);
+void oz_elt_info_free(struct oz_elt_buf *buf, struct oz_elt_info *ei);
+void oz_elt_info_free_chain(struct oz_elt_buf *buf, struct list_head *list);
+int oz_elt_stream_create(struct oz_elt_buf *buf, u8 id, int max_buf_count);
+int oz_elt_stream_delete(struct oz_elt_buf *buf, u8 id);
+void oz_elt_stream_get(struct oz_elt_stream *st);
+void oz_elt_stream_put(struct oz_elt_stream *st);
+int oz_queue_elt_info(struct oz_elt_buf *buf, u8 isoc, u8 id,
+		struct oz_elt_info *ei);
+int oz_select_elts_for_tx(struct oz_elt_buf *buf, u8 isoc, unsigned *len,
+		unsigned max_len, struct list_head *list);
+int oz_are_elts_available(struct oz_elt_buf *buf);
+void oz_trim_elt_pool(struct oz_elt_buf *buf);
+
+#endif /* _OZELTBUF_H */
+
diff --git a/drivers/staging/ozwpan/ozevent.c b/drivers/staging/ozwpan/ozevent.c
new file mode 100644
index 0000000..73703d3
--- /dev/null
+++ b/drivers/staging/ozwpan/ozevent.c
@@ -0,0 +1,116 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#include "ozconfig.h"
+#ifdef WANT_EVENT_TRACE
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+#include "oztrace.h"
+#include "ozevent.h"
+/*------------------------------------------------------------------------------
+ */
+unsigned long g_evt_mask = 0xffffffff;
+/*------------------------------------------------------------------------------
+ */
+#define OZ_MAX_EVTS	2048	/* Must be power of 2 */
+DEFINE_SPINLOCK(g_eventlock);
+static int g_evt_in;
+static int g_evt_out;
+static int g_missed_events;
+static struct oz_event g_events[OZ_MAX_EVTS];
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_event_init(void)
+{
+	oz_trace("Event tracing initialized\n");
+	g_evt_in = g_evt_out = 0;
+	g_missed_events = 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_event_term(void)
+{
+	oz_trace("Event tracing terminated\n");
+}
+/*------------------------------------------------------------------------------
+ * Context: any
+ */
+void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4)
+{
+	unsigned long irqstate;
+	int ix;
+	spin_lock_irqsave(&g_eventlock, irqstate);
+	ix = (g_evt_in + 1) & (OZ_MAX_EVTS - 1);
+	if (ix != g_evt_out) {
+		struct oz_event *e = &g_events[g_evt_in];
+		e->jiffies = jiffies;
+		e->evt = evt;
+		e->ctx1 = ctx1;
+		e->ctx2 = ctx2;
+		e->ctx3 = ctx3;
+		e->ctx4 = ctx4;
+		g_evt_in = ix;
+	} else {
+		g_missed_events++;
+	}
+	spin_unlock_irqrestore(&g_eventlock, irqstate);
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_events_copy(struct oz_evtlist __user *lst)
+{
+	int first;
+	int ix;
+	struct hdr {
+		int count;
+		int missed;
+	} hdr;
+	ix = g_evt_out;
+	hdr.count = g_evt_in - ix;
+	if (hdr.count < 0)
+		hdr.count += OZ_MAX_EVTS;
+	if (hdr.count > OZ_EVT_LIST_SZ)
+		hdr.count = OZ_EVT_LIST_SZ;
+	hdr.missed = g_missed_events;
+	g_missed_events = 0;
+	if (copy_to_user((void __user *)lst, &hdr, sizeof(hdr)))
+		return -EFAULT;
+	first = OZ_MAX_EVTS - ix;
+	if (first > hdr.count)
+		first = hdr.count;
+	if (first) {
+		int sz = first*sizeof(struct oz_event);
+		void __user *p = (void __user *)lst->evts;
+		if (copy_to_user(p, &g_events[ix], sz))
+			return -EFAULT;
+		if (hdr.count > first) {
+			p = (void __user *)&lst->evts[first];
+			sz = (hdr.count-first)*sizeof(struct oz_event);
+			if (copy_to_user(p, g_events, sz))
+				return -EFAULT;
+		}
+	}
+	ix += hdr.count;
+	if (ix >= OZ_MAX_EVTS)
+		ix -= OZ_MAX_EVTS;
+	g_evt_out = ix;
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_events_clear(void)
+{
+	unsigned long irqstate;
+	spin_lock_irqsave(&g_eventlock, irqstate);
+	g_evt_in = g_evt_out = 0;
+	g_missed_events = 0;
+	spin_unlock_irqrestore(&g_eventlock, irqstate);
+}
+#endif /* WANT_EVENT_TRACE */
+
diff --git a/drivers/staging/ozwpan/ozevent.h b/drivers/staging/ozwpan/ozevent.h
new file mode 100644
index 0000000..f033d01
--- /dev/null
+++ b/drivers/staging/ozwpan/ozevent.h
@@ -0,0 +1,31 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#ifndef _OZEVENT_H
+#define _OZEVENT_H
+#include "ozconfig.h"
+#include "ozeventdef.h"
+
+#ifdef WANT_EVENT_TRACE
+extern unsigned long g_evt_mask;
+void oz_event_init(void);
+void oz_event_term(void);
+void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4);
+#define oz_event_log(__evt, __ctx1, __ctx2, __ctx3, __ctx4) \
+	do { \
+		if ((1<<(__evt)) & g_evt_mask) \
+			oz_event_log2(__evt, __ctx1, __ctx2, __ctx3, __ctx4); \
+	} while (0)
+int oz_events_copy(struct oz_evtlist __user *lst);
+void oz_events_clear(void);
+#else
+#define oz_event_init()
+#define oz_event_term()
+#define oz_event_log(__evt, __ctx1, __ctx2, __ctx3, __ctx4)
+#define oz_events_copy(__lst)
+#define oz_events_clear()
+#endif /* WANT_EVENT_TRACE */
+
+#endif /* _OZEVENT_H */
diff --git a/drivers/staging/ozwpan/ozeventdef.h b/drivers/staging/ozwpan/ozeventdef.h
new file mode 100644
index 0000000..a880288
--- /dev/null
+++ b/drivers/staging/ozwpan/ozeventdef.h
@@ -0,0 +1,47 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#ifndef _OZEVENTDEF_H
+#define _OZEVENTDEF_H
+
+#define OZ_EVT_RX_FRAME		0
+#define OZ_EVT_RX_PROCESS	1
+#define OZ_EVT_TX_FRAME		2
+#define OZ_EVT_TX_ISOC		3
+#define OZ_EVT_URB_SUBMIT	4
+#define OZ_EVT_URB_DONE		5
+#define OZ_EVT_URB_CANCEL	6
+#define OZ_EVT_CTRL_REQ		7
+#define OZ_EVT_CTRL_CNF		8
+#define OZ_EVT_CTRL_LOCAL	9
+#define OZ_EVT_CONNECT_REQ	10
+#define OZ_EVT_CONNECT_RSP	11
+#define OZ_EVT_EP_CREDIT	12
+#define OZ_EVT_EP_BUFFERING	13
+#define OZ_EVT_TX_ISOC_DONE	14
+#define OZ_EVT_TX_ISOC_DROP	15
+#define OZ_EVT_TIMER_CTRL	16
+#define OZ_EVT_TIMER		17
+#define OZ_EVT_PD_STATE		18
+#define OZ_EVT_SERVICE		19
+#define OZ_EVT_DEBUG		20
+
+struct oz_event {
+	unsigned long jiffies;
+	unsigned char evt;
+	unsigned char ctx1;
+	unsigned short ctx2;
+	void *ctx3;
+	unsigned ctx4;
+};
+
+#define OZ_EVT_LIST_SZ	64
+struct oz_evtlist {
+	int count;
+	int missed;
+	struct oz_event evts[OZ_EVT_LIST_SZ];
+};
+
+#endif /* _OZEVENTDEF_H */
diff --git a/drivers/staging/ozwpan/ozhcd.c b/drivers/staging/ozwpan/ozhcd.c
new file mode 100644
index 0000000..750b14e
--- /dev/null
+++ b/drivers/staging/ozwpan/ozhcd.c
@@ -0,0 +1,2256 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ *
+ * This file provides the implementation of a USB host controller device that
+ * does not have any associated hardware. Instead the virtual device is
+ * connected to the WiFi network and emulates the operation of a USB hcd by
+ * receiving and sending network frames.
+ * Note:
+ * We take great pains to reduce the amount of code where interrupts need to be
+ * disabled and in this respect we are different from standard HCD's. In
+ * particular we don't want in_irq() code bleeding over to the protocol side of
+ * the driver.
+ * The troublesome functions are the urb enqueue and dequeue functions both of
+ * which can be called in_irq(). So for these functions we put the urbs into a
+ * queue and request a tasklet to process them. This means that a spinlock with
+ * interrupts disabled must be held for insertion and removal but most code is
+ * is in tasklet or soft irq context. The lock that protects this list is called
+ * the tasklet lock and serves the purpose of the 'HCD lock' which must be held
+ * when calling the following functions.
+ *   usb_hcd_link_urb_to_ep()
+ *   usb_hcd_unlink_urb_from_ep()
+ *   usb_hcd_flush_endpoint()
+ *   usb_hcd_check_unlink_urb()
+ * -----------------------------------------------------------------------------
+ */
+#include <linux/platform_device.h>
+#include <linux/usb.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include "linux/usb/hcd.h"
+#include <asm/unaligned.h>
+#include "ozconfig.h"
+#include "ozusbif.h"
+#include "oztrace.h"
+#include "ozurbparanoia.h"
+#include "ozevent.h"
+/*------------------------------------------------------------------------------
+ * Number of units of buffering to capture for an isochronous IN endpoint before
+ * allowing data to be indicated up.
+ */
+#define OZ_IN_BUFFERING_UNITS	50
+/* Name of our platform device.
+ */
+#define OZ_PLAT_DEV_NAME	"ozwpan"
+/* Maximum number of free urb links that can be kept in the pool.
+ */
+#define OZ_MAX_LINK_POOL_SIZE	16
+/* Get endpoint object from the containing link.
+ */
+#define ep_from_link(__e) container_of((__e), struct oz_endpoint, link)
+/*------------------------------------------------------------------------------
+ * Used to link urbs together and also store some status information for each
+ * urb.
+ * A cache of these are kept in a pool to reduce number of calls to kmalloc.
+ */
+struct oz_urb_link {
+	struct list_head link;
+	struct urb *urb;
+	struct oz_port *port;
+	u8 req_id;
+	u8 ep_num;
+	unsigned long submit_jiffies;
+};
+
+/* Holds state information about a USB endpoint.
+ */
+struct oz_endpoint {
+	struct list_head urb_list;	/* List of oz_urb_link items. */
+	struct list_head link;		/* For isoc ep, links in to isoc
+					   lists of oz_port. */
+	unsigned long last_jiffies;
+	int credit;
+	int credit_ceiling;
+	u8 ep_num;
+	u8 attrib;
+	u8 *buffer;
+	int buffer_size;
+	int in_ix;
+	int out_ix;
+	int buffered_units;
+	unsigned flags;
+	int start_frame;
+};
+/* Bits in the flags field. */
+#define OZ_F_EP_BUFFERING	0x1
+#define OZ_F_EP_HAVE_STREAM	0x2
+
+/* Holds state information about a USB interface.
+ */
+struct oz_interface {
+	unsigned ep_mask;
+	u8 alt;
+};
+
+/* Holds state information about an hcd port.
+ */
+#define OZ_NB_ENDPOINTS	16
+struct oz_port {
+	unsigned flags;
+	unsigned status;
+	void *hpd;
+	struct oz_hcd *ozhcd;
+	spinlock_t port_lock;
+	u8 bus_addr;
+	u8 next_req_id;
+	u8 config_num;
+	int num_iface;
+	struct oz_interface *iface;
+	struct oz_endpoint *out_ep[OZ_NB_ENDPOINTS];
+	struct oz_endpoint *in_ep[OZ_NB_ENDPOINTS];
+	struct list_head isoc_out_ep;
+	struct list_head isoc_in_ep;
+};
+#define OZ_PORT_F_PRESENT	0x1
+#define OZ_PORT_F_CHANGED	0x2
+#define OZ_PORT_F_DYING		0x4
+
+/* Data structure in the private context area of struct usb_hcd.
+ */
+#define OZ_NB_PORTS	8
+struct oz_hcd {
+	spinlock_t hcd_lock;
+	struct list_head urb_pending_list;
+	struct list_head urb_cancel_list;
+	struct list_head orphanage;
+	int conn_port; /* Port that is currently connecting, -1 if none.*/
+	struct oz_port ports[OZ_NB_PORTS];
+	uint flags;
+	struct usb_hcd *hcd;
+};
+/* Bits in flags field.
+ */
+#define OZ_HDC_F_SUSPENDED	0x1
+
+/*------------------------------------------------------------------------------
+ * Static function prototypes.
+ */
+static int oz_hcd_start(struct usb_hcd *hcd);
+static void oz_hcd_stop(struct usb_hcd *hcd);
+static void oz_hcd_shutdown(struct usb_hcd *hcd);
+static int oz_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+				gfp_t mem_flags);
+static int oz_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
+static void oz_hcd_endpoint_disable(struct usb_hcd *hcd,
+				struct usb_host_endpoint *ep);
+static void oz_hcd_endpoint_reset(struct usb_hcd *hcd,
+				struct usb_host_endpoint *ep);
+static int oz_hcd_get_frame_number(struct usb_hcd *hcd);
+static int oz_hcd_hub_status_data(struct usb_hcd *hcd, char *buf);
+static int oz_hcd_hub_control(struct usb_hcd *hcd, u16 req_type, u16 wvalue,
+				u16 windex, char *buf, u16 wlength);
+static int oz_hcd_bus_suspend(struct usb_hcd *hcd);
+static int oz_hcd_bus_resume(struct usb_hcd *hcd);
+static int oz_plat_probe(struct platform_device *dev);
+static int oz_plat_remove(struct platform_device *dev);
+static void oz_plat_shutdown(struct platform_device *dev);
+static int oz_plat_suspend(struct platform_device *dev, pm_message_t msg);
+static int oz_plat_resume(struct platform_device *dev);
+static void oz_urb_process_tasklet(unsigned long unused);
+static int oz_build_endpoints_for_config(struct usb_hcd *hcd,
+		struct oz_port *port, struct usb_host_config *config,
+		gfp_t mem_flags);
+static void oz_clean_endpoints_for_config(struct usb_hcd *hcd,
+				struct oz_port *port);
+static int oz_build_endpoints_for_interface(struct usb_hcd *hcd,
+			struct oz_port *port,
+			struct usb_host_interface *intf, gfp_t mem_flags);
+static void oz_clean_endpoints_for_interface(struct usb_hcd *hcd,
+			struct oz_port *port, int if_ix);
+static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
+		gfp_t mem_flags);
+static struct oz_urb_link *oz_remove_urb(struct oz_endpoint *ep,
+		struct urb *urb);
+static void oz_hcd_clear_orphanage(struct oz_hcd *ozhcd, int status);
+/*------------------------------------------------------------------------------
+ * Static external variables.
+ */
+static struct platform_device *g_plat_dev;
+static struct oz_hcd *g_ozhcd;
+static DEFINE_SPINLOCK(g_hcdlock);	/* Guards g_ozhcd. */
+static const char g_hcd_name[] = "Ozmo WPAN";
+static struct list_head *g_link_pool;
+static int g_link_pool_size;
+static DEFINE_SPINLOCK(g_link_lock);
+static DEFINE_SPINLOCK(g_tasklet_lock);
+static struct tasklet_struct g_urb_process_tasklet;
+static struct tasklet_struct g_urb_cancel_tasklet;
+static atomic_t g_pending_urbs = ATOMIC_INIT(0);
+static const struct hc_driver g_oz_hc_drv = {
+	.description =		g_hcd_name,
+	.product_desc =		"Ozmo Devices WPAN",
+	.hcd_priv_size =	sizeof(struct oz_hcd),
+	.flags =		HCD_USB11,
+	.start =		oz_hcd_start,
+	.stop =			oz_hcd_stop,
+	.shutdown =		oz_hcd_shutdown,
+	.urb_enqueue =		oz_hcd_urb_enqueue,
+	.urb_dequeue =		oz_hcd_urb_dequeue,
+	.endpoint_disable =	oz_hcd_endpoint_disable,
+	.endpoint_reset =	oz_hcd_endpoint_reset,
+	.get_frame_number =	oz_hcd_get_frame_number,
+	.hub_status_data =	oz_hcd_hub_status_data,
+	.hub_control =		oz_hcd_hub_control,
+	.bus_suspend =		oz_hcd_bus_suspend,
+	.bus_resume =		oz_hcd_bus_resume,
+};
+
+static struct platform_driver g_oz_plat_drv = {
+	.probe = oz_plat_probe,
+	.remove = oz_plat_remove,
+	.shutdown = oz_plat_shutdown,
+	.suspend = oz_plat_suspend,
+	.resume = oz_plat_resume,
+	.driver = {
+		.name = OZ_PLAT_DEV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+/*------------------------------------------------------------------------------
+ * Gets our private context area (which is of type struct oz_hcd) from the
+ * usb_hcd structure.
+ * Context: any
+ */
+static inline struct oz_hcd *oz_hcd_private(struct usb_hcd *hcd)
+{
+	return (struct oz_hcd *)hcd->hcd_priv;
+}
+/*------------------------------------------------------------------------------
+ * Searches list of ports to find the index of the one with a specified  USB
+ * bus address. If none of the ports has the bus address then the connection
+ * port is returned, if there is one or -1 otherwise.
+ * Context: any
+ */
+static int oz_get_port_from_addr(struct oz_hcd *ozhcd, u8 bus_addr)
+{
+	int i;
+	for (i = 0; i < OZ_NB_PORTS; i++) {
+		if (ozhcd->ports[i].bus_addr == bus_addr)
+			return i;
+	}
+	return ozhcd->conn_port;
+}
+/*------------------------------------------------------------------------------
+ * Allocates an urb link, first trying the pool but going to heap if empty.
+ * Context: any
+ */
+static struct oz_urb_link *oz_alloc_urb_link(void)
+{
+	struct oz_urb_link *urbl = 0;
+	unsigned long irq_state;
+	spin_lock_irqsave(&g_link_lock, irq_state);
+	if (g_link_pool) {
+		urbl = container_of(g_link_pool, struct oz_urb_link, link);
+		g_link_pool = urbl->link.next;
+		--g_link_pool_size;
+	}
+	spin_unlock_irqrestore(&g_link_lock, irq_state);
+	if (urbl == 0)
+		urbl = kmalloc(sizeof(struct oz_urb_link), GFP_ATOMIC);
+	return urbl;
+}
+/*------------------------------------------------------------------------------
+ * Frees an urb link by putting it in the pool if there is enough space or
+ * deallocating it to heap otherwise.
+ * Context: any
+ */
+static void oz_free_urb_link(struct oz_urb_link *urbl)
+{
+	if (urbl) {
+		unsigned long irq_state;
+		spin_lock_irqsave(&g_link_lock, irq_state);
+		if (g_link_pool_size < OZ_MAX_LINK_POOL_SIZE) {
+			urbl->link.next = g_link_pool;
+			g_link_pool = &urbl->link;
+			urbl = 0;
+			g_link_pool_size++;
+		}
+		spin_unlock_irqrestore(&g_link_lock, irq_state);
+		if (urbl)
+			kfree(urbl);
+	}
+}
+/*------------------------------------------------------------------------------
+ * Deallocates all the urb links in the pool.
+ * Context: unknown
+ */
+static void oz_empty_link_pool(void)
+{
+	struct list_head *e;
+	unsigned long irq_state;
+	spin_lock_irqsave(&g_link_lock, irq_state);
+	e = g_link_pool;
+	g_link_pool = 0;
+	g_link_pool_size = 0;
+	spin_unlock_irqrestore(&g_link_lock, irq_state);
+	while (e) {
+		struct oz_urb_link *urbl =
+			container_of(e, struct oz_urb_link, link);
+		e = e->next;
+		kfree(urbl);
+	}
+}
+/*------------------------------------------------------------------------------
+ * Allocates endpoint structure and optionally a buffer. If a buffer is
+ * allocated it immediately follows the endpoint structure.
+ * Context: softirq
+ */
+static struct oz_endpoint *oz_ep_alloc(gfp_t mem_flags, int buffer_size)
+{
+	struct oz_endpoint *ep =
+		kzalloc(sizeof(struct oz_endpoint)+buffer_size, mem_flags);
+	if (ep) {
+		INIT_LIST_HEAD(&ep->urb_list);
+		INIT_LIST_HEAD(&ep->link);
+		ep->credit = -1;
+		if (buffer_size) {
+			ep->buffer_size = buffer_size;
+			ep->buffer = (u8 *)(ep+1);
+		}
+	}
+	return ep;
+}
+/*------------------------------------------------------------------------------
+ * Pre-condition: Must be called with g_tasklet_lock held and interrupts
+ * disabled.
+ * Context: softirq or process
+ */
+struct oz_urb_link *oz_uncancel_urb(struct oz_hcd *ozhcd, struct urb *urb)
+{
+	struct oz_urb_link *urbl;
+	struct list_head *e;
+	list_for_each(e, &ozhcd->urb_cancel_list) {
+		urbl = container_of(e, struct oz_urb_link, link);
+		if (urb == urbl->urb) {
+			list_del_init(e);
+			return urbl;
+		}
+	}
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * This is called when we have finished processing an urb. It unlinks it from
+ * the ep and returns it to the core.
+ * Context: softirq or process
+ */
+static void oz_complete_urb(struct usb_hcd *hcd, struct urb *urb,
+		int status, unsigned long submit_jiffies)
+{
+	struct oz_hcd *ozhcd = oz_hcd_private(hcd);
+	unsigned long irq_state;
+	struct oz_urb_link *cancel_urbl = 0;
+	spin_lock_irqsave(&g_tasklet_lock, irq_state);
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+	/* Clear hcpriv which will prevent it being put in the cancel list
+	 * in the event that an attempt is made to cancel it.
+	 */
+	urb->hcpriv = 0;
+	/* Walk the cancel list in case the urb is already sitting there.
+	 * Since we process the cancel list in a tasklet rather than in
+	 * the dequeue function this could happen.
+	 */
+	cancel_urbl = oz_uncancel_urb(ozhcd, urb);
+	/* Note: we release lock but do not enable local irqs.
+	 * It appears that usb_hcd_giveback_urb() expects irqs to be disabled,
+	 * or at least other host controllers disable interrupts at this point
+	 * so we do the same. We must, however, release the lock otherwise a
+	 * deadlock will occur if an urb is submitted to our driver in the urb
+	 * completion function. Because we disable interrupts it is possible
+	 * that the urb_enqueue function can be called with them disabled.
+	 */
+	spin_unlock(&g_tasklet_lock);
+	if (oz_forget_urb(urb)) {
+		oz_trace("OZWPAN: ERROR Unknown URB %p\n", urb);
+	} else {
+		static unsigned long last_time;
+		atomic_dec(&g_pending_urbs);
+		oz_trace2(OZ_TRACE_URB,
+			"%lu: giveback_urb(%p,%x) %lu %lu pending:%d\n",
+			jiffies, urb, status, jiffies-submit_jiffies,
+			jiffies-last_time, atomic_read(&g_pending_urbs));
+		last_time = jiffies;
+		oz_event_log(OZ_EVT_URB_DONE, 0, 0, urb, status);
+		usb_hcd_giveback_urb(hcd, urb, status);
+	}
+	spin_lock(&g_tasklet_lock);
+	spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
+	if (cancel_urbl)
+		oz_free_urb_link(cancel_urbl);
+}
+/*------------------------------------------------------------------------------
+ * Deallocates an endpoint including deallocating any associated stream and
+ * returning any queued urbs to the core.
+ * Context: softirq
+ */
+static void oz_ep_free(struct oz_port *port, struct oz_endpoint *ep)
+{
+	oz_trace("oz_ep_free()\n");
+	if (port) {
+		struct list_head list;
+		struct oz_hcd *ozhcd = port->ozhcd;
+		INIT_LIST_HEAD(&list);
+		if (ep->flags & OZ_F_EP_HAVE_STREAM)
+			oz_usb_stream_delete(port->hpd, ep->ep_num);
+		/* Transfer URBs to the orphanage while we hold the lock. */
+		spin_lock_bh(&ozhcd->hcd_lock);
+		/* Note: this works even if ep->urb_list is empty.*/
+		list_replace_init(&ep->urb_list, &list);
+		/* Put the URBs in the orphanage. */
+		list_splice_tail(&list, &ozhcd->orphanage);
+		spin_unlock_bh(&ozhcd->hcd_lock);
+	}
+	oz_trace("Freeing endpoint memory\n");
+	kfree(ep);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static int oz_enqueue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir,
+			struct urb *urb, u8 req_id)
+{
+	struct oz_urb_link *urbl;
+	struct oz_endpoint *ep;
+	int err = 0;
+	if (ep_addr >= OZ_NB_ENDPOINTS) {
+		oz_trace("Invalid endpoint number in oz_enqueue_ep_urb().\n");
+		return -EINVAL;
+	}
+	urbl = oz_alloc_urb_link();
+	if (!urbl)
+		return -ENOMEM;
+	urbl->submit_jiffies = jiffies;
+	urbl->urb = urb;
+	urbl->req_id = req_id;
+	urbl->ep_num = ep_addr;
+	/* Hold lock while we insert the URB into the list within the
+	 * endpoint structure.
+	 */
+	spin_lock_bh(&port->ozhcd->hcd_lock);
+	/* If the urb has been unlinked while out of any list then
+	 * complete it now.
+	 */
+	if (urb->unlinked) {
+		spin_unlock_bh(&port->ozhcd->hcd_lock);
+		oz_trace("urb %p unlinked so complete immediately\n", urb);
+		oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
+		oz_free_urb_link(urbl);
+		return 0;
+	}
+	if (in_dir)
+		ep = port->in_ep[ep_addr];
+	else
+		ep = port->out_ep[ep_addr];
+	if (ep && port->hpd) {
+		list_add_tail(&urbl->link, &ep->urb_list);
+		if (!in_dir && ep_addr && (ep->credit < 0)) {
+			ep->last_jiffies = jiffies;
+			ep->credit = 0;
+			oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num,
+					0, 0, ep->credit);
+		}
+	} else {
+		err = -EPIPE;
+	}
+	spin_unlock_bh(&port->ozhcd->hcd_lock);
+	if (err)
+		oz_free_urb_link(urbl);
+	return err;
+}
+/*------------------------------------------------------------------------------
+ * Removes an urb from the queue in the endpoint.
+ * Returns 0 if it is found and -EIDRM otherwise.
+ * Context: softirq
+ */
+static int oz_dequeue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir,
+			struct urb *urb)
+{
+	struct oz_urb_link *urbl = 0;
+	struct oz_endpoint *ep;
+	spin_lock_bh(&port->ozhcd->hcd_lock);
+	if (in_dir)
+		ep = port->in_ep[ep_addr];
+	else
+		ep = port->out_ep[ep_addr];
+	if (ep) {
+		struct list_head *e;
+		list_for_each(e, &ep->urb_list) {
+			urbl = container_of(e, struct oz_urb_link, link);
+			if (urbl->urb == urb) {
+				list_del_init(e);
+				break;
+			}
+			urbl = 0;
+		}
+	}
+	spin_unlock_bh(&port->ozhcd->hcd_lock);
+	if (urbl)
+		oz_free_urb_link(urbl);
+	return urbl ? 0 : -EIDRM;
+}
+/*------------------------------------------------------------------------------
+ * Finds an urb given its request id.
+ * Context: softirq
+ */
+static struct urb *oz_find_urb_by_id(struct oz_port *port, int ep_ix,
+		u8 req_id)
+{
+	struct oz_hcd *ozhcd = port->ozhcd;
+	struct urb *urb = 0;
+	struct oz_urb_link *urbl = 0;
+	struct oz_endpoint *ep;
+
+	spin_lock_bh(&ozhcd->hcd_lock);
+	ep = port->out_ep[ep_ix];
+	if (ep) {
+		struct list_head *e;
+		list_for_each(e, &ep->urb_list) {
+			urbl = container_of(e, struct oz_urb_link, link);
+			if (urbl->req_id == req_id) {
+				urb = urbl->urb;
+				list_del_init(e);
+				break;
+			}
+		}
+	}
+	spin_unlock_bh(&ozhcd->hcd_lock);
+	/* If urb is non-zero then we we must have an urb link to delete.
+	 */
+	if (urb)
+		oz_free_urb_link(urbl);
+	return urb;
+}
+/*------------------------------------------------------------------------------
+ * Pre-condition: Port lock must be held.
+ * Context: softirq
+ */
+static void oz_acquire_port(struct oz_port *port, void *hpd)
+{
+	INIT_LIST_HEAD(&port->isoc_out_ep);
+	INIT_LIST_HEAD(&port->isoc_in_ep);
+	port->flags |= OZ_PORT_F_PRESENT | OZ_PORT_F_CHANGED;
+	port->status |= USB_PORT_STAT_CONNECTION |
+			(USB_PORT_STAT_C_CONNECTION << 16);
+	oz_usb_get(hpd);
+	port->hpd = hpd;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static struct oz_hcd *oz_hcd_claim(void)
+{
+	struct oz_hcd *ozhcd;
+	spin_lock_bh(&g_hcdlock);
+	ozhcd = g_ozhcd;
+	if (ozhcd)
+		usb_get_hcd(ozhcd->hcd);
+	spin_unlock_bh(&g_hcdlock);
+	return ozhcd;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static inline void oz_hcd_put(struct oz_hcd *ozhcd)
+{
+	if (ozhcd)
+		usb_put_hcd(ozhcd->hcd);
+}
+/*------------------------------------------------------------------------------
+ * This is called by the protocol handler to notify that a PD has arrived.
+ * We allocate a port to associate with the PD and create a structure for
+ * endpoint 0. This port is made the connection port.
+ * In the event that one of the other port is already a connection port then
+ * we fail.
+ * TODO We should be able to do better than fail and should be able remember
+ * that this port needs configuring and make it the connection port once the
+ * current connection port has been assigned an address. Collisions here are
+ * probably very rare indeed.
+ * Context: softirq
+ */
+void *oz_hcd_pd_arrived(void *hpd)
+{
+	int i;
+	void *hport = 0;
+	struct oz_hcd *ozhcd = 0;
+	struct oz_endpoint *ep;
+	oz_trace("oz_hcd_pd_arrived()\n");
+	ozhcd = oz_hcd_claim();
+	if (ozhcd == 0)
+		return 0;
+	/* Allocate an endpoint object in advance (before holding hcd lock) to
+	 * use for out endpoint 0.
+	 */
+	ep = oz_ep_alloc(GFP_ATOMIC, 0);
+	spin_lock_bh(&ozhcd->hcd_lock);
+	if (ozhcd->conn_port >= 0) {
+		spin_unlock_bh(&ozhcd->hcd_lock);
+		oz_trace("conn_port >= 0\n");
+		goto out;
+	}
+	for (i = 0; i < OZ_NB_PORTS; i++) {
+		struct oz_port *port = &ozhcd->ports[i];
+		spin_lock(&port->port_lock);
+		if ((port->flags & OZ_PORT_F_PRESENT) == 0) {
+			oz_acquire_port(port, hpd);
+			spin_unlock(&port->port_lock);
+			break;
+		}
+		spin_unlock(&port->port_lock);
+	}
+	if (i < OZ_NB_PORTS) {
+		oz_trace("Setting conn_port = %d\n", i);
+		ozhcd->conn_port = i;
+		/* Attach out endpoint 0.
+		 */
+		ozhcd->ports[i].out_ep[0] = ep;
+		ep = 0;
+		hport = &ozhcd->ports[i];
+		spin_unlock_bh(&ozhcd->hcd_lock);
+		if (ozhcd->flags & OZ_HDC_F_SUSPENDED) {
+			oz_trace("Resuming root hub\n");
+			usb_hcd_resume_root_hub(ozhcd->hcd);
+		}
+		usb_hcd_poll_rh_status(ozhcd->hcd);
+	} else {
+		spin_unlock_bh(&ozhcd->hcd_lock);
+	}
+out:
+	if (ep) /* ep is non-null if not used. */
+		oz_ep_free(0, ep);
+	oz_hcd_put(ozhcd);
+	return hport;
+}
+/*------------------------------------------------------------------------------
+ * This is called by the protocol handler to notify that the PD has gone away.
+ * We need to deallocate all resources and then request that the root hub is
+ * polled. We release the reference we hold on the PD.
+ * Context: softirq
+ */
+void oz_hcd_pd_departed(void *hport)
+{
+	struct oz_port *port = (struct oz_port *)hport;
+	struct oz_hcd *ozhcd;
+	void *hpd;
+	struct oz_endpoint *ep = 0;
+
+	oz_trace("oz_hcd_pd_departed()\n");
+	if (port == 0) {
+		oz_trace("oz_hcd_pd_departed() port = 0\n");
+		return;
+	}
+	ozhcd = port->ozhcd;
+	if (ozhcd == 0)
+		return;
+	/* Check if this is the connection port - if so clear it.
+	 */
+	spin_lock_bh(&ozhcd->hcd_lock);
+	if ((ozhcd->conn_port >= 0) &&
+		(port == &ozhcd->ports[ozhcd->conn_port])) {
+		oz_trace("Clearing conn_port\n");
+		ozhcd->conn_port = -1;
+	}
+	spin_lock(&port->port_lock);
+	port->flags |= OZ_PORT_F_DYING;
+	spin_unlock(&port->port_lock);
+	spin_unlock_bh(&ozhcd->hcd_lock);
+
+	oz_clean_endpoints_for_config(ozhcd->hcd, port);
+	spin_lock_bh(&port->port_lock);
+	hpd = port->hpd;
+	port->hpd = 0;
+	port->bus_addr = 0xff;
+	port->flags &= ~(OZ_PORT_F_PRESENT | OZ_PORT_F_DYING);
+	port->flags |= OZ_PORT_F_CHANGED;
+	port->status &= ~USB_PORT_STAT_CONNECTION;
+	port->status |= (USB_PORT_STAT_C_CONNECTION << 16);
+	/* If there is an endpont 0 then clear the pointer while we hold
+	 * the spinlock be we deallocate it after releasing the lock.
+	 */
+	if (port->out_ep[0]) {
+		ep = port->out_ep[0];
+		port->out_ep[0] = 0;
+	}
+	spin_unlock_bh(&port->port_lock);
+	if (ep)
+		oz_ep_free(port, ep);
+	usb_hcd_poll_rh_status(ozhcd->hcd);
+	oz_usb_put(hpd);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+void oz_hcd_pd_reset(void *hpd, void *hport)
+{
+	/* Cleanup the current configuration and report reset to the core.
+	 */
+	struct oz_port *port = (struct oz_port *)hport;
+	struct oz_hcd *ozhcd = port->ozhcd;
+	oz_trace("PD Reset\n");
+	spin_lock_bh(&port->port_lock);
+	port->flags |= OZ_PORT_F_CHANGED;
+	port->status |= USB_PORT_STAT_RESET;
+	port->status |= (USB_PORT_STAT_C_RESET << 16);
+	spin_unlock_bh(&port->port_lock);
+	oz_clean_endpoints_for_config(ozhcd->hcd, port);
+	usb_hcd_poll_rh_status(ozhcd->hcd);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+void oz_hcd_get_desc_cnf(void *hport, u8 req_id, int status, u8 *desc,
+			int length, int offset, int total_size)
+{
+	struct oz_port *port = (struct oz_port *)hport;
+	struct urb *urb;
+	int err = 0;
+
+	oz_event_log(OZ_EVT_CTRL_CNF, 0, req_id, 0, status);
+	oz_trace("oz_hcd_get_desc_cnf length = %d offs = %d tot_size = %d\n",
+			length, offset, total_size);
+	urb = oz_find_urb_by_id(port, 0, req_id);
+	if (!urb)
+		return;
+	if (status == 0) {
+		int copy_len;
+		int required_size = urb->transfer_buffer_length;
+		if (required_size > total_size)
+			required_size = total_size;
+		copy_len = required_size-offset;
+		if (length <= copy_len)
+			copy_len = length;
+		memcpy(urb->transfer_buffer+offset, desc, copy_len);
+		offset += copy_len;
+		if (offset < required_size) {
+			struct usb_ctrlrequest *setup =
+				(struct usb_ctrlrequest *)urb->setup_packet;
+			unsigned wvalue = le16_to_cpu(setup->wValue);
+			if (oz_enqueue_ep_urb(port, 0, 0, urb, req_id))
+				err = -ENOMEM;
+			else if (oz_usb_get_desc_req(port->hpd, req_id,
+					setup->bRequestType, (u8)(wvalue>>8),
+					(u8)wvalue, setup->wIndex, offset,
+					required_size-offset)) {
+				oz_dequeue_ep_urb(port, 0, 0, urb);
+				err = -ENOMEM;
+			}
+			if (err == 0)
+				return;
+		}
+	}
+	urb->actual_length = total_size;
+	oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+#ifdef WANT_TRACE
+static void oz_display_conf_type(u8 t)
+{
+	switch (t) {
+	case USB_REQ_GET_STATUS:
+		oz_trace("USB_REQ_GET_STATUS - cnf\n");
+		break;
+	case USB_REQ_CLEAR_FEATURE:
+		oz_trace("USB_REQ_CLEAR_FEATURE - cnf\n");
+		break;
+	case USB_REQ_SET_FEATURE:
+		oz_trace("USB_REQ_SET_FEATURE - cnf\n");
+		break;
+	case USB_REQ_SET_ADDRESS:
+		oz_trace("USB_REQ_SET_ADDRESS - cnf\n");
+		break;
+	case USB_REQ_GET_DESCRIPTOR:
+		oz_trace("USB_REQ_GET_DESCRIPTOR - cnf\n");
+		break;
+	case USB_REQ_SET_DESCRIPTOR:
+		oz_trace("USB_REQ_SET_DESCRIPTOR - cnf\n");
+		break;
+	case USB_REQ_GET_CONFIGURATION:
+		oz_trace("USB_REQ_GET_CONFIGURATION - cnf\n");
+		break;
+	case USB_REQ_SET_CONFIGURATION:
+		oz_trace("USB_REQ_SET_CONFIGURATION - cnf\n");
+		break;
+	case USB_REQ_GET_INTERFACE:
+		oz_trace("USB_REQ_GET_INTERFACE - cnf\n");
+		break;
+	case USB_REQ_SET_INTERFACE:
+		oz_trace("USB_REQ_SET_INTERFACE - cnf\n");
+		break;
+	case USB_REQ_SYNCH_FRAME:
+		oz_trace("USB_REQ_SYNCH_FRAME - cnf\n");
+		break;
+	}
+}
+#else
+#define oz_display_conf_type(__x)
+#endif /* WANT_TRACE */
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static void oz_hcd_complete_set_config(struct oz_port *port, struct urb *urb,
+		u8 rcode, u8 config_num)
+{
+	int rc = 0;
+	struct usb_hcd *hcd = port->ozhcd->hcd;
+	if (rcode == 0) {
+		port->config_num = config_num;
+		oz_clean_endpoints_for_config(hcd, port);
+		if (oz_build_endpoints_for_config(hcd, port,
+			&urb->dev->config[port->config_num-1], GFP_ATOMIC)) {
+			rc = -ENOMEM;
+		}
+	} else {
+		rc = -ENOMEM;
+	}
+	oz_complete_urb(hcd, urb, rc, 0);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static void oz_hcd_complete_set_interface(struct oz_port *port, struct urb *urb,
+		u8 rcode, u8 if_num, u8 alt)
+{
+	struct usb_hcd *hcd = port->ozhcd->hcd;
+	int rc = 0;
+	if (rcode == 0) {
+		struct usb_host_config *config;
+		struct usb_host_interface *intf;
+		oz_trace("Set interface %d alt %d\n", if_num, alt);
+		oz_clean_endpoints_for_interface(hcd, port, if_num);
+		config = &urb->dev->config[port->config_num-1];
+		intf = &config->intf_cache[if_num]->altsetting[alt];
+		if (oz_build_endpoints_for_interface(hcd, port, intf,
+			GFP_ATOMIC))
+			rc = -ENOMEM;
+		else
+			port->iface[if_num].alt = alt;
+	} else {
+		rc = -ENOMEM;
+	}
+	oz_complete_urb(hcd, urb, rc, 0);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, u8 *data,
+	int data_len)
+{
+	struct oz_port *port = (struct oz_port *)hport;
+	struct urb *urb;
+	struct usb_ctrlrequest *setup;
+	struct usb_hcd *hcd = port->ozhcd->hcd;
+	unsigned windex;
+	unsigned wvalue;
+
+	oz_event_log(OZ_EVT_CTRL_CNF, 0, req_id, 0, rcode);
+	oz_trace("oz_hcd_control_cnf rcode=%u len=%d\n", rcode, data_len);
+	urb = oz_find_urb_by_id(port, 0, req_id);
+	if (!urb) {
+		oz_trace("URB not found\n");
+		return;
+	}
+	setup = (struct usb_ctrlrequest *)urb->setup_packet;
+	windex = le16_to_cpu(setup->wIndex);
+	wvalue = le16_to_cpu(setup->wValue);
+	if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		/* Standard requests */
+		oz_display_conf_type(setup->bRequest);
+		switch (setup->bRequest) {
+		case USB_REQ_SET_CONFIGURATION:
+			oz_hcd_complete_set_config(port, urb, rcode,
+				(u8)wvalue);
+			break;
+		case USB_REQ_SET_INTERFACE:
+			oz_hcd_complete_set_interface(port, urb, rcode,
+				(u8)windex, (u8)wvalue);
+			break;
+		default:
+			oz_complete_urb(hcd, urb, 0, 0);
+		}
+
+	} else {
+		int copy_len;
+		oz_trace("VENDOR-CLASS - cnf\n");
+		if (data_len <= urb->transfer_buffer_length)
+			copy_len = data_len;
+		else
+			copy_len = urb->transfer_buffer_length;
+		if (copy_len)
+			memcpy(urb->transfer_buffer, data, copy_len);
+		urb->actual_length = copy_len;
+		oz_complete_urb(hcd, urb, 0, 0);
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+static int oz_hcd_buffer_data(struct oz_endpoint *ep, u8 *data, int data_len)
+{
+	int space;
+	int copy_len;
+	if (!ep->buffer)
+		return -1;
+	space = ep->out_ix-ep->in_ix-1;
+	if (space < 0)
+		space += ep->buffer_size;
+	if (space < (data_len+1)) {
+		oz_trace("Buffer full\n");
+		return -1;
+	}
+	ep->buffer[ep->in_ix] = (u8)data_len;
+	if (++ep->in_ix == ep->buffer_size)
+		ep->in_ix = 0;
+	copy_len = ep->buffer_size - ep->in_ix;
+	if (copy_len > data_len)
+		copy_len = data_len;
+	memcpy(&ep->buffer[ep->in_ix], data, copy_len);
+
+	if (copy_len < data_len) {
+		memcpy(ep->buffer, data+copy_len, data_len-copy_len);
+		ep->in_ix = data_len-copy_len;
+	} else {
+		ep->in_ix += copy_len;
+	}
+	if (ep->in_ix == ep->buffer_size)
+		ep->in_ix = 0;
+	ep->buffered_units++;
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+void oz_hcd_data_ind(void *hport, u8 endpoint, u8 *data, int data_len)
+{
+	struct oz_port *port = (struct oz_port *)hport;
+	struct oz_endpoint *ep;
+	struct oz_hcd *ozhcd = port->ozhcd;
+	spin_lock_bh(&ozhcd->hcd_lock);
+	ep = port->in_ep[endpoint & USB_ENDPOINT_NUMBER_MASK];
+	if (ep == 0)
+		goto done;
+	switch (ep->attrib & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_INT:
+	case USB_ENDPOINT_XFER_BULK:
+		if (!list_empty(&ep->urb_list)) {
+			struct oz_urb_link *urbl =
+				list_first_entry(&ep->urb_list,
+					struct oz_urb_link, link);
+			struct urb *urb;
+			int copy_len;
+			list_del_init(&urbl->link);
+			spin_unlock_bh(&ozhcd->hcd_lock);
+			urb = urbl->urb;
+			oz_free_urb_link(urbl);
+			if (data_len <= urb->transfer_buffer_length)
+				copy_len = data_len;
+			else
+				copy_len = urb->transfer_buffer_length;
+			memcpy(urb->transfer_buffer, data, copy_len);
+			urb->actual_length = copy_len;
+			oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
+			return;
+		}
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		oz_hcd_buffer_data(ep, data, data_len);
+		break;
+	}
+done:
+	spin_unlock_bh(&ozhcd->hcd_lock);
+}
+/*------------------------------------------------------------------------------
+ * Context: unknown
+ */
+static inline int oz_usb_get_frame_number(void)
+{
+	return jiffies_to_msecs(get_jiffies_64());
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+int oz_hcd_heartbeat(void *hport)
+{
+	int rc = 0;
+	struct oz_port *port = (struct oz_port *)hport;
+	struct oz_hcd *ozhcd = port->ozhcd;
+	struct oz_urb_link *urbl;
+	struct list_head xfr_list;
+	struct list_head *e;
+	struct list_head *n;
+	struct urb *urb;
+	struct oz_endpoint *ep;
+	unsigned long now = jiffies;
+	INIT_LIST_HEAD(&xfr_list);
+	/* Check the OUT isoc endpoints to see if any URB data can be sent.
+	 */
+	spin_lock_bh(&ozhcd->hcd_lock);
+	list_for_each(e, &port->isoc_out_ep) {
+		ep = ep_from_link(e);
+		if (ep->credit < 0)
+			continue;
+		ep->credit += (now - ep->last_jiffies);
+		if (ep->credit > ep->credit_ceiling)
+			ep->credit = ep->credit_ceiling;
+		oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num, 0, 0, ep->credit);
+		ep->last_jiffies = now;
+		while (ep->credit && !list_empty(&ep->urb_list)) {
+			urbl = list_first_entry(&ep->urb_list,
+				struct oz_urb_link, link);
+			urb = urbl->urb;
+			if (ep->credit < urb->number_of_packets)
+				break;
+			ep->credit -= urb->number_of_packets;
+			oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num, 0, 0,
+				ep->credit);
+			list_del(&urbl->link);
+			list_add_tail(&urbl->link, &xfr_list);
+		}
+	}
+	spin_unlock_bh(&ozhcd->hcd_lock);
+	/* Send to PD and complete URBs.
+	 */
+	list_for_each_safe(e, n, &xfr_list) {
+		unsigned long t;
+		urbl = container_of(e, struct oz_urb_link, link);
+		urb = urbl->urb;
+		t = urbl->submit_jiffies;
+		list_del_init(e);
+		urb->error_count = 0;
+		urb->start_frame = oz_usb_get_frame_number();
+		oz_usb_send_isoc(port->hpd, urbl->ep_num, urb);
+		oz_free_urb_link(urbl);
+		oz_complete_urb(port->ozhcd->hcd, urb, 0, t);
+	}
+	/* Check the IN isoc endpoints to see if any URBs can be completed.
+	 */
+	spin_lock_bh(&ozhcd->hcd_lock);
+	list_for_each(e, &port->isoc_in_ep) {
+		struct oz_endpoint *ep = ep_from_link(e);
+		if (ep->flags & OZ_F_EP_BUFFERING) {
+			if (ep->buffered_units * OZ_IN_BUFFERING_UNITS) {
+				ep->flags &= ~OZ_F_EP_BUFFERING;
+				ep->credit = 0;
+				oz_event_log(OZ_EVT_EP_CREDIT,
+					ep->ep_num | USB_DIR_IN,
+					0, 0, ep->credit);
+				ep->last_jiffies = now;
+				ep->start_frame = 0;
+				oz_event_log(OZ_EVT_EP_BUFFERING,
+					ep->ep_num | USB_DIR_IN, 0, 0, 0);
+			}
+			continue;
+		}
+		ep->credit += (now - ep->last_jiffies);
+		oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num | USB_DIR_IN,
+			0, 0, ep->credit);
+		ep->last_jiffies = now;
+		while (!list_empty(&ep->urb_list)) {
+			struct oz_urb_link *urbl =
+				list_first_entry(&ep->urb_list,
+					struct oz_urb_link, link);
+			struct urb *urb = urbl->urb;
+			int len = 0;
+			int copy_len;
+			int i;
+			if (ep->credit < urb->number_of_packets)
+				break;
+			if (ep->buffered_units < urb->number_of_packets)
+				break;
+			urb->actual_length = 0;
+			for (i = 0; i < urb->number_of_packets; i++) {
+				len = ep->buffer[ep->out_ix];
+				if (++ep->out_ix == ep->buffer_size)
+					ep->out_ix = 0;
+				copy_len = ep->buffer_size - ep->out_ix;
+				if (copy_len > len)
+					copy_len = len;
+				memcpy(urb->transfer_buffer,
+					&ep->buffer[ep->out_ix], copy_len);
+				if (copy_len < len) {
+					memcpy(urb->transfer_buffer+copy_len,
+						ep->buffer, len-copy_len);
+					ep->out_ix = len-copy_len;
+				} else
+					ep->out_ix += copy_len;
+				if (ep->out_ix == ep->buffer_size)
+					ep->out_ix = 0;
+				urb->iso_frame_desc[i].offset =
+					urb->actual_length;
+				urb->actual_length += len;
+				urb->iso_frame_desc[i].actual_length = len;
+				urb->iso_frame_desc[i].status = 0;
+			}
+			ep->buffered_units -= urb->number_of_packets;
+			urb->error_count = 0;
+			urb->start_frame = ep->start_frame;
+			ep->start_frame += urb->number_of_packets;
+			list_del(&urbl->link);
+			list_add_tail(&urbl->link, &xfr_list);
+			ep->credit -= urb->number_of_packets;
+			oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num | USB_DIR_IN,
+				0, 0, ep->credit);
+		}
+	}
+	if (!list_empty(&port->isoc_out_ep) || !list_empty(&port->isoc_in_ep))
+		rc = 1;
+	spin_unlock_bh(&ozhcd->hcd_lock);
+	/* Complete the filled URBs.
+	 */
+	list_for_each_safe(e, n, &xfr_list) {
+		urbl = container_of(e, struct oz_urb_link, link);
+		urb = urbl->urb;
+		list_del_init(e);
+		oz_free_urb_link(urbl);
+		oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
+	}
+	/* Check if there are any ep0 requests that have timed out.
+	 * If so resent to PD.
+	 */
+	ep = port->out_ep[0];
+	if (ep) {
+		struct list_head *e;
+		struct list_head *n;
+		spin_lock_bh(&ozhcd->hcd_lock);
+		list_for_each_safe(e, n, &ep->urb_list) {
+			urbl = container_of(e, struct oz_urb_link, link);
+			if (time_after(now, urbl->submit_jiffies+HZ/2)) {
+				oz_trace("%ld: Request 0x%p timeout\n",
+						now, urbl->urb);
+				urbl->submit_jiffies = now;
+				list_del(e);
+				list_add_tail(e, &xfr_list);
+			}
+		}
+		if (!list_empty(&ep->urb_list))
+			rc = 1;
+		spin_unlock_bh(&ozhcd->hcd_lock);
+		e = xfr_list.next;
+		while (e != &xfr_list) {
+			urbl = container_of(e, struct oz_urb_link, link);
+			e = e->next;
+			oz_trace("Resending request to PD.\n");
+			oz_process_ep0_urb(ozhcd, urbl->urb, GFP_ATOMIC);
+			oz_free_urb_link(urbl);
+		}
+	}
+	return rc;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static int oz_build_endpoints_for_interface(struct usb_hcd *hcd,
+		struct oz_port *port,
+		struct usb_host_interface *intf, gfp_t mem_flags)
+{
+	struct oz_hcd *ozhcd = port->ozhcd;
+	int i;
+	int if_ix = intf->desc.bInterfaceNumber;
+	int request_heartbeat = 0;
+	oz_trace("interface[%d] = %p\n", if_ix, intf);
+	for (i = 0; i < intf->desc.bNumEndpoints; i++) {
+		struct usb_host_endpoint *hep = &intf->endpoint[i];
+		u8 ep_addr = hep->desc.bEndpointAddress;
+		u8 ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+		struct oz_endpoint *ep;
+		int buffer_size = 0;
+
+		oz_trace("%d bEndpointAddress = %x\n", i, ep_addr);
+		if ((ep_addr & USB_ENDPOINT_DIR_MASK) &&
+			((hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+			== USB_ENDPOINT_XFER_ISOC)) {
+			buffer_size = 24*1024;
+		}
+
+		ep = oz_ep_alloc(mem_flags, buffer_size);
+		if (!ep) {
+			oz_clean_endpoints_for_interface(hcd, port, if_ix);
+			return -ENOMEM;
+		}
+		ep->attrib = hep->desc.bmAttributes;
+		ep->ep_num = ep_num;
+		if ((ep->attrib & USB_ENDPOINT_XFERTYPE_MASK)
+			== USB_ENDPOINT_XFER_ISOC) {
+			oz_trace("wMaxPacketSize = %d\n",
+				hep->desc.wMaxPacketSize);
+			ep->credit_ceiling = 200;
+			if (ep_addr & USB_ENDPOINT_DIR_MASK) {
+				ep->flags |= OZ_F_EP_BUFFERING;
+				oz_event_log(OZ_EVT_EP_BUFFERING,
+					ep->ep_num | USB_DIR_IN, 1, 0, 0);
+			} else {
+				ep->flags |= OZ_F_EP_HAVE_STREAM;
+				if (oz_usb_stream_create(port->hpd, ep_num))
+					ep->flags &= ~OZ_F_EP_HAVE_STREAM;
+			}
+		}
+		spin_lock_bh(&ozhcd->hcd_lock);
+		if (ep_addr & USB_ENDPOINT_DIR_MASK) {
+			port->in_ep[ep_num] = ep;
+			port->iface[if_ix].ep_mask |=
+				(1<<(ep_num+OZ_NB_ENDPOINTS));
+			if ((ep->attrib & USB_ENDPOINT_XFERTYPE_MASK)
+				 == USB_ENDPOINT_XFER_ISOC) {
+				list_add_tail(&ep->link, &port->isoc_in_ep);
+				request_heartbeat = 1;
+			}
+		} else {
+			port->out_ep[ep_num] = ep;
+			port->iface[if_ix].ep_mask |= (1<<ep_num);
+			if ((ep->attrib & USB_ENDPOINT_XFERTYPE_MASK)
+				== USB_ENDPOINT_XFER_ISOC) {
+				list_add_tail(&ep->link, &port->isoc_out_ep);
+				request_heartbeat = 1;
+			}
+		}
+		spin_unlock_bh(&ozhcd->hcd_lock);
+		if (request_heartbeat && port->hpd)
+			oz_usb_request_heartbeat(port->hpd);
+	}
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static void oz_clean_endpoints_for_interface(struct usb_hcd *hcd,
+			struct oz_port *port, int if_ix)
+{
+	struct oz_hcd *ozhcd = port->ozhcd;
+	unsigned mask;
+	int i;
+	struct list_head ep_list;
+
+	oz_trace("Deleting endpoints for interface %d\n", if_ix);
+	if (if_ix >= port->num_iface)
+		return;
+	INIT_LIST_HEAD(&ep_list);
+	spin_lock_bh(&ozhcd->hcd_lock);
+	mask = port->iface[if_ix].ep_mask;
+	port->iface[if_ix].ep_mask = 0;
+	for (i = 0; i < OZ_NB_ENDPOINTS; i++) {
+		struct list_head *e;
+		/* Gather OUT endpoints.
+		 */
+		if ((mask & (1<<i)) && port->out_ep[i]) {
+			e = &port->out_ep[i]->link;
+			port->out_ep[i] = 0;
+			/* Remove from isoc list if present.
+			 */
+			list_del(e);
+			list_add_tail(e, &ep_list);
+		}
+		/* Gather IN endpoints.
+		 */
+		if ((mask & (1<<(i+OZ_NB_ENDPOINTS))) && port->in_ep[i]) {
+			e = &port->in_ep[i]->link;
+			port->in_ep[i] = 0;
+			list_del(e);
+			list_add_tail(e, &ep_list);
+		}
+	}
+	spin_unlock_bh(&ozhcd->hcd_lock);
+	while (!list_empty(&ep_list)) {
+		struct oz_endpoint *ep =
+			list_first_entry(&ep_list, struct oz_endpoint, link);
+		list_del_init(&ep->link);
+		oz_ep_free(port, ep);
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static int oz_build_endpoints_for_config(struct usb_hcd *hcd,
+		struct oz_port *port, struct usb_host_config *config,
+		gfp_t mem_flags)
+{
+	struct oz_hcd *ozhcd = port->ozhcd;
+	int i;
+	int num_iface = config->desc.bNumInterfaces;
+	if (num_iface) {
+		struct oz_interface *iface;
+
+		iface = kmalloc(num_iface*sizeof(struct oz_interface),
+				mem_flags | __GFP_ZERO);
+		if (!iface)
+			return -ENOMEM;
+		spin_lock_bh(&ozhcd->hcd_lock);
+		port->iface = iface;
+		port->num_iface = num_iface;
+		spin_unlock_bh(&ozhcd->hcd_lock);
+	}
+	for (i = 0; i < num_iface; i++) {
+		struct usb_host_interface *intf =
+			&config->intf_cache[i]->altsetting[0];
+		if (oz_build_endpoints_for_interface(hcd, port, intf,
+			mem_flags))
+			goto fail;
+	}
+	return 0;
+fail:
+	oz_clean_endpoints_for_config(hcd, port);
+	return -1;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static void oz_clean_endpoints_for_config(struct usb_hcd *hcd,
+			struct oz_port *port)
+{
+	struct oz_hcd *ozhcd = port->ozhcd;
+	int i;
+	oz_trace("Deleting endpoints for configuration.\n");
+	for (i = 0; i < port->num_iface; i++)
+		oz_clean_endpoints_for_interface(hcd, port, i);
+	spin_lock_bh(&ozhcd->hcd_lock);
+	if (port->iface) {
+		oz_trace("Freeing interfaces object.\n");
+		kfree(port->iface);
+		port->iface = 0;
+	}
+	port->num_iface = 0;
+	spin_unlock_bh(&ozhcd->hcd_lock);
+}
+/*------------------------------------------------------------------------------
+ * Context: tasklet
+ */
+static void *oz_claim_hpd(struct oz_port *port)
+{
+	void *hpd = 0;
+	struct oz_hcd *ozhcd = port->ozhcd;
+	spin_lock_bh(&ozhcd->hcd_lock);
+	hpd = port->hpd;
+	if (hpd)
+		oz_usb_get(hpd);
+	spin_unlock_bh(&ozhcd->hcd_lock);
+	return hpd;
+}
+/*------------------------------------------------------------------------------
+ * Context: tasklet
+ */
+static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
+		gfp_t mem_flags)
+{
+	struct usb_ctrlrequest *setup;
+	unsigned windex;
+	unsigned wvalue;
+	unsigned wlength;
+	void *hpd = 0;
+	u8 req_id;
+	int rc = 0;
+	unsigned complete = 0;
+
+	int port_ix = -1;
+	struct oz_port *port = 0;
+
+	oz_trace2(OZ_TRACE_URB, "%lu: oz_process_ep0_urb(%p)\n", jiffies, urb);
+	port_ix = oz_get_port_from_addr(ozhcd, urb->dev->devnum);
+	if (port_ix < 0) {
+		rc = -EPIPE;
+		goto out;
+	}
+	port =  &ozhcd->ports[port_ix];
+	if (((port->flags & OZ_PORT_F_PRESENT) == 0)
+		|| (port->flags & OZ_PORT_F_DYING)) {
+		oz_trace("Refusing URB port_ix = %d devnum = %d\n",
+			port_ix, urb->dev->devnum);
+		rc = -EPIPE;
+		goto out;
+	}
+	/* Store port in private context data.
+	 */
+	urb->hcpriv = port;
+	setup = (struct usb_ctrlrequest *)urb->setup_packet;
+	windex = le16_to_cpu(setup->wIndex);
+	wvalue = le16_to_cpu(setup->wValue);
+	wlength = le16_to_cpu(setup->wLength);
+	oz_trace2(OZ_TRACE_CTRL_DETAIL, "bRequestType = %x\n",
+		setup->bRequestType);
+	oz_trace2(OZ_TRACE_CTRL_DETAIL, "bRequest = %x\n", setup->bRequest);
+	oz_trace2(OZ_TRACE_CTRL_DETAIL, "wValue = %x\n", wvalue);
+	oz_trace2(OZ_TRACE_CTRL_DETAIL, "wIndex = %x\n", windex);
+	oz_trace2(OZ_TRACE_CTRL_DETAIL, "wLength = %x\n", wlength);
+
+	req_id = port->next_req_id++;
+	hpd = oz_claim_hpd(port);
+	if (hpd == 0) {
+		oz_trace("Cannot claim port\n");
+		rc = -EPIPE;
+		goto out;
+	}
+
+	if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		/* Standard requests
+		 */
+		switch (setup->bRequest) {
+		case USB_REQ_GET_DESCRIPTOR:
+			oz_trace("USB_REQ_GET_DESCRIPTOR - req\n");
+			break;
+		case USB_REQ_SET_ADDRESS:
+			oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest,
+				0, 0, setup->bRequestType);
+			oz_trace("USB_REQ_SET_ADDRESS - req\n");
+			oz_trace("Port %d address is 0x%x\n", ozhcd->conn_port,
+				(u8)le16_to_cpu(setup->wValue));
+			spin_lock_bh(&ozhcd->hcd_lock);
+			if (ozhcd->conn_port >= 0) {
+				ozhcd->ports[ozhcd->conn_port].bus_addr =
+					(u8)le16_to_cpu(setup->wValue);
+				oz_trace("Clearing conn_port\n");
+				ozhcd->conn_port = -1;
+			}
+			spin_unlock_bh(&ozhcd->hcd_lock);
+			complete = 1;
+			break;
+		case USB_REQ_SET_CONFIGURATION:
+			oz_trace("USB_REQ_SET_CONFIGURATION - req\n");
+			break;
+		case USB_REQ_GET_CONFIGURATION:
+			/* We short curcuit this case and reply directly since
+			 * we have the selected configuration number cached.
+			 */
+			oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest, 0, 0,
+				setup->bRequestType);
+			oz_trace("USB_REQ_GET_CONFIGURATION - reply now\n");
+			if (urb->transfer_buffer_length >= 1) {
+				urb->actual_length = 1;
+				*((u8 *)urb->transfer_buffer) =
+					port->config_num;
+				complete = 1;
+			} else {
+				rc = -EPIPE;
+			}
+			break;
+		case USB_REQ_GET_INTERFACE:
+			/* We short curcuit this case and reply directly since
+			 * we have the selected interface alternative cached.
+			 */
+			oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest, 0, 0,
+				setup->bRequestType);
+			oz_trace("USB_REQ_GET_INTERFACE - reply now\n");
+			if (urb->transfer_buffer_length >= 1) {
+				urb->actual_length = 1;
+				*((u8 *)urb->transfer_buffer) =
+					port->iface[(u8)windex].alt;
+				oz_trace("interface = %d alt = %d\n",
+					windex, port->iface[(u8)windex].alt);
+				complete = 1;
+			} else {
+				rc = -EPIPE;
+			}
+			break;
+		case USB_REQ_SET_INTERFACE:
+			oz_trace("USB_REQ_SET_INTERFACE - req\n");
+			break;
+		}
+	}
+	if (!rc && !complete) {
+		int data_len = 0;
+		if ((setup->bRequestType & USB_DIR_IN) == 0)
+			data_len = wlength;
+		if (oz_usb_control_req(port->hpd, req_id, setup,
+				urb->transfer_buffer, data_len)) {
+			rc = -ENOMEM;
+		} else {
+			/* Note: we are queuing the request after we have
+			 * submitted it to be tranmitted. If the request were
+			 * to complete before we queued it then it would not
+			 * be found in the queue. It seems impossible for
+			 * this to happen but if it did the request would
+			 * be resubmitted so the problem would hopefully
+			 * resolve itself. Putting the request into the
+			 * queue before it has been sent is worse since the
+			 * urb could be cancelled while we are using it
+			 * to build the request.
+			 */
+			if (oz_enqueue_ep_urb(port, 0, 0, urb, req_id))
+				rc = -ENOMEM;
+		}
+	}
+	oz_usb_put(hpd);
+out:
+	if (rc || complete) {
+		oz_trace("Completing request locally\n");
+		oz_complete_urb(ozhcd->hcd, urb, rc, 0);
+	} else {
+		oz_usb_request_heartbeat(port->hpd);
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: tasklet
+ */
+static int oz_urb_process(struct oz_hcd *ozhcd, struct urb *urb)
+{
+	int rc = 0;
+	struct oz_port *port = urb->hcpriv;
+	u8 ep_addr;
+	/* When we are paranoid we keep a list of urbs which we check against
+	 * before handing one back. This is just for debugging during
+	 * development and should be turned off in the released driver.
+	 */
+	oz_remember_urb(urb);
+	/* Check buffer is valid.
+	 */
+	if (!urb->transfer_buffer && urb->transfer_buffer_length)
+		return -EINVAL;
+	/* Check if there is a device at the port - refuse if not.
+	 */
+	if ((port->flags & OZ_PORT_F_PRESENT) == 0)
+		return -EPIPE;
+	ep_addr = usb_pipeendpoint(urb->pipe);
+	if (ep_addr) {
+		/* If the request is not for EP0 then queue it.
+		 */
+		if (oz_enqueue_ep_urb(port, ep_addr, usb_pipein(urb->pipe),
+			urb, 0))
+			rc = -EPIPE;
+	} else {
+		oz_process_ep0_urb(ozhcd, urb, GFP_ATOMIC);
+	}
+	return rc;
+}
+/*------------------------------------------------------------------------------
+ * Context: tasklet
+ */
+static void oz_urb_process_tasklet(unsigned long unused)
+{
+	unsigned long irq_state;
+	struct urb *urb;
+	struct oz_hcd *ozhcd = oz_hcd_claim();
+	int rc = 0;
+	if (ozhcd == 0)
+		return;
+	/* This is called from a tasklet so is in softirq context but the urb
+	 * list is filled from any context so we need to lock
+	 * appropriately while removing urbs.
+	 */
+	spin_lock_irqsave(&g_tasklet_lock, irq_state);
+	while (!list_empty(&ozhcd->urb_pending_list)) {
+		struct oz_urb_link *urbl =
+			list_first_entry(&ozhcd->urb_pending_list,
+				struct oz_urb_link, link);
+		list_del_init(&urbl->link);
+		spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
+		urb = urbl->urb;
+		oz_free_urb_link(urbl);
+		rc = oz_urb_process(ozhcd, urb);
+		if (rc)
+			oz_complete_urb(ozhcd->hcd, urb, rc, 0);
+		spin_lock_irqsave(&g_tasklet_lock, irq_state);
+	}
+	spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
+	oz_hcd_put(ozhcd);
+}
+/*------------------------------------------------------------------------------
+ * This function searches for the urb in any of the lists it could be in.
+ * If it is found it is removed from the list and completed. If the urb is
+ * being processed then it won't be in a list so won't be found. However, the
+ * call to usb_hcd_check_unlink_urb() will set the value of the unlinked field
+ * to a non-zero value. When an attempt is made to put the urb back in a list
+ * the unlinked field will be checked and the urb will then be completed.
+ * Context: tasklet
+ */
+static void oz_urb_cancel(struct oz_port *port, u8 ep_num, struct urb *urb)
+{
+	struct oz_urb_link *urbl = 0;
+	struct list_head *e;
+	struct oz_hcd *ozhcd;
+	unsigned long irq_state;
+	u8 ix;
+	if (port == 0) {
+		oz_trace("ERRORERROR: oz_urb_cancel(%p) port is null\n", urb);
+		return;
+	}
+	ozhcd = port->ozhcd;
+	if (ozhcd == 0) {
+		oz_trace("ERRORERROR: oz_urb_cancel(%p) ozhcd is null\n", urb);
+		return;
+	}
+
+	/* Look in the tasklet queue.
+	 */
+	spin_lock_irqsave(&g_tasklet_lock, irq_state);
+	list_for_each(e, &ozhcd->urb_cancel_list) {
+		urbl = container_of(e, struct oz_urb_link, link);
+		if (urb == urbl->urb) {
+			list_del_init(e);
+			spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
+			goto out2;
+		}
+	}
+	spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
+	urbl = 0;
+
+	/* Look in the orphanage.
+	 */
+	spin_lock_irqsave(&ozhcd->hcd_lock, irq_state);
+	list_for_each(e, &ozhcd->orphanage) {
+		urbl = container_of(e, struct oz_urb_link, link);
+		if (urbl->urb == urb) {
+			list_del(e);
+			oz_trace("Found urb in orphanage\n");
+			goto out;
+		}
+	}
+	ix = (ep_num & 0xf);
+	urbl = 0;
+	if ((ep_num & USB_DIR_IN) && ix)
+		urbl = oz_remove_urb(port->in_ep[ix], urb);
+	else
+		urbl = oz_remove_urb(port->out_ep[ix], urb);
+out:
+	spin_unlock_irqrestore(&ozhcd->hcd_lock, irq_state);
+out2:
+	if (urbl) {
+		urb->actual_length = 0;
+		oz_free_urb_link(urbl);
+		oz_complete_urb(ozhcd->hcd, urb, -EPIPE, 0);
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: tasklet
+ */
+static void oz_urb_cancel_tasklet(unsigned long unused)
+{
+	unsigned long irq_state;
+	struct urb *urb;
+	struct oz_hcd *ozhcd = oz_hcd_claim();
+	if (ozhcd == 0)
+		return;
+	spin_lock_irqsave(&g_tasklet_lock, irq_state);
+	while (!list_empty(&ozhcd->urb_cancel_list)) {
+		struct oz_urb_link *urbl =
+			list_first_entry(&ozhcd->urb_cancel_list,
+				struct oz_urb_link, link);
+		list_del_init(&urbl->link);
+		spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
+		urb = urbl->urb;
+		if (urb->unlinked)
+			oz_urb_cancel(urbl->port, urbl->ep_num, urb);
+		oz_free_urb_link(urbl);
+		spin_lock_irqsave(&g_tasklet_lock, irq_state);
+	}
+	spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
+	oz_hcd_put(ozhcd);
+}
+/*------------------------------------------------------------------------------
+ * Context: unknown
+ */
+static void oz_hcd_clear_orphanage(struct oz_hcd *ozhcd, int status)
+{
+	if (ozhcd) {
+		struct oz_urb_link *urbl;
+		while (!list_empty(&ozhcd->orphanage)) {
+			urbl = list_first_entry(&ozhcd->orphanage,
+				struct oz_urb_link, link);
+			list_del(&urbl->link);
+			oz_complete_urb(ozhcd->hcd, urbl->urb, status, 0);
+			oz_free_urb_link(urbl);
+		}
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: unknown
+ */
+static int oz_hcd_start(struct usb_hcd *hcd)
+{
+	oz_trace("oz_hcd_start()\n");
+	hcd->power_budget = 200;
+	hcd->state = HC_STATE_RUNNING;
+	hcd->uses_new_polling = 1;
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: unknown
+ */
+static void oz_hcd_stop(struct usb_hcd *hcd)
+{
+	oz_trace("oz_hcd_stop()\n");
+}
+/*------------------------------------------------------------------------------
+ * Context: unknown
+ */
+static void oz_hcd_shutdown(struct usb_hcd *hcd)
+{
+	oz_trace("oz_hcd_shutdown()\n");
+}
+/*------------------------------------------------------------------------------
+ * Context: any
+ */
+#ifdef WANT_EVENT_TRACE
+static u8 oz_get_irq_ctx(void)
+{
+	u8 irq_info = 0;
+	if (in_interrupt())
+		irq_info |= 1;
+	if (in_irq())
+		irq_info |= 2;
+	return irq_info;
+}
+#endif /* WANT_EVENT_TRACE */
+/*------------------------------------------------------------------------------
+ * Called to queue an urb for the device.
+ * This function should return a non-zero error code if it fails the urb but
+ * should not call usb_hcd_giveback_urb().
+ * Context: any
+ */
+static int oz_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+				gfp_t mem_flags)
+{
+	struct oz_hcd *ozhcd = oz_hcd_private(hcd);
+	int rc = 0;
+	int port_ix;
+	struct oz_port *port;
+	unsigned long irq_state;
+	struct oz_urb_link *urbl;
+	oz_trace2(OZ_TRACE_URB, "%lu: oz_hcd_urb_enqueue(%p)\n",
+		jiffies, urb);
+	oz_event_log(OZ_EVT_URB_SUBMIT, oz_get_irq_ctx(),
+		(u16)urb->number_of_packets, urb, urb->pipe);
+	if (unlikely(ozhcd == 0)) {
+		oz_trace2(OZ_TRACE_URB, "%lu: Refused urb(%p) not ozhcd.\n",
+			jiffies, urb);
+		return -EPIPE;
+	}
+	if (unlikely(hcd->state != HC_STATE_RUNNING)) {
+		oz_trace2(OZ_TRACE_URB, "%lu: Refused urb(%p) not running.\n",
+			jiffies, urb);
+		return -EPIPE;
+	}
+	port_ix = oz_get_port_from_addr(ozhcd, urb->dev->devnum);
+	if (port_ix < 0)
+		return -EPIPE;
+	port =  &ozhcd->ports[port_ix];
+	if (port == 0)
+		return -EPIPE;
+	if ((port->flags & OZ_PORT_F_PRESENT) == 0) {
+		oz_trace("Refusing URB port_ix = %d devnum = %d\n",
+			port_ix, urb->dev->devnum);
+		return -EPIPE;
+	}
+	urb->hcpriv = port;
+	/* Put request in queue for processing by tasklet.
+	 */
+	urbl = oz_alloc_urb_link();
+	if (unlikely(urbl == 0))
+		return -ENOMEM;
+	urbl->urb = urb;
+	spin_lock_irqsave(&g_tasklet_lock, irq_state);
+	rc = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (unlikely(rc)) {
+		spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
+		oz_free_urb_link(urbl);
+		return rc;
+	}
+	list_add_tail(&urbl->link, &ozhcd->urb_pending_list);
+	spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
+	tasklet_schedule(&g_urb_process_tasklet);
+	atomic_inc(&g_pending_urbs);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: tasklet
+ */
+static struct oz_urb_link *oz_remove_urb(struct oz_endpoint *ep,
+				struct urb *urb)
+{
+	struct oz_urb_link *urbl = 0;
+	struct list_head *e;
+	if (unlikely(ep == 0))
+		return 0;
+	list_for_each(e, &ep->urb_list) {
+		urbl = container_of(e, struct oz_urb_link, link);
+		if (urbl->urb == urb) {
+			list_del_init(e);
+			if (usb_pipeisoc(urb->pipe)) {
+				ep->credit -= urb->number_of_packets;
+				if (ep->credit < 0)
+					ep->credit = 0;
+				oz_event_log(OZ_EVT_EP_CREDIT,
+					usb_pipein(urb->pipe) ?
+					(ep->ep_num | USB_DIR_IN) : ep->ep_num,
+					0, 0, ep->credit);
+			}
+			return urbl;
+		}
+	}
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Called to dequeue a previously submitted urb for the device.
+ * Context: any
+ */
+static int oz_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+	struct oz_hcd *ozhcd = oz_hcd_private(hcd);
+	struct oz_urb_link *urbl = 0;
+	int rc;
+	unsigned long irq_state;
+	oz_trace2(OZ_TRACE_URB, "%lu: oz_hcd_urb_dequeue(%p)\n", jiffies, urb);
+	urbl = oz_alloc_urb_link();
+	if (unlikely(urbl == 0))
+		return -ENOMEM;
+	spin_lock_irqsave(&g_tasklet_lock, irq_state);
+	/* The following function checks the urb is still in the queue
+	 * maintained by the core and that the unlinked field is zero.
+	 * If both are true the function sets the unlinked field and returns
+	 * zero. Otherwise it returns an error.
+	 */
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	/* We have to check we haven't completed the urb or are about
+	 * to complete it. When we do we set hcpriv to 0 so if this has
+	 * already happened we don't put the urb in the cancel queue.
+	 */
+	if ((rc == 0) && urb->hcpriv) {
+		urbl->urb = urb;
+		urbl->port = (struct oz_port *)urb->hcpriv;
+		urbl->ep_num = usb_pipeendpoint(urb->pipe);
+		if (usb_pipein(urb->pipe))
+			urbl->ep_num |= USB_DIR_IN;
+		list_add_tail(&urbl->link, &ozhcd->urb_cancel_list);
+		spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
+		tasklet_schedule(&g_urb_cancel_tasklet);
+	} else {
+		spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
+		oz_free_urb_link(urbl);
+	}
+	return rc;
+}
+/*------------------------------------------------------------------------------
+ * Context: unknown
+ */
+static void oz_hcd_endpoint_disable(struct usb_hcd *hcd,
+				struct usb_host_endpoint *ep)
+{
+	oz_trace("oz_hcd_endpoint_disable\n");
+}
+/*------------------------------------------------------------------------------
+ * Context: unknown
+ */
+static void oz_hcd_endpoint_reset(struct usb_hcd *hcd,
+				struct usb_host_endpoint *ep)
+{
+	oz_trace("oz_hcd_endpoint_reset\n");
+}
+/*------------------------------------------------------------------------------
+ * Context: unknown
+ */
+static int oz_hcd_get_frame_number(struct usb_hcd *hcd)
+{
+	oz_trace("oz_hcd_get_frame_number\n");
+	return oz_usb_get_frame_number();
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ * This is called as a consquence of us calling usb_hcd_poll_rh_status() and we
+ * always do that in softirq context.
+ */
+static int oz_hcd_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	struct oz_hcd *ozhcd = oz_hcd_private(hcd);
+	int i;
+
+	oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_status_data()\n");
+	buf[0] = 0;
+
+	spin_lock_bh(&ozhcd->hcd_lock);
+	for (i = 0; i < OZ_NB_PORTS; i++) {
+		if (ozhcd->ports[i].flags & OZ_PORT_F_CHANGED) {
+			oz_trace2(OZ_TRACE_HUB, "Port %d changed\n", i);
+			ozhcd->ports[i].flags &= ~OZ_PORT_F_CHANGED;
+			buf[0] |= 1<<(i+1);
+		}
+	}
+	spin_unlock_bh(&ozhcd->hcd_lock);
+	return buf[0] ? 1 : 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+static void oz_get_hub_descriptor(struct usb_hcd *hcd,
+				struct usb_hub_descriptor *desc)
+{
+	oz_trace2(OZ_TRACE_HUB, "GetHubDescriptor\n");
+	memset(desc, 0, sizeof(*desc));
+	desc->bDescriptorType = 0x29;
+	desc->bDescLength = 9;
+	desc->wHubCharacteristics = (__force __u16)
+			__constant_cpu_to_le16(0x0001);
+	desc->bNbrPorts = OZ_NB_PORTS;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+static int oz_set_port_feature(struct usb_hcd *hcd, u16 wvalue, u16 windex)
+{
+	struct oz_port *port;
+	int err = 0;
+	u8 port_id = (u8)windex;
+	struct oz_hcd *ozhcd = oz_hcd_private(hcd);
+	unsigned set_bits = 0;
+	unsigned clear_bits = 0;
+	oz_trace2(OZ_TRACE_HUB, "SetPortFeature\n");
+	if ((port_id < 1) || (port_id > OZ_NB_PORTS))
+		return -EPIPE;
+	port = &ozhcd->ports[port_id-1];
+	switch (wvalue) {
+	case USB_PORT_FEAT_CONNECTION:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_CONNECTION\n");
+		break;
+	case USB_PORT_FEAT_ENABLE:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_ENABLE\n");
+		break;
+	case USB_PORT_FEAT_SUSPEND:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_SUSPEND\n");
+		break;
+	case USB_PORT_FEAT_OVER_CURRENT:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_OVER_CURRENT\n");
+		break;
+	case USB_PORT_FEAT_RESET:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_RESET\n");
+		set_bits = USB_PORT_STAT_ENABLE | (USB_PORT_STAT_C_RESET<<16);
+		clear_bits = USB_PORT_STAT_RESET;
+		ozhcd->ports[port_id-1].bus_addr = 0;
+		break;
+	case USB_PORT_FEAT_POWER:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_POWER\n");
+		set_bits |= USB_PORT_STAT_POWER;
+		break;
+	case USB_PORT_FEAT_LOWSPEED:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_LOWSPEED\n");
+		break;
+	case USB_PORT_FEAT_C_CONNECTION:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_CONNECTION\n");
+		break;
+	case USB_PORT_FEAT_C_ENABLE:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_ENABLE\n");
+		break;
+	case USB_PORT_FEAT_C_SUSPEND:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_SUSPEND\n");
+		break;
+	case USB_PORT_FEAT_C_OVER_CURRENT:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_OVER_CURRENT\n");
+		break;
+	case USB_PORT_FEAT_C_RESET:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_RESET\n");
+		break;
+	case USB_PORT_FEAT_TEST:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_TEST\n");
+		break;
+	case USB_PORT_FEAT_INDICATOR:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_INDICATOR\n");
+		break;
+	default:
+		oz_trace2(OZ_TRACE_HUB, "Other %d\n", wvalue);
+		break;
+	}
+	if (set_bits || clear_bits) {
+		spin_lock_bh(&port->port_lock);
+		port->status &= ~clear_bits;
+		port->status |= set_bits;
+		spin_unlock_bh(&port->port_lock);
+	}
+	oz_trace2(OZ_TRACE_HUB, "Port[%d] status = 0x%x\n", port_id,
+		port->status);
+	return err;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+static int oz_clear_port_feature(struct usb_hcd *hcd, u16 wvalue, u16 windex)
+{
+	struct oz_port *port;
+	int err = 0;
+	u8 port_id = (u8)windex;
+	struct oz_hcd *ozhcd = oz_hcd_private(hcd);
+	unsigned clear_bits = 0;
+	oz_trace2(OZ_TRACE_HUB, "ClearPortFeature\n");
+	if ((port_id < 1) || (port_id > OZ_NB_PORTS))
+		return -EPIPE;
+	port = &ozhcd->ports[port_id-1];
+	switch (wvalue) {
+	case USB_PORT_FEAT_CONNECTION:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_CONNECTION\n");
+		break;
+	case USB_PORT_FEAT_ENABLE:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_ENABLE\n");
+		clear_bits = USB_PORT_STAT_ENABLE;
+		break;
+	case USB_PORT_FEAT_SUSPEND:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_SUSPEND\n");
+		break;
+	case USB_PORT_FEAT_OVER_CURRENT:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_OVER_CURRENT\n");
+		break;
+	case USB_PORT_FEAT_RESET:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_RESET\n");
+		break;
+	case USB_PORT_FEAT_POWER:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_POWER\n");
+		clear_bits |= USB_PORT_STAT_POWER;
+		break;
+	case USB_PORT_FEAT_LOWSPEED:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_LOWSPEED\n");
+		break;
+	case USB_PORT_FEAT_C_CONNECTION:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_CONNECTION\n");
+		clear_bits = (USB_PORT_STAT_C_CONNECTION << 16);
+		break;
+	case USB_PORT_FEAT_C_ENABLE:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_ENABLE\n");
+		clear_bits = (USB_PORT_STAT_C_ENABLE << 16);
+		break;
+	case USB_PORT_FEAT_C_SUSPEND:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_SUSPEND\n");
+		break;
+	case USB_PORT_FEAT_C_OVER_CURRENT:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_OVER_CURRENT\n");
+		break;
+	case USB_PORT_FEAT_C_RESET:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_RESET\n");
+		clear_bits = (USB_PORT_FEAT_C_RESET << 16);
+		break;
+	case USB_PORT_FEAT_TEST:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_TEST\n");
+		break;
+	case USB_PORT_FEAT_INDICATOR:
+		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_INDICATOR\n");
+		break;
+	default:
+		oz_trace2(OZ_TRACE_HUB, "Other %d\n", wvalue);
+		break;
+	}
+	if (clear_bits) {
+		spin_lock_bh(&port->port_lock);
+		port->status &= ~clear_bits;
+		spin_unlock_bh(&port->port_lock);
+	}
+	oz_trace2(OZ_TRACE_HUB, "Port[%d] status = 0x%x\n", port_id,
+		ozhcd->ports[port_id-1].status);
+	return err;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+static int oz_get_port_status(struct usb_hcd *hcd, u16 windex, char *buf)
+{
+	struct oz_hcd *ozhcd;
+	u32 status = 0;
+	if ((windex < 1) || (windex > OZ_NB_PORTS))
+		return -EPIPE;
+	ozhcd = oz_hcd_private(hcd);
+	oz_trace2(OZ_TRACE_HUB, "GetPortStatus windex = %d\n", windex);
+	status = ozhcd->ports[windex-1].status;
+	put_unaligned(cpu_to_le32(status), (__le32 *)buf);
+	oz_trace2(OZ_TRACE_HUB, "Port[%d] status = %x\n", windex, status);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+static int oz_hcd_hub_control(struct usb_hcd *hcd, u16 req_type, u16 wvalue,
+				u16 windex, char *buf, u16 wlength)
+{
+	int err = 0;
+	oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_control()\n");
+	switch (req_type) {
+	case ClearHubFeature:
+		oz_trace2(OZ_TRACE_HUB, "ClearHubFeature: %d\n", req_type);
+		break;
+	case ClearPortFeature:
+		err = oz_clear_port_feature(hcd, wvalue, windex);
+		break;
+	case GetHubDescriptor:
+		oz_get_hub_descriptor(hcd, (struct usb_hub_descriptor *)buf);
+		break;
+	case GetHubStatus:
+		oz_trace2(OZ_TRACE_HUB, "GetHubStatus: req_type = 0x%x\n",
+			req_type);
+		put_unaligned(__constant_cpu_to_le32(0), (__le32 *)buf);
+		break;
+	case GetPortStatus:
+		err = oz_get_port_status(hcd, windex, buf);
+		break;
+	case SetHubFeature:
+		oz_trace2(OZ_TRACE_HUB, "SetHubFeature: %d\n", req_type);
+		break;
+	case SetPortFeature:
+		err = oz_set_port_feature(hcd, wvalue, windex);
+		break;
+	default:
+		oz_trace2(OZ_TRACE_HUB, "Other: %d\n", req_type);
+		break;
+	}
+	return err;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+static int oz_hcd_bus_suspend(struct usb_hcd *hcd)
+{
+	struct oz_hcd *ozhcd;
+	oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_suspend()\n");
+	ozhcd = oz_hcd_private(hcd);
+	spin_lock_bh(&ozhcd->hcd_lock);
+	hcd->state = HC_STATE_SUSPENDED;
+	ozhcd->flags |= OZ_HDC_F_SUSPENDED;
+	spin_unlock_bh(&ozhcd->hcd_lock);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+static int oz_hcd_bus_resume(struct usb_hcd *hcd)
+{
+	struct oz_hcd *ozhcd;
+	oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_resume()\n");
+	ozhcd = oz_hcd_private(hcd);
+	spin_lock_bh(&ozhcd->hcd_lock);
+	ozhcd->flags &= ~OZ_HDC_F_SUSPENDED;
+	hcd->state = HC_STATE_RUNNING;
+	spin_unlock_bh(&ozhcd->hcd_lock);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ */
+static void oz_plat_shutdown(struct platform_device *dev)
+{
+	oz_trace("oz_plat_shutdown()\n");
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+static int oz_plat_probe(struct platform_device *dev)
+{
+	int i;
+	int err;
+	struct usb_hcd *hcd;
+	struct oz_hcd *ozhcd;
+	oz_trace("oz_plat_probe()\n");
+	hcd = usb_create_hcd(&g_oz_hc_drv, &dev->dev, dev_name(&dev->dev));
+	if (hcd == 0) {
+		oz_trace("Failed to created hcd object OK\n");
+		return -ENOMEM;
+	}
+	ozhcd = oz_hcd_private(hcd);
+	memset(ozhcd, 0, sizeof(*ozhcd));
+	INIT_LIST_HEAD(&ozhcd->urb_pending_list);
+	INIT_LIST_HEAD(&ozhcd->urb_cancel_list);
+	INIT_LIST_HEAD(&ozhcd->orphanage);
+	ozhcd->hcd = hcd;
+	ozhcd->conn_port = -1;
+	spin_lock_init(&ozhcd->hcd_lock);
+	for (i = 0; i < OZ_NB_PORTS; i++) {
+		struct oz_port *port = &ozhcd->ports[i];
+		port->ozhcd = ozhcd;
+		port->flags = 0;
+		port->status = 0;
+		port->bus_addr = 0xff;
+		spin_lock_init(&port->port_lock);
+	}
+	err = usb_add_hcd(hcd, 0, 0);
+	if (err) {
+		oz_trace("Failed to add hcd object OK\n");
+		usb_put_hcd(hcd);
+		return -1;
+	}
+	spin_lock_bh(&g_hcdlock);
+	g_ozhcd = ozhcd;
+	spin_unlock_bh(&g_hcdlock);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: unknown
+ */
+static int oz_plat_remove(struct platform_device *dev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(dev);
+	struct oz_hcd *ozhcd;
+	oz_trace("oz_plat_remove()\n");
+	if (hcd == 0)
+		return -1;
+	ozhcd = oz_hcd_private(hcd);
+	spin_lock_bh(&g_hcdlock);
+	if (ozhcd == g_ozhcd)
+		g_ozhcd = 0;
+	spin_unlock_bh(&g_hcdlock);
+	oz_trace("Clearing orphanage\n");
+	oz_hcd_clear_orphanage(ozhcd, -EPIPE);
+	oz_trace("Removing hcd\n");
+	usb_remove_hcd(hcd);
+	usb_put_hcd(hcd);
+	oz_empty_link_pool();
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: unknown
+ */
+static int oz_plat_suspend(struct platform_device *dev, pm_message_t msg)
+{
+	oz_trace("oz_plat_suspend()\n");
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: unknown
+ */
+static int oz_plat_resume(struct platform_device *dev)
+{
+	oz_trace("oz_plat_resume()\n");
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_hcd_init(void)
+{
+	int err;
+	if (usb_disabled())
+		return -ENODEV;
+	tasklet_init(&g_urb_process_tasklet, oz_urb_process_tasklet, 0);
+	tasklet_init(&g_urb_cancel_tasklet, oz_urb_cancel_tasklet, 0);
+	err = platform_driver_register(&g_oz_plat_drv);
+	oz_trace("platform_driver_register() returned %d\n", err);
+	if (err)
+		goto error;
+	g_plat_dev = platform_device_alloc(OZ_PLAT_DEV_NAME, -1);
+	if (g_plat_dev == 0) {
+		err = -ENOMEM;
+		goto error1;
+	}
+	oz_trace("platform_device_alloc() succeeded\n");
+	err = platform_device_add(g_plat_dev);
+	if (err)
+		goto error2;
+	oz_trace("platform_device_add() succeeded\n");
+	return 0;
+error2:
+	platform_device_put(g_plat_dev);
+error1:
+	platform_driver_unregister(&g_oz_plat_drv);
+error:
+	tasklet_disable(&g_urb_process_tasklet);
+	tasklet_disable(&g_urb_cancel_tasklet);
+	oz_trace("oz_hcd_init() failed %d\n", err);
+	return err;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_hcd_term(void)
+{
+	tasklet_disable(&g_urb_process_tasklet);
+	tasklet_disable(&g_urb_cancel_tasklet);
+	platform_device_unregister(g_plat_dev);
+	platform_driver_unregister(&g_oz_plat_drv);
+	oz_trace("Pending urbs:%d\n", atomic_read(&g_pending_urbs));
+}
diff --git a/drivers/staging/ozwpan/ozhcd.h b/drivers/staging/ozwpan/ozhcd.h
new file mode 100644
index 0000000..9b30dfd
--- /dev/null
+++ b/drivers/staging/ozwpan/ozhcd.h
@@ -0,0 +1,15 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * ---------------------------------------------------------------------------*/
+#ifndef _OZHCD_H
+#define _OZHCD_H
+
+int oz_hcd_init(void);
+void oz_hcd_term(void);
+void *oz_hcd_pd_arrived(void *ctx);
+void oz_hcd_pd_departed(void *ctx);
+void oz_hcd_pd_reset(void *hpd, void *hport);
+
+#endif /* _OZHCD_H */
+
diff --git a/drivers/staging/ozwpan/ozmain.c b/drivers/staging/ozwpan/ozmain.c
new file mode 100644
index 0000000..aaf2ccc
--- /dev/null
+++ b/drivers/staging/ozwpan/ozmain.c
@@ -0,0 +1,58 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/errno.h>
+#include <linux/ieee80211.h>
+#include "ozconfig.h"
+#include "ozpd.h"
+#include "ozproto.h"
+#include "ozcdev.h"
+#include "oztrace.h"
+#include "ozevent.h"
+/*------------------------------------------------------------------------------
+ * The name of the 802.11 mac device. Empty string is the default value but a
+ * value can be supplied as a parameter to the module. An empty string means
+ * bind to nothing. '*' means bind to all netcards - this includes non-802.11
+ * netcards. Bindings can be added later using an IOCTL.
+ */
+char *g_net_dev = "";
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+static int __init ozwpan_init(void)
+{
+	oz_event_init();
+	oz_cdev_register();
+	oz_protocol_init(g_net_dev);
+	oz_app_enable(OZ_APPID_USB, 1);
+	oz_apps_init();
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+static void __exit ozwpan_exit(void)
+{
+	oz_protocol_term();
+	oz_apps_term();
+	oz_cdev_deregister();
+	oz_event_term();
+}
+/*------------------------------------------------------------------------------
+ */
+module_param(g_net_dev, charp, S_IRUGO);
+module_init(ozwpan_init);
+module_exit(ozwpan_exit);
+
+MODULE_AUTHOR("Chris Kelly");
+MODULE_DESCRIPTION("Ozmo Devices USB over WiFi hcd driver");
+MODULE_VERSION("1.0.8");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/staging/ozwpan/ozpd.c b/drivers/staging/ozwpan/ozpd.c
new file mode 100644
index 0000000..2b45d3d
--- /dev/null
+++ b/drivers/staging/ozwpan/ozpd.c
@@ -0,0 +1,832 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/errno.h>
+#include "ozconfig.h"
+#include "ozprotocol.h"
+#include "ozeltbuf.h"
+#include "ozpd.h"
+#include "ozproto.h"
+#include "oztrace.h"
+#include "ozevent.h"
+#include "ozcdev.h"
+#include "ozusbsvc.h"
+#include <asm/unaligned.h>
+#include <linux/uaccess.h>
+#include <net/psnap.h>
+/*------------------------------------------------------------------------------
+ */
+#define OZ_MAX_TX_POOL_SIZE	6
+/* Maximum number of uncompleted isoc frames that can be pending.
+ */
+#define OZ_MAX_SUBMITTED_ISOC	16
+/*------------------------------------------------------------------------------
+ */
+static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd);
+static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f);
+static struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f);
+static int oz_send_isoc_frame(struct oz_pd *pd);
+static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f);
+static void oz_isoc_stream_free(struct oz_isoc_stream *st);
+static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data);
+static void oz_isoc_destructor(struct sk_buff *skb);
+static int oz_def_app_init(void);
+static void oz_def_app_term(void);
+static int oz_def_app_start(struct oz_pd *pd, int resume);
+static void oz_def_app_stop(struct oz_pd *pd, int pause);
+static void oz_def_app_rx(struct oz_pd *pd, struct oz_elt *elt);
+/*------------------------------------------------------------------------------
+ * Counts the uncompleted isoc frames submitted to netcard.
+ */
+static atomic_t g_submitted_isoc = ATOMIC_INIT(0);
+/* Application handler functions.
+ */
+static struct oz_app_if g_app_if[OZ_APPID_MAX] = {
+	{oz_usb_init,
+	oz_usb_term,
+	oz_usb_start,
+	oz_usb_stop,
+	oz_usb_rx,
+	oz_usb_heartbeat,
+	oz_usb_farewell,
+	OZ_APPID_USB},
+
+	{oz_def_app_init,
+	oz_def_app_term,
+	oz_def_app_start,
+	oz_def_app_stop,
+	oz_def_app_rx,
+	0,
+	0,
+	OZ_APPID_UNUSED1},
+
+	{oz_def_app_init,
+	oz_def_app_term,
+	oz_def_app_start,
+	oz_def_app_stop,
+	oz_def_app_rx,
+	0,
+	0,
+	OZ_APPID_UNUSED2},
+
+	{oz_cdev_init,
+	oz_cdev_term,
+	oz_cdev_start,
+	oz_cdev_stop,
+	oz_cdev_rx,
+	0,
+	0,
+	OZ_APPID_SERIAL},
+};
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+static int oz_def_app_init(void)
+{
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+static void oz_def_app_term(void)
+{
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static int oz_def_app_start(struct oz_pd *pd, int resume)
+{
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static void oz_def_app_stop(struct oz_pd *pd, int pause)
+{
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static void oz_def_app_rx(struct oz_pd *pd, struct oz_elt *elt)
+{
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+void oz_pd_set_state(struct oz_pd *pd, unsigned state)
+{
+	pd->state = state;
+	oz_event_log(OZ_EVT_PD_STATE, 0, 0, 0, state);
+#ifdef WANT_TRACE
+	switch (state) {
+	case OZ_PD_S_IDLE:
+		oz_trace("PD State: OZ_PD_S_IDLE\n");
+		break;
+	case OZ_PD_S_CONNECTED:
+		oz_trace("PD State: OZ_PD_S_CONNECTED\n");
+		break;
+	case OZ_PD_S_STOPPED:
+		oz_trace("PD State: OZ_PD_S_STOPPED\n");
+		break;
+	case OZ_PD_S_SLEEP:
+		oz_trace("PD State: OZ_PD_S_SLEEP\n");
+		break;
+	}
+#endif /* WANT_TRACE */
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+void oz_pd_get(struct oz_pd *pd)
+{
+	atomic_inc(&pd->ref_count);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+void oz_pd_put(struct oz_pd *pd)
+{
+	if (atomic_dec_and_test(&pd->ref_count))
+		oz_pd_destroy(pd);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+struct oz_pd *oz_pd_alloc(u8 *mac_addr)
+{
+	struct oz_pd *pd = kzalloc(sizeof(struct oz_pd), GFP_ATOMIC);
+	if (pd) {
+		int i;
+		atomic_set(&pd->ref_count, 2);
+		for (i = 0; i < OZ_APPID_MAX; i++)
+			spin_lock_init(&pd->app_lock[i]);
+		pd->last_rx_pkt_num = 0xffffffff;
+		oz_pd_set_state(pd, OZ_PD_S_IDLE);
+		pd->max_tx_size = OZ_MAX_TX_SIZE;
+		memcpy(pd->mac_addr, mac_addr, ETH_ALEN);
+		if (0 != oz_elt_buf_init(&pd->elt_buff)) {
+			kfree(pd);
+			pd = 0;
+		}
+		spin_lock_init(&pd->tx_frame_lock);
+		INIT_LIST_HEAD(&pd->tx_queue);
+		INIT_LIST_HEAD(&pd->farewell_list);
+		pd->last_sent_frame = &pd->tx_queue;
+		spin_lock_init(&pd->stream_lock);
+		INIT_LIST_HEAD(&pd->stream_list);
+	}
+	return pd;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+void oz_pd_destroy(struct oz_pd *pd)
+{
+	struct list_head *e;
+	struct oz_tx_frame *f;
+	struct oz_isoc_stream *st;
+	struct oz_farewell *fwell;
+	oz_trace("Destroying PD\n");
+	/* Delete any streams.
+	 */
+	e = pd->stream_list.next;
+	while (e != &pd->stream_list) {
+		st = container_of(e, struct oz_isoc_stream, link);
+		e = e->next;
+		oz_isoc_stream_free(st);
+	}
+	/* Free any queued tx frames.
+	 */
+	e = pd->tx_queue.next;
+	while (e != &pd->tx_queue) {
+		f = container_of(e, struct oz_tx_frame, link);
+		e = e->next;
+		oz_retire_frame(pd, f);
+	}
+	oz_elt_buf_term(&pd->elt_buff);
+	/* Free any farewells.
+	 */
+	e = pd->farewell_list.next;
+	while (e != &pd->farewell_list) {
+		fwell = container_of(e, struct oz_farewell, link);
+		e = e->next;
+		kfree(fwell);
+	}
+	/* Deallocate all frames in tx pool.
+	 */
+	while (pd->tx_pool) {
+		e = pd->tx_pool;
+		pd->tx_pool = e->next;
+		kfree(container_of(e, struct oz_tx_frame, link));
+	}
+	if (pd->net_dev)
+		dev_put(pd->net_dev);
+	kfree(pd);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+int oz_services_start(struct oz_pd *pd, u16 apps, int resume)
+{
+	struct oz_app_if *ai;
+	int rc = 0;
+	oz_trace("oz_services_start(0x%x) resume(%d)\n", apps, resume);
+	for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
+		if (apps & (1<<ai->app_id)) {
+			if (ai->start(pd, resume)) {
+				rc = -1;
+				oz_trace("Unabled to start service %d\n",
+					ai->app_id);
+				break;
+			}
+			oz_polling_lock_bh();
+			pd->total_apps |= (1<<ai->app_id);
+			if (resume)
+				pd->paused_apps &= ~(1<<ai->app_id);
+			oz_polling_unlock_bh();
+		}
+	}
+	return rc;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+void oz_services_stop(struct oz_pd *pd, u16 apps, int pause)
+{
+	struct oz_app_if *ai;
+	oz_trace("oz_stop_services(0x%x) pause(%d)\n", apps, pause);
+	for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
+		if (apps & (1<<ai->app_id)) {
+			oz_polling_lock_bh();
+			if (pause) {
+				pd->paused_apps |= (1<<ai->app_id);
+			} else {
+				pd->total_apps &= ~(1<<ai->app_id);
+				pd->paused_apps &= ~(1<<ai->app_id);
+			}
+			oz_polling_unlock_bh();
+			ai->stop(pd, pause);
+		}
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+void oz_pd_heartbeat(struct oz_pd *pd, u16 apps)
+{
+	struct oz_app_if *ai;
+	int more = 0;
+	for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
+		if (ai->heartbeat && (apps & (1<<ai->app_id))) {
+			if (ai->heartbeat(pd))
+				more = 1;
+		}
+	}
+	if (more)
+		oz_pd_request_heartbeat(pd);
+	if (pd->mode & OZ_F_ISOC_ANYTIME) {
+		int count = 8;
+		while (count-- && (oz_send_isoc_frame(pd) >= 0))
+			;
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+void oz_pd_stop(struct oz_pd *pd)
+{
+	u16 stop_apps = 0;
+	oz_trace("oz_pd_stop() State = 0x%x\n", pd->state);
+	oz_pd_indicate_farewells(pd);
+	oz_polling_lock_bh();
+	stop_apps = pd->total_apps;
+	pd->total_apps = 0;
+	pd->paused_apps = 0;
+	oz_polling_unlock_bh();
+	oz_services_stop(pd, stop_apps, 0);
+	oz_polling_lock_bh();
+	oz_pd_set_state(pd, OZ_PD_S_STOPPED);
+	/* Remove from PD list.*/
+	list_del(&pd->link);
+	oz_polling_unlock_bh();
+	oz_trace("pd ref count = %d\n", atomic_read(&pd->ref_count));
+	oz_timer_delete(pd, 0);
+	oz_pd_put(pd);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+int oz_pd_sleep(struct oz_pd *pd)
+{
+	int do_stop = 0;
+	u16 stop_apps = 0;
+	oz_polling_lock_bh();
+	if (pd->state & (OZ_PD_S_SLEEP | OZ_PD_S_STOPPED)) {
+		oz_polling_unlock_bh();
+		return 0;
+	}
+	if (pd->keep_alive_j && pd->session_id) {
+		oz_pd_set_state(pd, OZ_PD_S_SLEEP);
+		pd->pulse_time_j = jiffies + pd->keep_alive_j;
+		oz_trace("Sleep Now %lu until %lu\n",
+			jiffies, pd->pulse_time_j);
+	} else {
+		do_stop = 1;
+	}
+	stop_apps = pd->total_apps;
+	oz_polling_unlock_bh();
+	if (do_stop) {
+		oz_pd_stop(pd);
+	} else {
+		oz_services_stop(pd, stop_apps, 1);
+		oz_timer_add(pd, OZ_TIMER_STOP, jiffies + pd->keep_alive_j, 1);
+	}
+	return do_stop;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd)
+{
+	struct oz_tx_frame *f = 0;
+	spin_lock_bh(&pd->tx_frame_lock);
+	if (pd->tx_pool) {
+		f = container_of(pd->tx_pool, struct oz_tx_frame, link);
+		pd->tx_pool = pd->tx_pool->next;
+		pd->tx_pool_count--;
+	}
+	spin_unlock_bh(&pd->tx_frame_lock);
+	if (f == 0)
+		f = kmalloc(sizeof(struct oz_tx_frame), GFP_ATOMIC);
+	if (f) {
+		f->total_size = sizeof(struct oz_hdr);
+		INIT_LIST_HEAD(&f->link);
+		INIT_LIST_HEAD(&f->elt_list);
+	}
+	return f;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
+{
+	spin_lock_bh(&pd->tx_frame_lock);
+	if (pd->tx_pool_count < OZ_MAX_TX_POOL_SIZE) {
+		f->link.next = pd->tx_pool;
+		pd->tx_pool = &f->link;
+		pd->tx_pool_count++;
+		f = 0;
+	} else {
+		kfree(f);
+	}
+	spin_unlock_bh(&pd->tx_frame_lock);
+	if (f)
+		kfree(f);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+int oz_prepare_frame(struct oz_pd *pd, int empty)
+{
+	struct oz_tx_frame *f;
+	if ((pd->mode & OZ_MODE_MASK) != OZ_MODE_TRIGGERED)
+		return -1;
+	if (pd->nb_queued_frames >= OZ_MAX_QUEUED_FRAMES)
+		return -1;
+	if (!empty && !oz_are_elts_available(&pd->elt_buff))
+		return -1;
+	f = oz_tx_frame_alloc(pd);
+	if (f == 0)
+		return -1;
+	f->hdr.control =
+		(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ACK_REQUESTED;
+	++pd->last_tx_pkt_num;
+	put_unaligned(cpu_to_le32(pd->last_tx_pkt_num), &f->hdr.pkt_num);
+	if (empty == 0) {
+		oz_select_elts_for_tx(&pd->elt_buff, 0, &f->total_size,
+			pd->max_tx_size, &f->elt_list);
+	}
+	spin_lock(&pd->tx_frame_lock);
+	list_add_tail(&f->link, &pd->tx_queue);
+	pd->nb_queued_frames++;
+	spin_unlock(&pd->tx_frame_lock);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+static struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f)
+{
+	struct sk_buff *skb = 0;
+	struct net_device *dev = pd->net_dev;
+	struct oz_hdr *oz_hdr;
+	struct oz_elt *elt;
+	struct list_head *e;
+	/* Allocate skb with enough space for the lower layers as well
+	 * as the space we need.
+	 */
+	skb = alloc_skb(f->total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
+	if (skb == 0)
+		return 0;
+	/* Reserve the head room for lower layers.
+	 */
+	skb_reserve(skb, LL_RESERVED_SPACE(dev));
+	skb_reset_network_header(skb);
+	skb->dev = dev;
+	skb->protocol = htons(OZ_ETHERTYPE);
+	if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
+		dev->dev_addr, skb->len) < 0)
+		goto fail;
+	/* Push the tail to the end of the area we are going to copy to.
+	 */
+	oz_hdr = (struct oz_hdr *)skb_put(skb, f->total_size);
+	f->hdr.last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
+	memcpy(oz_hdr, &f->hdr, sizeof(struct oz_hdr));
+	/* Copy the elements into the frame body.
+	 */
+	elt = (struct oz_elt *)(oz_hdr+1);
+	for (e = f->elt_list.next; e != &f->elt_list; e = e->next) {
+		struct oz_elt_info *ei;
+		ei = container_of(e, struct oz_elt_info, link);
+		memcpy(elt, ei->data, ei->length);
+		elt = oz_next_elt(elt);
+	}
+	return skb;
+fail:
+	kfree_skb(skb);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f)
+{
+	struct list_head *e;
+	struct oz_elt_info *ei;
+	e = f->elt_list.next;
+	while (e != &f->elt_list) {
+		ei = container_of(e, struct oz_elt_info, link);
+		e = e->next;
+		list_del_init(&ei->link);
+		if (ei->callback)
+			ei->callback(pd, ei->context);
+		spin_lock_bh(&pd->elt_buff.lock);
+		oz_elt_info_free(&pd->elt_buff, ei);
+		spin_unlock_bh(&pd->elt_buff.lock);
+	}
+	oz_tx_frame_free(pd, f);
+	if (pd->elt_buff.free_elts > pd->elt_buff.max_free_elts)
+		oz_trim_elt_pool(&pd->elt_buff);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data)
+{
+	struct sk_buff *skb;
+	struct oz_tx_frame *f;
+	struct list_head *e;
+	*more_data = 0;
+	spin_lock(&pd->tx_frame_lock);
+	e = pd->last_sent_frame->next;
+	if (e == &pd->tx_queue) {
+		spin_unlock(&pd->tx_frame_lock);
+		return -1;
+	}
+	pd->last_sent_frame = e;
+	if (e->next != &pd->tx_queue)
+		*more_data = 1;
+	f = container_of(e, struct oz_tx_frame, link);
+	skb = oz_build_frame(pd, f);
+	spin_unlock(&pd->tx_frame_lock);
+	oz_trace2(OZ_TRACE_TX_FRAMES, "TX frame PN=0x%x\n", f->hdr.pkt_num);
+	if (skb) {
+		oz_event_log(OZ_EVT_TX_FRAME,
+			0,
+			(((u16)f->hdr.control)<<8)|f->hdr.last_pkt_num,
+			0, f->hdr.pkt_num);
+		if (dev_queue_xmit(skb) < 0)
+			return -1;
+	}
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+void oz_send_queued_frames(struct oz_pd *pd, int backlog)
+{
+	int more;
+	if (backlog <  OZ_MAX_QUEUED_FRAMES) {
+		if (oz_send_next_queued_frame(pd, &more) >= 0) {
+			while (more && oz_send_next_queued_frame(pd, &more))
+				;
+		} else {
+			if (((pd->mode & OZ_F_ISOC_ANYTIME) == 0)
+				|| (pd->isoc_sent == 0)) {
+				if (oz_prepare_frame(pd, 1) >= 0)
+					oz_send_next_queued_frame(pd, &more);
+			}
+		}
+	} else {
+		oz_send_next_queued_frame(pd, &more);
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static int oz_send_isoc_frame(struct oz_pd *pd)
+{
+	struct sk_buff *skb = 0;
+	struct net_device *dev = pd->net_dev;
+	struct oz_hdr *oz_hdr;
+	struct oz_elt *elt;
+	struct list_head *e;
+	struct list_head list;
+	int total_size = sizeof(struct oz_hdr);
+	INIT_LIST_HEAD(&list);
+
+	oz_select_elts_for_tx(&pd->elt_buff, 1, &total_size,
+		pd->max_tx_size, &list);
+	if (list.next == &list)
+		return 0;
+	skb = alloc_skb(total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
+	if (skb == 0) {
+		oz_trace("Cannot alloc skb\n");
+		oz_elt_info_free_chain(&pd->elt_buff, &list);
+		return -1;
+	}
+	skb_reserve(skb, LL_RESERVED_SPACE(dev));
+	skb_reset_network_header(skb);
+	skb->dev = dev;
+	skb->protocol = htons(OZ_ETHERTYPE);
+	if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
+		dev->dev_addr, skb->len) < 0) {
+		kfree_skb(skb);
+		return -1;
+	}
+	oz_hdr = (struct oz_hdr *)skb_put(skb, total_size);
+	oz_hdr->control = (OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ISOC;
+	oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
+	elt = (struct oz_elt *)(oz_hdr+1);
+
+	for (e = list.next; e != &list; e = e->next) {
+		struct oz_elt_info *ei;
+		ei = container_of(e, struct oz_elt_info, link);
+		memcpy(elt, ei->data, ei->length);
+		elt = oz_next_elt(elt);
+	}
+	oz_event_log(OZ_EVT_TX_ISOC, 0, 0, 0, 0);
+	dev_queue_xmit(skb);
+	oz_elt_info_free_chain(&pd->elt_buff, &list);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn)
+{
+	struct list_head *e;
+	struct oz_tx_frame *f;
+	struct list_head *first = 0;
+	struct list_head *last = 0;
+	u8 diff;
+	u32 pkt_num;
+
+	spin_lock(&pd->tx_frame_lock);
+	e = pd->tx_queue.next;
+	while (e != &pd->tx_queue) {
+		f = container_of(e, struct oz_tx_frame, link);
+		pkt_num = le32_to_cpu(get_unaligned(&f->hdr.pkt_num));
+		diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK;
+		if (diff > OZ_LAST_PN_HALF_CYCLE)
+			break;
+		if (first == 0)
+			first = e;
+		last = e;
+		e = e->next;
+		pd->nb_queued_frames--;
+	}
+	if (first) {
+		last->next->prev = &pd->tx_queue;
+		pd->tx_queue.next = last->next;
+		last->next = 0;
+	}
+	pd->last_sent_frame = &pd->tx_queue;
+	spin_unlock(&pd->tx_frame_lock);
+	while (first) {
+		f = container_of(first, struct oz_tx_frame, link);
+		first = first->next;
+		oz_retire_frame(pd, f);
+	}
+}
+/*------------------------------------------------------------------------------
+ * Precondition: stream_lock must be held.
+ * Context: softirq
+ */
+static struct oz_isoc_stream *pd_stream_find(struct oz_pd *pd, u8 ep_num)
+{
+	struct list_head *e;
+	struct oz_isoc_stream *st;
+	list_for_each(e, &pd->stream_list) {
+		st = container_of(e, struct oz_isoc_stream, link);
+		if (st->ep_num == ep_num)
+			return st;
+	}
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+int oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num)
+{
+	struct oz_isoc_stream *st =
+		kzalloc(sizeof(struct oz_isoc_stream), GFP_ATOMIC);
+	if (!st)
+		return -ENOMEM;
+	st->ep_num = ep_num;
+	spin_lock_bh(&pd->stream_lock);
+	if (!pd_stream_find(pd, ep_num)) {
+		list_add(&st->link, &pd->stream_list);
+		st = 0;
+	}
+	spin_unlock_bh(&pd->stream_lock);
+	if (st)
+		kfree(st);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+static void oz_isoc_stream_free(struct oz_isoc_stream *st)
+{
+	if (st->skb)
+		kfree_skb(st->skb);
+	kfree(st);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+int oz_isoc_stream_delete(struct oz_pd *pd, u8 ep_num)
+{
+	struct oz_isoc_stream *st;
+	spin_lock_bh(&pd->stream_lock);
+	st = pd_stream_find(pd, ep_num);
+	if (st)
+		list_del(&st->link);
+	spin_unlock_bh(&pd->stream_lock);
+	if (st)
+		oz_isoc_stream_free(st);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: any
+ */
+static void oz_isoc_destructor(struct sk_buff *skb)
+{
+	atomic_dec(&g_submitted_isoc);
+	oz_event_log(OZ_EVT_TX_ISOC_DONE, atomic_read(&g_submitted_isoc),
+		0, skb, 0);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, u8 *data, int len)
+{
+	struct net_device *dev = pd->net_dev;
+	struct oz_isoc_stream *st;
+	u8 nb_units = 0;
+	struct sk_buff *skb = 0;
+	struct oz_hdr *oz_hdr = 0;
+	int size = 0;
+	spin_lock_bh(&pd->stream_lock);
+	st = pd_stream_find(pd, ep_num);
+	if (st) {
+		skb = st->skb;
+		st->skb = 0;
+		nb_units = st->nb_units;
+		st->nb_units = 0;
+		oz_hdr = st->oz_hdr;
+		size = st->size;
+	}
+	spin_unlock_bh(&pd->stream_lock);
+	if (!st)
+		return 0;
+	if (!skb) {
+		/* Allocate enough space for max size frame. */
+		skb = alloc_skb(pd->max_tx_size + OZ_ALLOCATED_SPACE(dev),
+				GFP_ATOMIC);
+		if (skb == 0)
+			return 0;
+		/* Reserve the head room for lower layers. */
+		skb_reserve(skb, LL_RESERVED_SPACE(dev));
+		skb_reset_network_header(skb);
+		skb->dev = dev;
+		skb->protocol = htons(OZ_ETHERTYPE);
+		size = sizeof(struct oz_hdr) + sizeof(struct oz_isoc_large);
+		oz_hdr = (struct oz_hdr *)skb_put(skb, size);
+	}
+	memcpy(skb_put(skb, len), data, len);
+	size += len;
+	if (++nb_units < pd->ms_per_isoc) {
+		spin_lock_bh(&pd->stream_lock);
+		st->skb = skb;
+		st->nb_units = nb_units;
+		st->oz_hdr = oz_hdr;
+		st->size = size;
+		spin_unlock_bh(&pd->stream_lock);
+	} else {
+		struct oz_hdr oz;
+		struct oz_isoc_large iso;
+		spin_lock_bh(&pd->stream_lock);
+		iso.frame_number = st->frame_num;
+		st->frame_num += nb_units;
+		spin_unlock_bh(&pd->stream_lock);
+		oz.control =
+			(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ISOC;
+		oz.last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
+		oz.pkt_num = 0;
+		iso.endpoint = ep_num;
+		iso.format = OZ_DATA_F_ISOC_LARGE;
+		iso.ms_data = nb_units;
+		memcpy(oz_hdr, &oz, sizeof(oz));
+		memcpy(oz_hdr+1, &iso, sizeof(iso));
+		if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
+				dev->dev_addr, skb->len) < 0) {
+			kfree_skb(skb);
+			return -1;
+		}
+		if (atomic_read(&g_submitted_isoc) < OZ_MAX_SUBMITTED_ISOC) {
+			skb->destructor = oz_isoc_destructor;
+			atomic_inc(&g_submitted_isoc);
+			oz_event_log(OZ_EVT_TX_ISOC, nb_units, iso.frame_number,
+				skb, atomic_read(&g_submitted_isoc));
+			if (dev_queue_xmit(skb) < 0)
+				return -1;
+		} else {
+			oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, 0, 0);
+			kfree_skb(skb);
+		}
+	}
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_apps_init(void)
+{
+	int i;
+	for (i = 0; i < OZ_APPID_MAX; i++)
+		if (g_app_if[i].init)
+			g_app_if[i].init();
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_apps_term(void)
+{
+	int i;
+	/* Terminate all the apps. */
+	for (i = 0; i < OZ_APPID_MAX; i++)
+		if (g_app_if[i].term)
+			g_app_if[i].term();
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+void oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt)
+{
+	struct oz_app_if *ai;
+	if (app_id == 0 || app_id > OZ_APPID_MAX)
+		return;
+	ai = &g_app_if[app_id-1];
+	ai->rx(pd, elt);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+void oz_pd_indicate_farewells(struct oz_pd *pd)
+{
+	struct oz_farewell *f;
+	struct oz_app_if *ai = &g_app_if[OZ_APPID_USB-1];
+	while (1) {
+		oz_polling_lock_bh();
+		if (list_empty(&pd->farewell_list)) {
+			oz_polling_unlock_bh();
+			break;
+		}
+		f = list_first_entry(&pd->farewell_list,
+				struct oz_farewell, link);
+		list_del(&f->link);
+		oz_polling_unlock_bh();
+		if (ai->farewell)
+			ai->farewell(pd, f->ep_num, f->report, f->len);
+		kfree(f);
+	}
+}
diff --git a/drivers/staging/ozwpan/ozpd.h b/drivers/staging/ozwpan/ozpd.h
new file mode 100644
index 0000000..afc77f0
--- /dev/null
+++ b/drivers/staging/ozwpan/ozpd.h
@@ -0,0 +1,121 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#ifndef _OZPD_H_
+#define _OZPD_H_
+
+#include "ozeltbuf.h"
+
+/* PD state
+ */
+#define OZ_PD_S_IDLE		0x1
+#define OZ_PD_S_CONNECTED	0x2
+#define OZ_PD_S_SLEEP		0x4
+#define OZ_PD_S_STOPPED		0x8
+
+/* Timer event types.
+ */
+#define OZ_TIMER_TOUT		1
+#define OZ_TIMER_HEARTBEAT	2
+#define OZ_TIMER_STOP		3
+
+/* Data structure that hold information on a frame for transmisson. This is
+ * built when the frame is first transmitted and is used to rebuild the frame
+ * if a re-transmission is required.
+ */
+struct oz_tx_frame {
+	struct list_head link;
+	struct list_head elt_list;
+	struct oz_hdr hdr;
+	int total_size;
+};
+
+struct oz_isoc_stream {
+	struct list_head link;
+	u8 ep_num;
+	u8 frame_num;
+	u8 nb_units;
+	int size;
+	struct sk_buff *skb;
+	struct oz_hdr *oz_hdr;
+};
+
+struct oz_farewell {
+	struct list_head link;
+	u8 ep_num;
+	u8 index;
+	u8 report[1];
+	u8 len;
+};
+
+/* Data structure that holds information on a specific peripheral device (PD).
+ */
+struct oz_pd {
+	struct list_head link;
+	atomic_t	ref_count;
+	u8		mac_addr[ETH_ALEN];
+	unsigned	state;
+	unsigned	state_flags;
+	unsigned	send_flags;
+	u16		total_apps;
+	u16		paused_apps;
+	u8		session_id;
+	u8		param_rsp_status;
+	u8		pd_info;
+	u8		isoc_sent;
+	u32		last_rx_pkt_num;
+	u32		last_tx_pkt_num;
+	u32		trigger_pkt_num;
+	unsigned long	pulse_time_j;
+	unsigned long	timeout_time_j;
+	unsigned long	pulse_period_j;
+	unsigned long	presleep_j;
+	unsigned long	keep_alive_j;
+	unsigned long	last_rx_time_j;
+	struct oz_elt_buf elt_buff;
+	void		*app_ctx[OZ_APPID_MAX];
+	spinlock_t	app_lock[OZ_APPID_MAX];
+	int		max_tx_size;
+	u8		heartbeat_requested;
+	u8		mode;
+	u8		ms_per_isoc;
+	unsigned	max_stream_buffering;
+	int		nb_queued_frames;
+	struct list_head *tx_pool;
+	int		tx_pool_count;
+	spinlock_t	tx_frame_lock;
+	struct list_head *last_sent_frame;
+	struct list_head tx_queue;
+	struct list_head farewell_list;
+	spinlock_t	stream_lock;
+	struct list_head stream_list;
+	struct net_device *net_dev;
+};
+
+#define OZ_MAX_QUEUED_FRAMES	4
+
+struct oz_pd *oz_pd_alloc(u8 *mac_addr);
+void oz_pd_destroy(struct oz_pd *pd);
+void oz_pd_get(struct oz_pd *pd);
+void oz_pd_put(struct oz_pd *pd);
+void oz_pd_set_state(struct oz_pd *pd, unsigned state);
+void oz_pd_indicate_farewells(struct oz_pd *pd);
+int oz_pd_sleep(struct oz_pd *pd);
+void oz_pd_stop(struct oz_pd *pd);
+void oz_pd_heartbeat(struct oz_pd *pd, u16 apps);
+int oz_services_start(struct oz_pd *pd, u16 apps, int resume);
+void oz_services_stop(struct oz_pd *pd, u16 apps, int pause);
+int oz_prepare_frame(struct oz_pd *pd, int empty);
+void oz_send_queued_frames(struct oz_pd *pd, int backlog);
+void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn);
+int oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num);
+int oz_isoc_stream_delete(struct oz_pd *pd, u8 ep_num);
+int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, u8 *data, int len);
+void oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt);
+void oz_apps_init(void);
+void oz_apps_term(void);
+
+#endif /* Sentry */
+
diff --git a/drivers/staging/ozwpan/ozproto.c b/drivers/staging/ozwpan/ozproto.c
new file mode 100644
index 0000000..ad857ee
--- /dev/null
+++ b/drivers/staging/ozwpan/ozproto.c
@@ -0,0 +1,957 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/errno.h>
+#include <linux/ieee80211.h>
+#include "ozconfig.h"
+#include "ozprotocol.h"
+#include "ozeltbuf.h"
+#include "ozpd.h"
+#include "ozproto.h"
+#include "ozusbsvc.h"
+#include "oztrace.h"
+#include "ozappif.h"
+#include "ozevent.h"
+#include <asm/unaligned.h>
+#include <linux/uaccess.h>
+#include <net/psnap.h>
+/*------------------------------------------------------------------------------
+ */
+#define OZ_CF_CONN_SUCCESS	1
+#define OZ_CF_CONN_FAILURE	2
+
+#define OZ_DO_STOP		1
+#define OZ_DO_SLEEP		2
+
+/* States of the timer.
+ */
+#define OZ_TIMER_IDLE		0
+#define OZ_TIMER_SET		1
+#define OZ_TIMER_IN_HANDLER	2
+
+#define OZ_MAX_TIMER_POOL_SIZE	16
+
+/*------------------------------------------------------------------------------
+ */
+struct oz_binding {
+	struct packet_type ptype;
+	char name[OZ_MAX_BINDING_LEN];
+	struct oz_binding *next;
+};
+
+struct oz_timer {
+	struct list_head link;
+	struct oz_pd *pd;
+	unsigned long due_time;
+	int type;
+};
+/*------------------------------------------------------------------------------
+ * Static external variables.
+ */
+static DEFINE_SPINLOCK(g_polling_lock);
+static LIST_HEAD(g_pd_list);
+static struct oz_binding *g_binding ;
+static DEFINE_SPINLOCK(g_binding_lock);
+static struct sk_buff_head g_rx_queue;
+static u8 g_session_id;
+static u16 g_apps = 0x1;
+static int g_processing_rx;
+static struct timer_list g_timer;
+static struct oz_timer *g_cur_timer;
+static struct list_head *g_timer_pool;
+static int g_timer_pool_count;
+static int g_timer_state = OZ_TIMER_IDLE;
+static LIST_HEAD(g_timer_list);
+/*------------------------------------------------------------------------------
+ */
+static void oz_protocol_timer_start(void);
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+static u8 oz_get_new_session_id(u8 exclude)
+{
+	if (++g_session_id == 0)
+		g_session_id = 1;
+	if (g_session_id == exclude) {
+		if (++g_session_id == 0)
+			g_session_id = 1;
+	}
+	return g_session_id;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+static void oz_send_conn_rsp(struct oz_pd *pd, u8 status)
+{
+	struct sk_buff *skb;
+	struct net_device *dev = pd->net_dev;
+	struct oz_hdr *oz_hdr;
+	struct oz_elt *elt;
+	struct oz_elt_connect_rsp *body;
+	int sz = sizeof(struct oz_hdr) + sizeof(struct oz_elt) +
+			sizeof(struct oz_elt_connect_rsp);
+	skb = alloc_skb(sz + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
+	if (skb == 0)
+		return;
+	skb_reserve(skb, LL_RESERVED_SPACE(dev));
+	skb_reset_network_header(skb);
+	oz_hdr = (struct oz_hdr *)skb_put(skb, sz);
+	elt = (struct oz_elt *)(oz_hdr+1);
+	body = (struct oz_elt_connect_rsp *)(elt+1);
+	skb->dev = dev;
+	skb->protocol = htons(OZ_ETHERTYPE);
+	/* Fill in device header */
+	if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
+			dev->dev_addr, skb->len) < 0) {
+		kfree_skb(skb);
+		return;
+	}
+	oz_hdr->control = (OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT);
+	oz_hdr->last_pkt_num = 0;
+	put_unaligned(0, &oz_hdr->pkt_num);
+	oz_event_log(OZ_EVT_CONNECT_RSP, 0, 0, 0, 0);
+	elt->type = OZ_ELT_CONNECT_RSP;
+	elt->length = sizeof(struct oz_elt_connect_rsp);
+	memset(body, 0, sizeof(struct oz_elt_connect_rsp));
+	body->status = status;
+	if (status == 0) {
+		body->mode = pd->mode;
+		body->session_id = pd->session_id;
+		put_unaligned(cpu_to_le16(pd->total_apps), &body->apps);
+	}
+	oz_trace("TX: OZ_ELT_CONNECT_RSP %d", status);
+	dev_queue_xmit(skb);
+	return;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+static void pd_set_keepalive(struct oz_pd *pd, u8 kalive)
+{
+	unsigned long keep_alive = kalive & OZ_KALIVE_VALUE_MASK;
+
+	switch (kalive & OZ_KALIVE_TYPE_MASK) {
+	case OZ_KALIVE_SPECIAL:
+		pd->keep_alive_j =
+			oz_ms_to_jiffies(keep_alive * 1000*60*60*24*20);
+		break;
+	case OZ_KALIVE_SECS:
+		pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000);
+		break;
+	case OZ_KALIVE_MINS:
+		pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000*60);
+		break;
+	case OZ_KALIVE_HOURS:
+		pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000*60*60);
+		break;
+	default:
+		pd->keep_alive_j = 0;
+	}
+	oz_trace("Keepalive = %lu jiffies\n", pd->keep_alive_j);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+static void pd_set_presleep(struct oz_pd *pd, u8 presleep)
+{
+	if (presleep)
+		pd->presleep_j = oz_ms_to_jiffies(presleep*100);
+	else
+		pd->presleep_j = OZ_PRESLEEP_TOUT_J;
+	oz_trace("Presleep time = %lu jiffies\n", pd->presleep_j);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt,
+			u8 *pd_addr, struct net_device *net_dev)
+{
+	struct oz_pd *pd;
+	struct oz_elt_connect_req *body =
+			(struct oz_elt_connect_req *)(elt+1);
+	u8 rsp_status = OZ_STATUS_SUCCESS;
+	u8 stop_needed = 0;
+	u16 new_apps = g_apps;
+	struct net_device *old_net_dev = 0;
+	struct oz_pd *free_pd = 0;
+	if (cur_pd) {
+		pd = cur_pd;
+		spin_lock_bh(&g_polling_lock);
+	} else {
+		struct oz_pd *pd2 = 0;
+		struct list_head *e;
+		pd = oz_pd_alloc(pd_addr);
+		if (pd == 0)
+			return 0;
+		pd->last_rx_time_j = jiffies;
+		spin_lock_bh(&g_polling_lock);
+		list_for_each(e, &g_pd_list) {
+			pd2 = container_of(e, struct oz_pd, link);
+			if (memcmp(pd2->mac_addr, pd_addr, ETH_ALEN) == 0) {
+				free_pd = pd;
+				pd = pd2;
+				break;
+			}
+		}
+		if (pd != pd2)
+			list_add_tail(&pd->link, &g_pd_list);
+	}
+	if (pd == 0) {
+		spin_unlock_bh(&g_polling_lock);
+		return 0;
+	}
+	if (pd->net_dev != net_dev) {
+		old_net_dev = pd->net_dev;
+		dev_hold(net_dev);
+		pd->net_dev = net_dev;
+	}
+	oz_trace("Host vendor: %d\n", body->host_vendor);
+	pd->max_tx_size = OZ_MAX_TX_SIZE;
+	pd->mode = body->mode;
+	pd->pd_info = body->pd_info;
+	if (pd->mode & OZ_F_ISOC_NO_ELTS) {
+		pd->mode |= OZ_F_ISOC_ANYTIME;
+		pd->ms_per_isoc = body->ms_per_isoc;
+		if (!pd->ms_per_isoc)
+			pd->ms_per_isoc = 4;
+	}
+	if (body->max_len_div16)
+		pd->max_tx_size = ((u16)body->max_len_div16)<<4;
+	oz_trace("Max frame:%u Ms per isoc:%u\n",
+		pd->max_tx_size, pd->ms_per_isoc);
+	pd->max_stream_buffering = 3*1024;
+	pd->timeout_time_j = jiffies + OZ_CONNECTION_TOUT_J;
+	pd->pulse_period_j = OZ_QUANTUM_J;
+	pd_set_presleep(pd, body->presleep);
+	pd_set_keepalive(pd, body->keep_alive);
+
+	new_apps &= le16_to_cpu(get_unaligned(&body->apps));
+	if ((new_apps & 0x1) && (body->session_id)) {
+		if (pd->session_id) {
+			if (pd->session_id != body->session_id) {
+				rsp_status = OZ_STATUS_SESSION_MISMATCH;
+				goto done;
+			}
+		} else {
+			new_apps &= ~0x1;  /* Resume not permitted */
+			pd->session_id =
+				oz_get_new_session_id(body->session_id);
+		}
+	} else {
+		if (pd->session_id && !body->session_id) {
+			rsp_status = OZ_STATUS_SESSION_TEARDOWN;
+			stop_needed = 1;
+		} else {
+			new_apps &= ~0x1;  /* Resume not permitted */
+			pd->session_id =
+				oz_get_new_session_id(body->session_id);
+		}
+	}
+done:
+	if (rsp_status == OZ_STATUS_SUCCESS) {
+		u16 start_apps = new_apps & ~pd->total_apps & ~0x1;
+		u16 stop_apps = pd->total_apps & ~new_apps & ~0x1;
+		u16 resume_apps = new_apps & pd->paused_apps  & ~0x1;
+		spin_unlock_bh(&g_polling_lock);
+		oz_pd_set_state(pd, OZ_PD_S_CONNECTED);
+		oz_timer_delete(pd, OZ_TIMER_STOP);
+		oz_trace("new_apps=0x%x total_apps=0x%x paused_apps=0x%x\n",
+			new_apps, pd->total_apps, pd->paused_apps);
+		if (start_apps) {
+			if (oz_services_start(pd, start_apps, 0))
+				rsp_status = OZ_STATUS_TOO_MANY_PDS;
+		}
+		if (resume_apps)
+			if (oz_services_start(pd, resume_apps, 1))
+				rsp_status = OZ_STATUS_TOO_MANY_PDS;
+		if (stop_apps)
+			oz_services_stop(pd, stop_apps, 0);
+		oz_pd_request_heartbeat(pd);
+	} else {
+		spin_unlock_bh(&g_polling_lock);
+	}
+	oz_send_conn_rsp(pd, rsp_status);
+	if (rsp_status != OZ_STATUS_SUCCESS) {
+		if (stop_needed)
+			oz_pd_stop(pd);
+		oz_pd_put(pd);
+		pd = 0;
+	}
+	if (old_net_dev)
+		dev_put(old_net_dev);
+	if (free_pd)
+		oz_pd_destroy(free_pd);
+	return pd;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+static void oz_add_farewell(struct oz_pd *pd, u8 ep_num, u8 index,
+			u8 *report, u8 len)
+{
+	struct oz_farewell *f;
+	struct oz_farewell *f2;
+	int found = 0;
+	f = kmalloc(sizeof(struct oz_farewell) + len - 1, GFP_ATOMIC);
+	if (!f)
+		return;
+	f->ep_num = ep_num;
+	f->index = index;
+	memcpy(f->report, report, len);
+	oz_trace("RX: Adding farewell report\n");
+	spin_lock(&g_polling_lock);
+	list_for_each_entry(f2, &pd->farewell_list, link) {
+		if ((f2->ep_num == ep_num) && (f2->index == index)) {
+			found = 1;
+			list_del(&f2->link);
+			break;
+		}
+	}
+	list_add_tail(&f->link, &pd->farewell_list);
+	spin_unlock(&g_polling_lock);
+	if (found)
+		kfree(f2);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+static void oz_rx_frame(struct sk_buff *skb)
+{
+	u8 *mac_hdr;
+	u8 *src_addr;
+	struct oz_elt *elt;
+	int length;
+	struct oz_pd *pd = 0;
+	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
+	int dup = 0;
+	u32 pkt_num;
+
+	oz_event_log(OZ_EVT_RX_PROCESS, 0,
+		(((u16)oz_hdr->control)<<8)|oz_hdr->last_pkt_num,
+		0, oz_hdr->pkt_num);
+	oz_trace2(OZ_TRACE_RX_FRAMES,
+		"RX frame PN=0x%x LPN=0x%x control=0x%x\n",
+		oz_hdr->pkt_num, oz_hdr->last_pkt_num, oz_hdr->control);
+	mac_hdr = skb_mac_header(skb);
+	src_addr = &mac_hdr[ETH_ALEN] ;
+	length = skb->len;
+
+	/* Check the version field */
+	if (oz_get_prot_ver(oz_hdr->control) != OZ_PROTOCOL_VERSION) {
+		oz_trace("Incorrect protocol version: %d\n",
+			oz_get_prot_ver(oz_hdr->control));
+		goto done;
+	}
+
+	pkt_num = le32_to_cpu(get_unaligned(&oz_hdr->pkt_num));
+
+	pd = oz_pd_find(src_addr);
+	if (pd) {
+		pd->last_rx_time_j = jiffies;
+		oz_timer_add(pd, OZ_TIMER_TOUT,
+			pd->last_rx_time_j + pd->presleep_j, 1);
+		if (pkt_num != pd->last_rx_pkt_num) {
+			pd->last_rx_pkt_num = pkt_num;
+		} else {
+			dup = 1;
+			oz_trace("Duplicate frame\n");
+		}
+	}
+
+	if (pd && !dup && ((pd->mode & OZ_MODE_MASK) == OZ_MODE_TRIGGERED)) {
+		pd->last_sent_frame = &pd->tx_queue;
+		if (oz_hdr->control & OZ_F_ACK) {
+			/* Retire completed frames */
+			oz_retire_tx_frames(pd, oz_hdr->last_pkt_num);
+		}
+		if ((oz_hdr->control & OZ_F_ACK_REQUESTED) &&
+				(pd->state == OZ_PD_S_CONNECTED)) {
+			int backlog = pd->nb_queued_frames;
+			pd->trigger_pkt_num = pkt_num;
+			/* Send queued frames */
+			while (oz_prepare_frame(pd, 0) >= 0)
+				;
+			oz_send_queued_frames(pd, backlog);
+		}
+	}
+
+	length -= sizeof(struct oz_hdr);
+	elt = (struct oz_elt *)((u8 *)oz_hdr + sizeof(struct oz_hdr));
+
+	while (length >= sizeof(struct oz_elt)) {
+		length -= sizeof(struct oz_elt) + elt->length;
+		if (length < 0)
+			break;
+		switch (elt->type) {
+		case OZ_ELT_CONNECT_REQ:
+			oz_event_log(OZ_EVT_CONNECT_REQ, 0, 0, 0, 0);
+			oz_trace("RX: OZ_ELT_CONNECT_REQ\n");
+			pd = oz_connect_req(pd, elt, src_addr, skb->dev);
+			break;
+		case OZ_ELT_DISCONNECT:
+			oz_trace("RX: OZ_ELT_DISCONNECT\n");
+			if (pd)
+				oz_pd_sleep(pd);
+			break;
+		case OZ_ELT_UPDATE_PARAM_REQ: {
+				struct oz_elt_update_param *body =
+					(struct oz_elt_update_param *)(elt + 1);
+				oz_trace("RX: OZ_ELT_UPDATE_PARAM_REQ\n");
+				if (pd && (pd->state & OZ_PD_S_CONNECTED)) {
+					spin_lock(&g_polling_lock);
+					pd_set_keepalive(pd, body->keepalive);
+					pd_set_presleep(pd, body->presleep);
+					spin_unlock(&g_polling_lock);
+				}
+			}
+			break;
+		case OZ_ELT_FAREWELL_REQ: {
+				struct oz_elt_farewell *body =
+					(struct oz_elt_farewell *)(elt + 1);
+				oz_trace("RX: OZ_ELT_FAREWELL_REQ\n");
+				oz_add_farewell(pd, body->ep_num,
+					body->index, body->report,
+					elt->length + 1 - sizeof(*body));
+			}
+			break;
+		case OZ_ELT_APP_DATA:
+			if (pd && (pd->state & OZ_PD_S_CONNECTED)) {
+				struct oz_app_hdr *app_hdr =
+					(struct oz_app_hdr *)(elt+1);
+				if (dup)
+					break;
+				oz_handle_app_elt(pd, app_hdr->app_id, elt);
+			}
+			break;
+		default:
+			oz_trace("RX: Unknown elt %02x\n", elt->type);
+		}
+		elt = oz_next_elt(elt);
+	}
+done:
+	if (pd)
+		oz_pd_put(pd);
+	consume_skb(skb);
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_protocol_term(void)
+{
+	struct list_head *chain = 0;
+	del_timer_sync(&g_timer);
+	/* Walk the list of bindings and remove each one.
+	 */
+	spin_lock_bh(&g_binding_lock);
+	while (g_binding) {
+		struct oz_binding *b = g_binding;
+		g_binding = b->next;
+		spin_unlock_bh(&g_binding_lock);
+		dev_remove_pack(&b->ptype);
+		if (b->ptype.dev)
+			dev_put(b->ptype.dev);
+		kfree(b);
+		spin_lock_bh(&g_binding_lock);
+	}
+	spin_unlock_bh(&g_binding_lock);
+	/* Walk the list of PDs and stop each one. This causes the PD to be
+	 * removed from the list so we can just pull each one from the head
+	 * of the list.
+	 */
+	spin_lock_bh(&g_polling_lock);
+	while (!list_empty(&g_pd_list)) {
+		struct oz_pd *pd =
+			list_first_entry(&g_pd_list, struct oz_pd, link);
+		oz_pd_get(pd);
+		spin_unlock_bh(&g_polling_lock);
+		oz_pd_stop(pd);
+		oz_pd_put(pd);
+		spin_lock_bh(&g_polling_lock);
+	}
+	chain = g_timer_pool;
+	g_timer_pool = 0;
+	spin_unlock_bh(&g_polling_lock);
+	while (chain) {
+		struct oz_timer *t = container_of(chain, struct oz_timer, link);
+		chain = chain->next;
+		kfree(t);
+	}
+	oz_trace("Protocol stopped\n");
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static void oz_pd_handle_timer(struct oz_pd *pd, int type)
+{
+	switch (type) {
+	case OZ_TIMER_TOUT:
+		oz_pd_sleep(pd);
+		break;
+	case OZ_TIMER_STOP:
+		oz_pd_stop(pd);
+		break;
+	case OZ_TIMER_HEARTBEAT: {
+			u16 apps = 0;
+			spin_lock_bh(&g_polling_lock);
+			pd->heartbeat_requested = 0;
+			if (pd->state & OZ_PD_S_CONNECTED)
+				apps = pd->total_apps;
+			spin_unlock_bh(&g_polling_lock);
+			if (apps)
+				oz_pd_heartbeat(pd, apps);
+		}
+		break;
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static void oz_protocol_timer(unsigned long arg)
+{
+	struct oz_timer *t;
+	struct oz_timer *t2;
+	struct oz_pd *pd;
+	spin_lock_bh(&g_polling_lock);
+	if (!g_cur_timer) {
+		/* This happens if we remove the current timer but can't stop
+		 * the timer from firing. In this case just get out.
+		 */
+		oz_event_log(OZ_EVT_TIMER, 0, 0, 0, 0);
+		spin_unlock_bh(&g_polling_lock);
+		return;
+	}
+	g_timer_state = OZ_TIMER_IN_HANDLER;
+	t = g_cur_timer;
+	g_cur_timer = 0;
+	list_del(&t->link);
+	spin_unlock_bh(&g_polling_lock);
+	do {
+		pd = t->pd;
+		oz_event_log(OZ_EVT_TIMER, 0, t->type, 0, 0);
+		oz_pd_handle_timer(pd, t->type);
+		spin_lock_bh(&g_polling_lock);
+		if (g_timer_pool_count < OZ_MAX_TIMER_POOL_SIZE) {
+			t->link.next = g_timer_pool;
+			g_timer_pool = &t->link;
+			g_timer_pool_count++;
+			t = 0;
+		}
+		if (!list_empty(&g_timer_list)) {
+			t2 =  container_of(g_timer_list.next,
+				struct oz_timer, link);
+			if (time_before_eq(t2->due_time, jiffies))
+				list_del(&t2->link);
+			else
+				t2 = 0;
+		} else {
+			t2 = 0;
+		}
+		spin_unlock_bh(&g_polling_lock);
+		oz_pd_put(pd);
+		if (t)
+			kfree(t);
+		t = t2;
+	} while (t);
+	g_timer_state = OZ_TIMER_IDLE;
+	oz_protocol_timer_start();
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static void oz_protocol_timer_start(void)
+{
+	spin_lock_bh(&g_polling_lock);
+	if (!list_empty(&g_timer_list)) {
+		g_cur_timer =
+			container_of(g_timer_list.next, struct oz_timer, link);
+		if (g_timer_state == OZ_TIMER_SET) {
+			oz_event_log(OZ_EVT_TIMER_CTRL, 3,
+				(u16)g_cur_timer->type, 0,
+				(unsigned)g_cur_timer->due_time);
+			mod_timer(&g_timer, g_cur_timer->due_time);
+		} else {
+			oz_event_log(OZ_EVT_TIMER_CTRL, 4,
+				(u16)g_cur_timer->type, 0,
+				(unsigned)g_cur_timer->due_time);
+			g_timer.expires = g_cur_timer->due_time;
+			g_timer.function = oz_protocol_timer;
+			g_timer.data = 0;
+			add_timer(&g_timer);
+		}
+		g_timer_state = OZ_TIMER_SET;
+	} else {
+		oz_trace("No queued timers\n");
+	}
+	spin_unlock_bh(&g_polling_lock);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time,
+		int remove)
+{
+	struct list_head *e;
+	struct oz_timer *t = 0;
+	int restart_needed = 0;
+	oz_event_log(OZ_EVT_TIMER_CTRL, 1, (u16)type, 0, (unsigned)due_time);
+	spin_lock(&g_polling_lock);
+	if (remove) {
+		list_for_each(e, &g_timer_list) {
+			t = container_of(e, struct oz_timer, link);
+			if ((t->pd == pd) && (t->type == type)) {
+				if (g_cur_timer == t) {
+					restart_needed = 1;
+					g_cur_timer = 0;
+				}
+				list_del(e);
+				break;
+			}
+			t = 0;
+		}
+	}
+	if (!t) {
+		if (g_timer_pool) {
+			t = container_of(g_timer_pool, struct oz_timer, link);
+			g_timer_pool = g_timer_pool->next;
+			g_timer_pool_count--;
+		} else {
+			t = kmalloc(sizeof(struct oz_timer), GFP_ATOMIC);
+		}
+		if (t) {
+			t->pd = pd;
+			t->type = type;
+			oz_pd_get(pd);
+		}
+	}
+	if (t) {
+		struct oz_timer *t2;
+		t->due_time = due_time;
+		list_for_each(e, &g_timer_list) {
+			t2 = container_of(e, struct oz_timer, link);
+			if (time_before(due_time, t2->due_time)) {
+				if (t2 == g_cur_timer) {
+					g_cur_timer = 0;
+					restart_needed = 1;
+				}
+				break;
+			}
+		}
+		list_add_tail(&t->link, e);
+	}
+	if (g_timer_state == OZ_TIMER_IDLE)
+		restart_needed = 1;
+	else if (g_timer_state == OZ_TIMER_IN_HANDLER)
+		restart_needed = 0;
+	spin_unlock(&g_polling_lock);
+	if (restart_needed)
+		oz_protocol_timer_start();
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+void oz_timer_delete(struct oz_pd *pd, int type)
+{
+	struct list_head *chain = 0;
+	struct oz_timer *t;
+	struct oz_timer *n;
+	int restart_needed = 0;
+	int release = 0;
+	oz_event_log(OZ_EVT_TIMER_CTRL, 2, (u16)type, 0, 0);
+	spin_lock(&g_polling_lock);
+	list_for_each_entry_safe(t, n, &g_timer_list, link) {
+		if ((t->pd == pd) && ((type == 0) || (t->type == type))) {
+			if (g_cur_timer == t) {
+				restart_needed = 1;
+				g_cur_timer = 0;
+				del_timer(&g_timer);
+			}
+			list_del(&t->link);
+			release++;
+			if (g_timer_pool_count < OZ_MAX_TIMER_POOL_SIZE) {
+				t->link.next = g_timer_pool;
+				g_timer_pool = &t->link;
+				g_timer_pool_count++;
+			} else {
+				t->link.next = chain;
+				chain = &t->link;
+			}
+			if (type)
+				break;
+		}
+	}
+	if (g_timer_state == OZ_TIMER_IN_HANDLER)
+		restart_needed = 0;
+	else if (restart_needed)
+		g_timer_state = OZ_TIMER_IDLE;
+	spin_unlock(&g_polling_lock);
+	if (restart_needed)
+		oz_protocol_timer_start();
+	while (release--)
+		oz_pd_put(pd);
+	while (chain) {
+		t = container_of(chain, struct oz_timer, link);
+		chain = chain->next;
+		kfree(t);
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+void oz_pd_request_heartbeat(struct oz_pd *pd)
+{
+	unsigned long now = jiffies;
+	unsigned long t;
+	spin_lock(&g_polling_lock);
+	if (pd->heartbeat_requested) {
+		spin_unlock(&g_polling_lock);
+		return;
+	}
+	if (pd->pulse_period_j)
+		t = ((now / pd->pulse_period_j) + 1) * pd->pulse_period_j;
+	else
+		t = now + 1;
+	pd->heartbeat_requested = 1;
+	spin_unlock(&g_polling_lock);
+	oz_timer_add(pd, OZ_TIMER_HEARTBEAT, t, 0);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+struct oz_pd *oz_pd_find(u8 *mac_addr)
+{
+	struct oz_pd *pd;
+	struct list_head *e;
+	spin_lock_bh(&g_polling_lock);
+	list_for_each(e, &g_pd_list) {
+		pd = container_of(e, struct oz_pd, link);
+		if (memcmp(pd->mac_addr, mac_addr, ETH_ALEN) == 0) {
+			atomic_inc(&pd->ref_count);
+			spin_unlock_bh(&g_polling_lock);
+			return pd;
+		}
+	}
+	spin_unlock_bh(&g_polling_lock);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_app_enable(int app_id, int enable)
+{
+	if (app_id <= OZ_APPID_MAX) {
+		spin_lock_bh(&g_polling_lock);
+		if (enable)
+			g_apps |= (1<<app_id);
+		else
+			g_apps &= ~(1<<app_id);
+		spin_unlock_bh(&g_polling_lock);
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static int oz_pkt_recv(struct sk_buff *skb, struct net_device *dev,
+		struct packet_type *pt, struct net_device *orig_dev)
+{
+	oz_event_log(OZ_EVT_RX_FRAME, 0, 0, 0, 0);
+	skb = skb_share_check(skb, GFP_ATOMIC);
+	if (skb == 0)
+		return 0;
+	spin_lock_bh(&g_rx_queue.lock);
+	if (g_processing_rx) {
+		/* We already hold the lock so use __ variant.
+		 */
+		__skb_queue_head(&g_rx_queue, skb);
+		spin_unlock_bh(&g_rx_queue.lock);
+	} else {
+		g_processing_rx = 1;
+		do {
+
+			spin_unlock_bh(&g_rx_queue.lock);
+			oz_rx_frame(skb);
+			spin_lock_bh(&g_rx_queue.lock);
+			if (skb_queue_empty(&g_rx_queue)) {
+				g_processing_rx = 0;
+				spin_unlock_bh(&g_rx_queue.lock);
+				break;
+			}
+			/* We already hold the lock so use __ variant.
+			 */
+			skb = __skb_dequeue(&g_rx_queue);
+		} while (1);
+	}
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_binding_add(char *net_dev)
+{
+	struct oz_binding *binding;
+
+	binding = kmalloc(sizeof(struct oz_binding), GFP_ATOMIC);
+	if (binding) {
+		binding->ptype.type = __constant_htons(OZ_ETHERTYPE);
+		binding->ptype.func = oz_pkt_recv;
+		memcpy(binding->name, net_dev, OZ_MAX_BINDING_LEN);
+		if (net_dev && *net_dev) {
+			oz_trace("Adding binding: %s\n", net_dev);
+			binding->ptype.dev =
+				dev_get_by_name(&init_net, net_dev);
+			if (binding->ptype.dev == 0) {
+				oz_trace("Netdev %s not found\n", net_dev);
+				kfree(binding);
+				binding = 0;
+			}
+		} else {
+			oz_trace("Binding to all netcards\n");
+			binding->ptype.dev = 0;
+		}
+		if (binding) {
+			dev_add_pack(&binding->ptype);
+			spin_lock_bh(&g_binding_lock);
+			binding->next = g_binding;
+			g_binding = binding;
+			spin_unlock_bh(&g_binding_lock);
+		}
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+static int compare_binding_name(char *s1, char *s2)
+{
+	int i;
+	for (i = 0; i < OZ_MAX_BINDING_LEN; i++) {
+		if (*s1 != *s2)
+			return 0;
+		if (!*s1++)
+			return 1;
+		s2++;
+	}
+	return 1;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+static void pd_stop_all_for_device(struct net_device *net_dev)
+{
+	struct list_head h;
+	struct oz_pd *pd;
+	struct oz_pd *n;
+	INIT_LIST_HEAD(&h);
+	spin_lock_bh(&g_polling_lock);
+	list_for_each_entry_safe(pd, n, &g_pd_list, link) {
+		if (pd->net_dev == net_dev) {
+			list_move(&pd->link, &h);
+			oz_pd_get(pd);
+		}
+	}
+	spin_unlock_bh(&g_polling_lock);
+	while (!list_empty(&h)) {
+		pd = list_first_entry(&h, struct oz_pd, link);
+		oz_pd_stop(pd);
+		oz_pd_put(pd);
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_binding_remove(char *net_dev)
+{
+	struct oz_binding *binding = 0;
+	struct oz_binding **link;
+	oz_trace("Removing binding: %s\n", net_dev);
+	spin_lock_bh(&g_binding_lock);
+	binding = g_binding;
+	link = &g_binding;
+	while (binding) {
+		if (compare_binding_name(binding->name, net_dev)) {
+			oz_trace("Binding '%s' found\n", net_dev);
+			*link = binding->next;
+			break;
+		} else {
+			link = &binding;
+			binding = binding->next;
+		}
+	}
+	spin_unlock_bh(&g_binding_lock);
+	if (binding) {
+		dev_remove_pack(&binding->ptype);
+		if (binding->ptype.dev) {
+			dev_put(binding->ptype.dev);
+			pd_stop_all_for_device(binding->ptype.dev);
+		}
+		kfree(binding);
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+static char *oz_get_next_device_name(char *s, char *dname, int max_size)
+{
+	while (*s == ',')
+		s++;
+	while (*s && (*s != ',') && max_size > 1) {
+		*dname++ = *s++;
+		max_size--;
+	}
+	*dname = 0;
+	return s;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_protocol_init(char *devs)
+{
+	skb_queue_head_init(&g_rx_queue);
+	if (devs && (devs[0] == '*')) {
+		oz_binding_add(0);
+	} else {
+		char d[32];
+		while (*devs) {
+			devs = oz_get_next_device_name(devs, d, sizeof(d));
+			if (d[0])
+				oz_binding_add(d);
+		}
+	}
+	init_timer(&g_timer);
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_get_pd_list(struct oz_mac_addr *addr, int max_count)
+{
+	struct oz_pd *pd;
+	struct list_head *e;
+	int count = 0;
+	spin_lock_bh(&g_polling_lock);
+	list_for_each(e, &g_pd_list) {
+		if (count >= max_count)
+			break;
+		pd = container_of(e, struct oz_pd, link);
+		memcpy(&addr[count++], pd->mac_addr, ETH_ALEN);
+	}
+	spin_unlock_bh(&g_polling_lock);
+	return count;
+}
+/*------------------------------------------------------------------------------
+*/
+void oz_polling_lock_bh(void)
+{
+	spin_lock_bh(&g_polling_lock);
+}
+/*------------------------------------------------------------------------------
+*/
+void oz_polling_unlock_bh(void)
+{
+	spin_unlock_bh(&g_polling_lock);
+}
diff --git a/drivers/staging/ozwpan/ozproto.h b/drivers/staging/ozwpan/ozproto.h
new file mode 100644
index 0000000..89aea28
--- /dev/null
+++ b/drivers/staging/ozwpan/ozproto.h
@@ -0,0 +1,69 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#ifndef _OZPROTO_H
+#define _OZPROTO_H
+
+#include <asm/byteorder.h>
+#include "ozconfig.h"
+#include "ozappif.h"
+
+#define OZ_ALLOCATED_SPACE(__x)	(LL_RESERVED_SPACE(__x)+(__x)->needed_tailroom)
+
+/* Converts millisecs to jiffies.
+ */
+#define oz_ms_to_jiffies(__x)	(((__x)*1000)/HZ)
+
+/* Quantum milliseconds.
+ */
+#define OZ_QUANTUM_MS		8
+/* Quantum jiffies
+ */
+#define OZ_QUANTUM_J		(oz_ms_to_jiffies(OZ_QUANTUM_MS))
+/* Default timeouts.
+ */
+#define OZ_CONNECTION_TOUT_J	(2*HZ)
+#define OZ_PRESLEEP_TOUT_J	(11*HZ)
+
+/* Maximun sizes of tx frames. */
+#define OZ_MAX_TX_SIZE		1514
+
+/* Application handler functions.
+ */
+typedef int (*oz_app_init_fn_t)(void);
+typedef void (*oz_app_term_fn_t)(void);
+typedef int (*oz_app_start_fn_t)(struct oz_pd *pd, int resume);
+typedef void (*oz_app_stop_fn_t)(struct oz_pd *pd, int pause);
+typedef void (*oz_app_rx_fn_t)(struct oz_pd *pd, struct oz_elt *elt);
+typedef int (*oz_app_hearbeat_fn_t)(struct oz_pd *pd);
+typedef void (*oz_app_farewell_fn_t)(struct oz_pd *pd, u8 ep_num,
+			u8 *data, u8 len);
+
+struct oz_app_if {
+	oz_app_init_fn_t	init;
+	oz_app_term_fn_t	term;
+	oz_app_start_fn_t	start;
+	oz_app_stop_fn_t	stop;
+	oz_app_rx_fn_t		rx;
+	oz_app_hearbeat_fn_t	heartbeat;
+	oz_app_farewell_fn_t	farewell;
+	int			app_id;
+};
+
+int oz_protocol_init(char *devs);
+void oz_protocol_term(void);
+int oz_get_pd_list(struct oz_mac_addr *addr, int max_count);
+void oz_app_enable(int app_id, int enable);
+struct oz_pd *oz_pd_find(u8 *mac_addr);
+void oz_binding_add(char *net_dev);
+void oz_binding_remove(char *net_dev);
+void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time,
+		int remove);
+void oz_timer_delete(struct oz_pd *pd, int type);
+void oz_pd_request_heartbeat(struct oz_pd *pd);
+void oz_polling_lock_bh(void);
+void oz_polling_unlock_bh(void);
+
+#endif /* _OZPROTO_H */
diff --git a/drivers/staging/ozwpan/ozprotocol.h b/drivers/staging/ozwpan/ozprotocol.h
new file mode 100644
index 0000000..b3e7d77
--- /dev/null
+++ b/drivers/staging/ozwpan/ozprotocol.h
@@ -0,0 +1,372 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#ifndef _OZPROTOCOL_H
+#define _OZPROTOCOL_H
+
+#define PACKED __packed
+
+#define OZ_ETHERTYPE 0x892e
+
+/* Status codes
+ */
+#define OZ_STATUS_SUCCESS		0
+#define OZ_STATUS_INVALID_PARAM		1
+#define OZ_STATUS_TOO_MANY_PDS		2
+#define OZ_STATUS_NOT_ALLOWED		4
+#define OZ_STATUS_SESSION_MISMATCH	5
+#define OZ_STATUS_SESSION_TEARDOWN	6
+
+/* This is the generic element header.
+   Every element starts with this.
+ */
+struct oz_elt {
+	u8 type;
+	u8 length;
+} PACKED;
+
+#define oz_next_elt(__elt)	\
+	(struct oz_elt *)((u8 *)((__elt) + 1) + (__elt)->length)
+
+/* Protocol element IDs.
+ */
+#define OZ_ELT_CONNECT_REQ	0x06
+#define OZ_ELT_CONNECT_RSP	0x07
+#define OZ_ELT_DISCONNECT	0x08
+#define OZ_ELT_UPDATE_PARAM_REQ	0x11
+#define OZ_ELT_FAREWELL_REQ	0x12
+#define OZ_ELT_APP_DATA		0x31
+
+/* This is the Ozmo header which is the first Ozmo specific part
+ * of a frame and comes after the MAC header.
+ */
+struct oz_hdr {
+	u8	control;
+	u8	last_pkt_num;
+	u32	pkt_num;
+} PACKED;
+
+#define OZ_PROTOCOL_VERSION	0x1
+/* Bits in the control field. */
+#define OZ_VERSION_MASK		0xc
+#define OZ_VERSION_SHIFT	2
+#define OZ_F_ACK		0x10
+#define OZ_F_ISOC		0x20
+#define OZ_F_MORE_DATA		0x40
+#define OZ_F_ACK_REQUESTED	0x80
+
+#define oz_get_prot_ver(__x)	(((__x) & OZ_VERSION_MASK) >> OZ_VERSION_SHIFT)
+
+/* Used to select the bits of packet number to put in the last_pkt_num.
+ */
+#define OZ_LAST_PN_MASK		0x00ff
+
+#define OZ_LAST_PN_HALF_CYCLE	127
+
+/* Connect request data structure.
+ */
+struct oz_elt_connect_req {
+	u8	mode;
+	u8	resv1[16];
+	u8	pd_info;
+	u8	session_id;
+	u8	presleep;
+	u8	resv2;
+	u8	host_vendor;
+	u8	keep_alive;
+	u16	apps;
+	u8	max_len_div16;
+	u8	ms_per_isoc;
+	u8	resv3[2];
+} PACKED;
+
+/* mode field bits.
+ */
+#define OZ_MODE_POLLED		0x0
+#define OZ_MODE_TRIGGERED	0x1
+#define OZ_MODE_MASK		0xf
+#define OZ_F_ISOC_NO_ELTS	0x40
+#define OZ_F_ISOC_ANYTIME	0x80
+
+/* Keep alive field.
+ */
+#define OZ_KALIVE_TYPE_MASK	0xc0
+#define OZ_KALIVE_VALUE_MASK	0x3f
+#define OZ_KALIVE_SPECIAL	0x00
+#define OZ_KALIVE_SECS		0x40
+#define OZ_KALIVE_MINS		0x80
+#define OZ_KALIVE_HOURS		0xc0
+
+/* Connect response data structure.
+ */
+struct oz_elt_connect_rsp {
+	u8	mode;
+	u8	status;
+	u8	resv1[3];
+	u8	session_id;
+	u16	apps;
+	u32	resv2;
+} PACKED;
+
+struct oz_elt_farewell {
+	u8	ep_num;
+	u8	index;
+	u8	report[1];
+} PACKED;
+
+struct oz_elt_update_param {
+	u8	resv1[16];
+	u8	presleep;
+	u8	resv2;
+	u8	host_vendor;
+	u8	keepalive;
+} PACKED;
+
+/* Header common to all application elements.
+ */
+struct oz_app_hdr {
+	u8	app_id;
+	u8	elt_seq_num;
+} PACKED;
+
+/* Values for app_id.
+ */
+#define OZ_APPID_USB				0x1
+#define OZ_APPID_UNUSED1			0x2
+#define OZ_APPID_UNUSED2			0x3
+#define OZ_APPID_SERIAL				0x4
+#define OZ_APPID_MAX				OZ_APPID_SERIAL
+#define OZ_NB_APPS				(OZ_APPID_MAX+1)
+
+/* USB header common to all elements for the  USB application.
+ * This header extends the oz_app_hdr and comes directly after
+ * the element header in a USB application.
+ */
+struct oz_usb_hdr {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+} PACKED;
+
+
+
+/* USB requests element subtypes (type field of hs_usb_hdr).
+ */
+#define OZ_GET_DESC_REQ			1
+#define OZ_GET_DESC_RSP			2
+#define OZ_SET_CONFIG_REQ		3
+#define OZ_SET_CONFIG_RSP		4
+#define OZ_SET_INTERFACE_REQ		5
+#define OZ_SET_INTERFACE_RSP		6
+#define OZ_VENDOR_CLASS_REQ		7
+#define OZ_VENDOR_CLASS_RSP		8
+#define OZ_GET_STATUS_REQ		9
+#define OZ_GET_STATUS_RSP		10
+#define OZ_CLEAR_FEATURE_REQ		11
+#define OZ_CLEAR_FEATURE_RSP		12
+#define OZ_SET_FEATURE_REQ		13
+#define OZ_SET_FEATURE_RSP		14
+#define OZ_GET_CONFIGURATION_REQ	15
+#define OZ_GET_CONFIGURATION_RSP	16
+#define OZ_GET_INTERFACE_REQ		17
+#define OZ_GET_INTERFACE_RSP		18
+#define OZ_SYNCH_FRAME_REQ		19
+#define OZ_SYNCH_FRAME_RSP		20
+#define OZ_USB_ENDPOINT_DATA		23
+
+#define OZ_REQD_D2H			0x80
+
+struct oz_get_desc_req {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+	u8	req_id;
+	u16	offset;
+	u16	size;
+	u8	req_type;
+	u8	desc_type;
+	u16	w_index;
+	u8	index;
+} PACKED;
+
+/* Values for desc_type field.
+*/
+#define OZ_DESC_DEVICE			0x01
+#define OZ_DESC_CONFIG			0x02
+#define OZ_DESC_STRING			0x03
+
+/* Values for req_type field.
+ */
+#define OZ_RECP_MASK			0x1F
+#define OZ_RECP_DEVICE			0x00
+#define OZ_RECP_INTERFACE		0x01
+#define OZ_RECP_ENDPOINT		0x02
+
+#define OZ_REQT_MASK			0x60
+#define OZ_REQT_STD			0x00
+#define OZ_REQT_CLASS			0x20
+#define OZ_REQT_VENDOR			0x40
+
+struct oz_get_desc_rsp {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+	u8	req_id;
+	u16	offset;
+	u16	total_size;
+	u8	rcode;
+	u8	data[1];
+} PACKED;
+
+struct oz_feature_req {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+	u8	req_id;
+	u8	recipient;
+	u8	index;
+	u16	feature;
+} PACKED;
+
+struct oz_feature_rsp {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+	u8	req_id;
+	u8	rcode;
+} PACKED;
+
+struct oz_set_config_req {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+	u8	req_id;
+	u8	index;
+} PACKED;
+
+struct oz_set_config_rsp {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+	u8	req_id;
+	u8	rcode;
+} PACKED;
+
+struct oz_set_interface_req {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+	u8	req_id;
+	u8	index;
+	u8	alternative;
+} PACKED;
+
+struct oz_set_interface_rsp {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+	u8	req_id;
+	u8	rcode;
+} PACKED;
+
+struct oz_get_interface_req {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+	u8	req_id;
+	u8	index;
+} PACKED;
+
+struct oz_get_interface_rsp {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+	u8	req_id;
+	u8	rcode;
+	u8	alternative;
+} PACKED;
+
+struct oz_vendor_class_req {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+	u8	req_id;
+	u8	req_type;
+	u8	request;
+	u16	value;
+	u16	index;
+	u8	data[1];
+} PACKED;
+
+struct oz_vendor_class_rsp {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+	u8	req_id;
+	u8	rcode;
+	u8	data[1];
+} PACKED;
+
+struct oz_data {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+	u8	endpoint;
+	u8	format;
+} PACKED;
+
+struct oz_isoc_fixed {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+	u8	endpoint;
+	u8	format;
+	u8	unit_size;
+	u8	frame_number;
+	u8	data[1];
+} PACKED;
+
+struct oz_multiple_fixed {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+	u8	endpoint;
+	u8	format;
+	u8	unit_size;
+	u8	data[1];
+} PACKED;
+
+struct oz_fragmented {
+	u8	app_id;
+	u8	elt_seq_num;
+	u8	type;
+	u8	endpoint;
+	u8	format;
+	u16	total_size;
+	u16	offset;
+	u8	data[1];
+} PACKED;
+
+/* Note: the following does not get packaged in an element in the same way
+ * that other data formats are packaged. Instead the data is put in a frame
+ * directly after the oz_header and is the only permitted data in such a
+ * frame. The length of the data is directly determined from the frame size.
+ */
+struct oz_isoc_large {
+	u8	endpoint;
+	u8	format;
+	u8	ms_data;
+	u8	frame_number;
+} PACKED;
+
+#define OZ_DATA_F_TYPE_MASK		0xF
+#define OZ_DATA_F_MULTIPLE_FIXED	0x1
+#define OZ_DATA_F_MULTIPLE_VAR		0x2
+#define OZ_DATA_F_ISOC_FIXED		0x3
+#define OZ_DATA_F_ISOC_VAR		0x4
+#define OZ_DATA_F_FRAGMENTED		0x5
+#define OZ_DATA_F_ISOC_LARGE		0x7
+
+#endif /* _OZPROTOCOL_H */
diff --git a/drivers/staging/ozwpan/oztrace.c b/drivers/staging/ozwpan/oztrace.c
new file mode 100644
index 0000000..353ead2
--- /dev/null
+++ b/drivers/staging/ozwpan/oztrace.c
@@ -0,0 +1,36 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#include "ozconfig.h"
+#include "oztrace.h"
+
+#ifdef WANT_VERBOSE_TRACE
+unsigned long trace_flags =
+	0
+#ifdef WANT_TRACE_STREAM
+	| OZ_TRACE_STREAM
+#endif /* WANT_TRACE_STREAM */
+#ifdef WANT_TRACE_URB
+	| OZ_TRACE_URB
+#endif /* WANT_TRACE_URB */
+
+#ifdef WANT_TRACE_CTRL_DETAIL
+	| OZ_TRACE_CTRL_DETAIL
+#endif /* WANT_TRACE_CTRL_DETAIL */
+
+#ifdef WANT_TRACE_HUB
+	| OZ_TRACE_HUB
+#endif /* WANT_TRACE_HUB */
+
+#ifdef WANT_TRACE_RX_FRAMES
+	| OZ_TRACE_RX_FRAMES
+#endif /* WANT_TRACE_RX_FRAMES */
+
+#ifdef WANT_TRACE_TX_FRAMES
+	| OZ_TRACE_TX_FRAMES
+#endif /* WANT_TRACE_TX_FRAMES */
+	;
+#endif /* WANT_VERBOSE_TRACE */
+
diff --git a/drivers/staging/ozwpan/oztrace.h b/drivers/staging/ozwpan/oztrace.h
new file mode 100644
index 0000000..8293b24
--- /dev/null
+++ b/drivers/staging/ozwpan/oztrace.h
@@ -0,0 +1,35 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#ifndef _OZTRACE_H_
+#define _OZTRACE_H_
+#include "ozconfig.h"
+
+#define TRACE_PREFIX	KERN_ALERT "OZWPAN: "
+
+#ifdef WANT_TRACE
+#define oz_trace(...) printk(TRACE_PREFIX __VA_ARGS__)
+#ifdef WANT_VERBOSE_TRACE
+extern unsigned long trace_flags;
+#define oz_trace2(_flag, ...) \
+	do { if (trace_flags & _flag) printk(TRACE_PREFIX __VA_ARGS__); \
+	} while (0)
+#else
+#define oz_trace2(...)
+#endif /* #ifdef WANT_VERBOSE_TRACE */
+#else
+#define oz_trace(...)
+#define oz_trace2(...)
+#endif /* #ifdef WANT_TRACE */
+
+#define OZ_TRACE_STREAM		0x1
+#define OZ_TRACE_URB		0x2
+#define OZ_TRACE_CTRL_DETAIL	0x4
+#define OZ_TRACE_HUB		0x8
+#define OZ_TRACE_RX_FRAMES	0x10
+#define OZ_TRACE_TX_FRAMES	0x20
+
+#endif /* Sentry */
+
diff --git a/drivers/staging/ozwpan/ozurbparanoia.c b/drivers/staging/ozwpan/ozurbparanoia.c
new file mode 100644
index 0000000..55b9afb
--- /dev/null
+++ b/drivers/staging/ozwpan/ozurbparanoia.c
@@ -0,0 +1,53 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#include <linux/usb.h>
+#include "ozconfig.h"
+#ifdef WANT_URB_PARANOIA
+#include "ozurbparanoia.h"
+#include "oztrace.h"
+/*-----------------------------------------------------------------------------
+ */
+#define OZ_MAX_URBS	1000
+struct urb *g_urb_memory[OZ_MAX_URBS];
+int g_nb_urbs;
+DEFINE_SPINLOCK(g_urb_mem_lock);
+/*-----------------------------------------------------------------------------
+ */
+void oz_remember_urb(struct urb *urb)
+{
+	unsigned long irq_state;
+	spin_lock_irqsave(&g_urb_mem_lock, irq_state);
+	if (g_nb_urbs < OZ_MAX_URBS) {
+		g_urb_memory[g_nb_urbs++] = urb;
+		oz_trace("%lu: urb up = %d %p\n", jiffies, g_nb_urbs, urb);
+	} else {
+		oz_trace("ERROR urb buffer full\n");
+	}
+	spin_unlock_irqrestore(&g_urb_mem_lock, irq_state);
+}
+/*------------------------------------------------------------------------------
+ */
+int oz_forget_urb(struct urb *urb)
+{
+	unsigned long irq_state;
+	int i;
+	int rc = -1;
+	spin_lock_irqsave(&g_urb_mem_lock, irq_state);
+	for (i = 0; i < g_nb_urbs; i++) {
+		if (g_urb_memory[i] == urb) {
+			rc = 0;
+			if (--g_nb_urbs > i)
+				memcpy(&g_urb_memory[i], &g_urb_memory[i+1],
+					(g_nb_urbs - i) * sizeof(struct urb *));
+			oz_trace("%lu: urb down = %d %p\n",
+				jiffies, g_nb_urbs, urb);
+		}
+	}
+	spin_unlock_irqrestore(&g_urb_mem_lock, irq_state);
+	return rc;
+}
+#endif /* #ifdef WANT_URB_PARANOIA */
+
diff --git a/drivers/staging/ozwpan/ozurbparanoia.h b/drivers/staging/ozwpan/ozurbparanoia.h
new file mode 100644
index 0000000..00f5a3a
--- /dev/null
+++ b/drivers/staging/ozwpan/ozurbparanoia.h
@@ -0,0 +1,19 @@
+#ifndef _OZURBPARANOIA_H
+#define _OZURBPARANOIA_H
+/* -----------------------------------------------------------------------------
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * Copyright (c) 2011 Ozmo Inc
+ * -----------------------------------------------------------------------------
+ */
+
+#ifdef WANT_URB_PARANOIA
+void oz_remember_urb(struct urb *urb);
+int oz_forget_urb(struct urb *urb);
+#else
+#define oz_remember_urb(__x)
+#define oz_forget_urb(__x)	0
+#endif /* WANT_URB_PARANOIA */
+
+
+#endif /* _OZURBPARANOIA_H */
+
diff --git a/drivers/staging/ozwpan/ozusbif.h b/drivers/staging/ozwpan/ozusbif.h
new file mode 100644
index 0000000..3acf598
--- /dev/null
+++ b/drivers/staging/ozwpan/ozusbif.h
@@ -0,0 +1,43 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#ifndef _OZUSBIF_H
+#define _OZUSBIF_H
+
+#include <linux/usb.h>
+
+/* Reference counting functions.
+ */
+void oz_usb_get(void *hpd);
+void oz_usb_put(void *hpd);
+
+/* Stream functions.
+ */
+int oz_usb_stream_create(void *hpd, u8 ep_num);
+int oz_usb_stream_delete(void *hpd, u8 ep_num);
+
+/* Request functions.
+ */
+int oz_usb_control_req(void *hpd, u8 req_id, struct usb_ctrlrequest *setup,
+		u8 *data, int data_len);
+int oz_usb_get_desc_req(void *hpd, u8 req_id, u8 req_type, u8 desc_type,
+	u8 index, u16 windex, int offset, int len);
+int oz_usb_send_isoc(void *hpd, u8 ep_num, struct urb *urb);
+void oz_usb_request_heartbeat(void *hpd);
+
+/* Confirmation functions.
+ */
+void oz_hcd_get_desc_cnf(void *hport, u8 req_id, int status,
+	u8 *desc, int length, int offset, int total_size);
+void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode,
+	u8 *data, int data_len);
+
+/* Indication functions.
+ */
+void oz_hcd_data_ind(void *hport, u8 endpoint, u8 *data, int data_len);
+
+int oz_hcd_heartbeat(void *hport);
+
+#endif /* _OZUSBIF_H */
diff --git a/drivers/staging/ozwpan/ozusbsvc.c b/drivers/staging/ozwpan/ozusbsvc.c
new file mode 100644
index 0000000..9e74f96
--- /dev/null
+++ b/drivers/staging/ozwpan/ozusbsvc.c
@@ -0,0 +1,245 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ *
+ * This file provides protocol independent part of the implementation of the USB
+ * service for a PD.
+ * The implementation of this service is split into two parts the first of which
+ * is protocol independent and the second contains protocol specific details.
+ * This split is to allow alternative protocols to be defined.
+ * The implemenation of this service uses ozhcd.c to implement a USB HCD.
+ * -----------------------------------------------------------------------------
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <asm/unaligned.h>
+#include "ozconfig.h"
+#include "ozprotocol.h"
+#include "ozeltbuf.h"
+#include "ozpd.h"
+#include "ozproto.h"
+#include "ozusbif.h"
+#include "ozhcd.h"
+#include "oztrace.h"
+#include "ozusbsvc.h"
+#include "ozevent.h"
+/*------------------------------------------------------------------------------
+ * This is called once when the driver is loaded to initialise the USB service.
+ * Context: process
+ */
+int oz_usb_init(void)
+{
+	oz_event_log(OZ_EVT_SERVICE, 1, OZ_APPID_USB, 0, 0);
+	return oz_hcd_init();
+}
+/*------------------------------------------------------------------------------
+ * This is called once when the driver is unloaded to terminate the USB service.
+ * Context: process
+ */
+void oz_usb_term(void)
+{
+	oz_event_log(OZ_EVT_SERVICE, 2, OZ_APPID_USB, 0, 0);
+	oz_hcd_term();
+}
+/*------------------------------------------------------------------------------
+ * This is called when the USB service is started or resumed for a PD.
+ * Context: softirq
+ */
+int oz_usb_start(struct oz_pd *pd, int resume)
+{
+	int rc = 0;
+	struct oz_usb_ctx *usb_ctx;
+	struct oz_usb_ctx *old_ctx = 0;
+	oz_event_log(OZ_EVT_SERVICE, 3, OZ_APPID_USB, 0, resume);
+	if (resume) {
+		oz_trace("USB service resumed.\n");
+		return 0;
+	}
+	oz_trace("USB service started.\n");
+	/* Create a USB context in case we need one. If we find the PD already
+	 * has a USB context then we will destroy it.
+	 */
+	usb_ctx = kzalloc(sizeof(struct oz_usb_ctx), GFP_ATOMIC);
+	if (usb_ctx == 0)
+		return -ENOMEM;
+	atomic_set(&usb_ctx->ref_count, 1);
+	usb_ctx->pd = pd;
+	usb_ctx->stopped = 0;
+	/* Install the USB context if the PD doesn't already have one.
+	 * If it does already have one then destroy the one we have just
+	 * created.
+	 */
+	spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
+	old_ctx = pd->app_ctx[OZ_APPID_USB-1];
+	if (old_ctx == 0)
+		pd->app_ctx[OZ_APPID_USB-1] = usb_ctx;
+	oz_usb_get(pd->app_ctx[OZ_APPID_USB-1]);
+	spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
+	if (old_ctx) {
+		oz_trace("Already have USB context.\n");
+		kfree(usb_ctx);
+		usb_ctx = old_ctx;
+	} else if (usb_ctx) {
+		/* Take a reference to the PD. This will be released when
+		 * the USB context is destroyed.
+		 */
+		oz_pd_get(pd);
+	}
+	/* If we already had a USB context and had obtained a port from
+	 * the USB HCD then just reset the port. If we didn't have a port
+	 * then report the arrival to the USB HCD so we get one.
+	 */
+	if (usb_ctx->hport) {
+		oz_hcd_pd_reset(usb_ctx, usb_ctx->hport);
+	} else {
+		usb_ctx->hport = oz_hcd_pd_arrived(usb_ctx);
+		if (usb_ctx->hport == 0) {
+			oz_trace("USB hub returned null port.\n");
+			spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
+			pd->app_ctx[OZ_APPID_USB-1] = 0;
+			spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
+			oz_usb_put(usb_ctx);
+			rc = -1;
+		}
+	}
+	oz_usb_put(usb_ctx);
+	return rc;
+}
+/*------------------------------------------------------------------------------
+ * This is called when the USB service is stopped or paused for a PD.
+ * Context: softirq or process
+ */
+void oz_usb_stop(struct oz_pd *pd, int pause)
+{
+	struct oz_usb_ctx *usb_ctx;
+	oz_event_log(OZ_EVT_SERVICE, 4, OZ_APPID_USB, 0, pause);
+	if (pause) {
+		oz_trace("USB service paused.\n");
+		return;
+	}
+	spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
+	usb_ctx = (struct oz_usb_ctx *)pd->app_ctx[OZ_APPID_USB-1];
+	pd->app_ctx[OZ_APPID_USB-1] = 0;
+	spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
+	if (usb_ctx) {
+		unsigned long tout = jiffies + HZ;
+		oz_trace("USB service stopping...\n");
+		usb_ctx->stopped = 1;
+		/* At this point the reference count on the usb context should
+		 * be 2 - one from when we created it and one from the hcd
+		 * which claims a reference. Since stopped = 1 no one else
+		 * should get in but someone may already be in. So wait
+		 * until they leave but timeout after 1 second.
+		 */
+		while ((atomic_read(&usb_ctx->ref_count) > 2) &&
+			time_before(jiffies, tout))
+			;
+		oz_trace("USB service stopped.\n");
+		oz_hcd_pd_departed(usb_ctx->hport);
+		/* Release the reference taken in oz_usb_start.
+		 */
+		oz_usb_put(usb_ctx);
+	}
+}
+/*------------------------------------------------------------------------------
+ * This increments the reference count of the context area for a specific PD.
+ * This ensures this context area does not disappear while still in use.
+ * Context: softirq
+ */
+void oz_usb_get(void *hpd)
+{
+	struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
+	atomic_inc(&usb_ctx->ref_count);
+}
+/*------------------------------------------------------------------------------
+ * This decrements the reference count of the context area for a specific PD
+ * and destroys the context area if the reference count becomes zero.
+ * Context: softirq or process
+ */
+void oz_usb_put(void *hpd)
+{
+	struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
+	if (atomic_dec_and_test(&usb_ctx->ref_count)) {
+		oz_trace("Dealloc USB context.\n");
+		oz_pd_put(usb_ctx->pd);
+		kfree(usb_ctx);
+	}
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+int oz_usb_heartbeat(struct oz_pd *pd)
+{
+	struct oz_usb_ctx *usb_ctx;
+	int rc = 0;
+	spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
+	usb_ctx = (struct oz_usb_ctx *)pd->app_ctx[OZ_APPID_USB-1];
+	if (usb_ctx)
+		oz_usb_get(usb_ctx);
+	spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
+	if (usb_ctx == 0)
+		return rc;
+	if (usb_ctx->stopped)
+		goto done;
+	if (usb_ctx->hport)
+		if (oz_hcd_heartbeat(usb_ctx->hport))
+			rc = 1;
+done:
+	oz_usb_put(usb_ctx);
+	return rc;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+int oz_usb_stream_create(void *hpd, u8 ep_num)
+{
+	struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
+	struct oz_pd *pd = usb_ctx->pd;
+	oz_trace("oz_usb_stream_create(0x%x)\n", ep_num);
+	if (pd->mode & OZ_F_ISOC_NO_ELTS) {
+		oz_isoc_stream_create(pd, ep_num);
+	} else {
+		oz_pd_get(pd);
+		if (oz_elt_stream_create(&pd->elt_buff, ep_num,
+			4*pd->max_tx_size)) {
+			oz_pd_put(pd);
+			return -1;
+		}
+	}
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+int oz_usb_stream_delete(void *hpd, u8 ep_num)
+{
+	struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
+	if (usb_ctx) {
+		struct oz_pd *pd = usb_ctx->pd;
+		if (pd) {
+			oz_trace("oz_usb_stream_delete(0x%x)\n", ep_num);
+			if (pd->mode & OZ_F_ISOC_NO_ELTS) {
+				oz_isoc_stream_delete(pd, ep_num);
+			} else {
+				if (oz_elt_stream_delete(&pd->elt_buff, ep_num))
+					return -1;
+				oz_pd_put(pd);
+			}
+		}
+	}
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
+void oz_usb_request_heartbeat(void *hpd)
+{
+	struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
+	if (usb_ctx && usb_ctx->pd)
+		oz_pd_request_heartbeat(usb_ctx->pd);
+}
diff --git a/drivers/staging/ozwpan/ozusbsvc.h b/drivers/staging/ozwpan/ozusbsvc.h
new file mode 100644
index 0000000..58e05a5
--- /dev/null
+++ b/drivers/staging/ozwpan/ozusbsvc.h
@@ -0,0 +1,32 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * -----------------------------------------------------------------------------
+ */
+#ifndef _OZUSBSVC_H
+#define _OZUSBSVC_H
+
+/*------------------------------------------------------------------------------
+ * Per PD context info stored in application context area of PD.
+ * This object is reference counted to ensure it doesn't disappear while
+ * still in use.
+ */
+struct oz_usb_ctx {
+	atomic_t ref_count;
+	u8 tx_seq_num;
+	u8 rx_seq_num;
+	struct oz_pd *pd;
+	void *hport;
+	int stopped;
+};
+
+int oz_usb_init(void);
+void oz_usb_term(void);
+int oz_usb_start(struct oz_pd *pd, int resume);
+void oz_usb_stop(struct oz_pd *pd, int pause);
+void oz_usb_rx(struct oz_pd *pd, struct oz_elt *elt);
+int oz_usb_heartbeat(struct oz_pd *pd);
+void oz_usb_farewell(struct oz_pd *pd, u8 ep_num, u8 *data, u8 len);
+
+#endif /* _OZUSBSVC_H */
+
diff --git a/drivers/staging/ozwpan/ozusbsvc1.c b/drivers/staging/ozwpan/ozusbsvc1.c
new file mode 100644
index 0000000..66bd576
--- /dev/null
+++ b/drivers/staging/ozwpan/ozusbsvc1.c
@@ -0,0 +1,437 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ *
+ * This file implements the protocol specific parts of the USB service for a PD.
+ * -----------------------------------------------------------------------------
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <asm/unaligned.h>
+#include "ozconfig.h"
+#include "ozprotocol.h"
+#include "ozeltbuf.h"
+#include "ozpd.h"
+#include "ozproto.h"
+#include "ozusbif.h"
+#include "ozhcd.h"
+#include "oztrace.h"
+#include "ozusbsvc.h"
+#include "ozevent.h"
+/*------------------------------------------------------------------------------
+ */
+#define MAX_ISOC_FIXED_DATA	(253-sizeof(struct oz_isoc_fixed))
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+static int oz_usb_submit_elt(struct oz_elt_buf *eb, struct oz_elt_info *ei,
+	struct oz_usb_ctx *usb_ctx, u8 strid, u8 isoc)
+{
+	int ret;
+	struct oz_elt *elt = (struct oz_elt *)ei->data;
+	struct oz_app_hdr *app_hdr = (struct oz_app_hdr *)(elt+1);
+	elt->type = OZ_ELT_APP_DATA;
+	ei->app_id = OZ_APPID_USB;
+	ei->length = elt->length + sizeof(struct oz_elt);
+	app_hdr->app_id = OZ_APPID_USB;
+	spin_lock_bh(&eb->lock);
+	if (isoc == 0) {
+		app_hdr->elt_seq_num = usb_ctx->tx_seq_num++;
+		if (usb_ctx->tx_seq_num == 0)
+			usb_ctx->tx_seq_num = 1;
+	}
+	ret = oz_queue_elt_info(eb, isoc, strid, ei);
+	if (ret)
+		oz_elt_info_free(eb, ei);
+	spin_unlock_bh(&eb->lock);
+	return ret;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+int oz_usb_get_desc_req(void *hpd, u8 req_id, u8 req_type, u8 desc_type,
+	u8 index, u16 windex, int offset, int len)
+{
+	struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
+	struct oz_pd *pd = usb_ctx->pd;
+	struct oz_elt *elt;
+	struct oz_get_desc_req *body;
+	struct oz_elt_buf *eb = &pd->elt_buff;
+	struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
+	oz_trace("    req_type = 0x%x\n", req_type);
+	oz_trace("    desc_type = 0x%x\n", desc_type);
+	oz_trace("    index = 0x%x\n", index);
+	oz_trace("    windex = 0x%x\n", windex);
+	oz_trace("    offset = 0x%x\n", offset);
+	oz_trace("    len = 0x%x\n", len);
+	if (len > 200)
+		len = 200;
+	if (ei == 0)
+		return -1;
+	elt = (struct oz_elt *)ei->data;
+	elt->length = sizeof(struct oz_get_desc_req);
+	body = (struct oz_get_desc_req *)(elt+1);
+	body->type = OZ_GET_DESC_REQ;
+	body->req_id = req_id;
+	put_unaligned(cpu_to_le16(offset), &body->offset);
+	put_unaligned(cpu_to_le16(len), &body->size);
+	body->req_type = req_type;
+	body->desc_type = desc_type;
+	body->w_index = windex;
+	body->index = index;
+	return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0);
+}
+/*------------------------------------------------------------------------------
+ * Context: tasklet
+ */
+static int oz_usb_set_config_req(void *hpd, u8 req_id, u8 index)
+{
+	struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
+	struct oz_pd *pd = usb_ctx->pd;
+	struct oz_elt *elt;
+	struct oz_elt_buf *eb = &pd->elt_buff;
+	struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
+	struct oz_set_config_req *body;
+	if (ei == 0)
+		return -1;
+	elt = (struct oz_elt *)ei->data;
+	elt->length = sizeof(struct oz_set_config_req);
+	body = (struct oz_set_config_req *)(elt+1);
+	body->type = OZ_SET_CONFIG_REQ;
+	body->req_id = req_id;
+	body->index = index;
+	return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0);
+}
+/*------------------------------------------------------------------------------
+ * Context: tasklet
+ */
+static int oz_usb_set_interface_req(void *hpd, u8 req_id, u8 index, u8 alt)
+{
+	struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
+	struct oz_pd *pd = usb_ctx->pd;
+	struct oz_elt *elt;
+	struct oz_elt_buf *eb = &pd->elt_buff;
+	struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
+	struct oz_set_interface_req *body;
+	if (ei == 0)
+		return -1;
+	elt = (struct oz_elt *)ei->data;
+	elt->length = sizeof(struct oz_set_interface_req);
+	body = (struct oz_set_interface_req *)(elt+1);
+	body->type = OZ_SET_INTERFACE_REQ;
+	body->req_id = req_id;
+	body->index = index;
+	body->alternative = alt;
+	return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0);
+}
+/*------------------------------------------------------------------------------
+ * Context: tasklet
+ */
+static int oz_usb_set_clear_feature_req(void *hpd, u8 req_id, u8 type,
+			u8 recipient, u8 index, __le16 feature)
+{
+	struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
+	struct oz_pd *pd = usb_ctx->pd;
+	struct oz_elt *elt;
+	struct oz_elt_buf *eb = &pd->elt_buff;
+	struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
+	struct oz_feature_req *body;
+	if (ei == 0)
+		return -1;
+	elt = (struct oz_elt *)ei->data;
+	elt->length = sizeof(struct oz_feature_req);
+	body = (struct oz_feature_req *)(elt+1);
+	body->type = type;
+	body->req_id = req_id;
+	body->recipient = recipient;
+	body->index = index;
+	put_unaligned(feature, &body->feature);
+	return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0);
+}
+/*------------------------------------------------------------------------------
+ * Context: tasklet
+ */
+static int oz_usb_vendor_class_req(void *hpd, u8 req_id, u8 req_type,
+	u8 request, __le16 value, __le16 index, u8 *data, int data_len)
+{
+	struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
+	struct oz_pd *pd = usb_ctx->pd;
+	struct oz_elt *elt;
+	struct oz_elt_buf *eb = &pd->elt_buff;
+	struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
+	struct oz_vendor_class_req *body;
+	if (ei == 0)
+		return -1;
+	elt = (struct oz_elt *)ei->data;
+	elt->length = sizeof(struct oz_vendor_class_req) - 1 + data_len;
+	body = (struct oz_vendor_class_req *)(elt+1);
+	body->type = OZ_VENDOR_CLASS_REQ;
+	body->req_id = req_id;
+	body->req_type = req_type;
+	body->request = request;
+	put_unaligned(value, &body->value);
+	put_unaligned(index, &body->index);
+	if (data_len)
+		memcpy(body->data, data, data_len);
+	return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0);
+}
+/*------------------------------------------------------------------------------
+ * Context: tasklet
+ */
+int oz_usb_control_req(void *hpd, u8 req_id, struct usb_ctrlrequest *setup,
+			u8 *data, int data_len)
+{
+	unsigned wvalue = le16_to_cpu(setup->wValue);
+	unsigned windex = le16_to_cpu(setup->wIndex);
+	unsigned wlength = le16_to_cpu(setup->wLength);
+	int rc = 0;
+	oz_event_log(OZ_EVT_CTRL_REQ, setup->bRequest, req_id,
+		(void *)(((unsigned long)(setup->wValue))<<16 |
+			((unsigned long)setup->wIndex)),
+		setup->bRequestType);
+	if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		switch (setup->bRequest) {
+		case USB_REQ_GET_DESCRIPTOR:
+			rc = oz_usb_get_desc_req(hpd, req_id,
+				setup->bRequestType, (u8)(wvalue>>8),
+				(u8)wvalue, setup->wIndex, 0, wlength);
+			break;
+		case USB_REQ_SET_CONFIGURATION:
+			rc = oz_usb_set_config_req(hpd, req_id, (u8)wvalue);
+			break;
+		case USB_REQ_SET_INTERFACE: {
+				u8 if_num = (u8)windex;
+				u8 alt = (u8)wvalue;
+				rc = oz_usb_set_interface_req(hpd, req_id,
+					if_num, alt);
+			}
+			break;
+		case USB_REQ_SET_FEATURE:
+			rc = oz_usb_set_clear_feature_req(hpd, req_id,
+				OZ_SET_FEATURE_REQ,
+				setup->bRequestType & 0xf, (u8)windex,
+				setup->wValue);
+			break;
+		case USB_REQ_CLEAR_FEATURE:
+			rc = oz_usb_set_clear_feature_req(hpd, req_id,
+				OZ_CLEAR_FEATURE_REQ,
+				setup->bRequestType & 0xf,
+				(u8)windex, setup->wValue);
+			break;
+		}
+	} else {
+		rc = oz_usb_vendor_class_req(hpd, req_id, setup->bRequestType,
+			setup->bRequest, setup->wValue, setup->wIndex,
+			data, data_len);
+	}
+	return rc;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+int oz_usb_send_isoc(void *hpd, u8 ep_num, struct urb *urb)
+{
+	struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
+	struct oz_pd *pd = usb_ctx->pd;
+	struct oz_elt_buf *eb;
+	int i;
+	int hdr_size;
+	u8 *data;
+	struct usb_iso_packet_descriptor *desc;
+
+	if (pd->mode & OZ_F_ISOC_NO_ELTS) {
+		for (i = 0; i < urb->number_of_packets; i++) {
+			u8 *data;
+			desc = &urb->iso_frame_desc[i];
+			data = ((u8 *)urb->transfer_buffer)+desc->offset;
+			oz_send_isoc_unit(pd, ep_num, data, desc->length);
+		}
+		return 0;
+	}
+
+	hdr_size = sizeof(struct oz_isoc_fixed) - 1;
+	eb = &pd->elt_buff;
+	i = 0;
+	while (i < urb->number_of_packets) {
+		struct oz_elt_info *ei = oz_elt_info_alloc(eb);
+		struct oz_elt *elt;
+		struct oz_isoc_fixed *body;
+		int unit_count;
+		int unit_size;
+		int rem;
+		if (ei == 0)
+			return -1;
+		rem = MAX_ISOC_FIXED_DATA;
+		elt = (struct oz_elt *)ei->data;
+		body = (struct oz_isoc_fixed *)(elt + 1);
+		body->type = OZ_USB_ENDPOINT_DATA;
+		body->endpoint = ep_num;
+		body->format = OZ_DATA_F_ISOC_FIXED;
+		unit_size = urb->iso_frame_desc[i].length;
+		body->unit_size = (u8)unit_size;
+		data = ((u8 *)(elt+1)) + hdr_size;
+		unit_count = 0;
+		while (i < urb->number_of_packets) {
+			desc = &urb->iso_frame_desc[i];
+			if ((unit_size == desc->length) &&
+				(desc->length <= rem)) {
+				memcpy(data, ((u8 *)urb->transfer_buffer) +
+					desc->offset, unit_size);
+				data += unit_size;
+				rem -= unit_size;
+				unit_count++;
+				desc->status = 0;
+				desc->actual_length = desc->length;
+				i++;
+			} else {
+				break;
+			}
+		}
+		elt->length = hdr_size + MAX_ISOC_FIXED_DATA - rem;
+		/* Store the number of units in body->frame_number for the
+		 * moment. This field will be correctly determined before
+		 * the element is sent. */
+		body->frame_number = (u8)unit_count;
+		oz_usb_submit_elt(eb, ei, usb_ctx, ep_num,
+			pd->mode & OZ_F_ISOC_ANYTIME);
+	}
+	return 0;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+void oz_usb_handle_ep_data(struct oz_usb_ctx *usb_ctx,
+	struct oz_usb_hdr *usb_hdr, int len)
+{
+	struct oz_data *data_hdr = (struct oz_data *)usb_hdr;
+	switch (data_hdr->format) {
+	case OZ_DATA_F_MULTIPLE_FIXED: {
+			struct oz_multiple_fixed *body =
+				(struct oz_multiple_fixed *)data_hdr;
+			u8 *data = body->data;
+			int n = (len - sizeof(struct oz_multiple_fixed)+1)
+				/ body->unit_size;
+			while (n--) {
+				oz_hcd_data_ind(usb_ctx->hport, body->endpoint,
+					data, body->unit_size);
+				data += body->unit_size;
+			}
+		}
+		break;
+	case OZ_DATA_F_ISOC_FIXED: {
+			struct oz_isoc_fixed *body =
+				(struct oz_isoc_fixed *)data_hdr;
+			int data_len = len-sizeof(struct oz_isoc_fixed)+1;
+			int unit_size = body->unit_size;
+			u8 *data = body->data;
+			int count;
+			int i;
+			if (!unit_size)
+				break;
+			count = data_len/unit_size;
+			for (i = 0; i < count; i++) {
+				oz_hcd_data_ind(usb_ctx->hport,
+					body->endpoint, data, unit_size);
+				data += unit_size;
+			}
+		}
+		break;
+	}
+
+}
+/*------------------------------------------------------------------------------
+ * This is called when the PD has received a USB element. The type of element
+ * is determined and is then passed to an appropriate handler function.
+ * Context: softirq-serialized
+ */
+void oz_usb_rx(struct oz_pd *pd, struct oz_elt *elt)
+{
+	struct oz_usb_hdr *usb_hdr = (struct oz_usb_hdr *)(elt + 1);
+	struct oz_usb_ctx *usb_ctx;
+
+	spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
+	usb_ctx = (struct oz_usb_ctx *)pd->app_ctx[OZ_APPID_USB-1];
+	if (usb_ctx)
+		oz_usb_get(usb_ctx);
+	spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
+	if (usb_ctx == 0)
+		return; /* Context has gone so nothing to do. */
+	if (usb_ctx->stopped)
+		goto done;
+	/* If sequence number is non-zero then check it is not a duplicate.
+	 * Zero sequence numbers are always accepted.
+	 */
+	if (usb_hdr->elt_seq_num != 0) {
+		if (((usb_ctx->rx_seq_num - usb_hdr->elt_seq_num) & 0x80) == 0)
+			/* Reject duplicate element. */
+			goto done;
+	}
+	usb_ctx->rx_seq_num = usb_hdr->elt_seq_num;
+	switch (usb_hdr->type) {
+	case OZ_GET_DESC_RSP: {
+			struct oz_get_desc_rsp *body =
+				(struct oz_get_desc_rsp *)usb_hdr;
+			int data_len = elt->length -
+					sizeof(struct oz_get_desc_rsp) + 1;
+			u16 offs = le16_to_cpu(get_unaligned(&body->offset));
+			u16 total_size =
+				le16_to_cpu(get_unaligned(&body->total_size));
+			oz_trace("USB_REQ_GET_DESCRIPTOR - cnf\n");
+			oz_hcd_get_desc_cnf(usb_ctx->hport, body->req_id,
+					body->rcode, body->data,
+					data_len, offs, total_size);
+		}
+		break;
+	case OZ_SET_CONFIG_RSP: {
+			struct oz_set_config_rsp *body =
+				(struct oz_set_config_rsp *)usb_hdr;
+			oz_hcd_control_cnf(usb_ctx->hport, body->req_id,
+				body->rcode, 0, 0);
+		}
+		break;
+	case OZ_SET_INTERFACE_RSP: {
+			struct oz_set_interface_rsp *body =
+				(struct oz_set_interface_rsp *)usb_hdr;
+			oz_hcd_control_cnf(usb_ctx->hport,
+				body->req_id, body->rcode, 0, 0);
+		}
+		break;
+	case OZ_VENDOR_CLASS_RSP: {
+			struct oz_vendor_class_rsp *body =
+				(struct oz_vendor_class_rsp *)usb_hdr;
+			oz_hcd_control_cnf(usb_ctx->hport, body->req_id,
+				body->rcode, body->data, elt->length-
+				sizeof(struct oz_vendor_class_rsp)+1);
+		}
+		break;
+	case OZ_USB_ENDPOINT_DATA:
+		oz_usb_handle_ep_data(usb_ctx, usb_hdr, elt->length);
+		break;
+	}
+done:
+	oz_usb_put(usb_ctx);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq, process
+ */
+void oz_usb_farewell(struct oz_pd *pd, u8 ep_num, u8 *data, u8 len)
+{
+	struct oz_usb_ctx *usb_ctx;
+	spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
+	usb_ctx = (struct oz_usb_ctx *)pd->app_ctx[OZ_APPID_USB-1];
+	if (usb_ctx)
+		oz_usb_get(usb_ctx);
+	spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
+	if (usb_ctx == 0)
+		return; /* Context has gone so nothing to do. */
+	if (!usb_ctx->stopped) {
+		oz_trace("Farewell indicated ep = 0x%x\n", ep_num);
+		oz_hcd_data_ind(usb_ctx->hport, ep_num, data, len);
+	}
+	oz_usb_put(usb_ctx);
+}
diff --git a/drivers/staging/quatech_usb2/quatech_usb2.c b/drivers/staging/quatech_usb2/quatech_usb2.c
index 897a3a9..bb977e0 100644
--- a/drivers/staging/quatech_usb2/quatech_usb2.c
+++ b/drivers/staging/quatech_usb2/quatech_usb2.c
@@ -135,7 +135,6 @@
 	.probe = usb_serial_probe,
 	.disconnect = usb_serial_disconnect,
 	.id_table = quausb2_id_table,
-	.no_dynamic_id = 1,
 };
 
 /**
@@ -1942,7 +1941,6 @@
 		.name = "quatech_usb2",
 	},
 	.description = DRIVER_DESC,
-	.usb_driver = &quausb2_usb_driver,
 	.id_table = quausb2_id_table,
 	.num_ports = 8,
 	.open = qt2_open,
@@ -1964,41 +1962,11 @@
 	.write_bulk_callback = qt2_write_bulk_callback,
 };
 
-static int __init quausb2_usb_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&quatech2_device, NULL
+};
 
-	dbg("%s\n", __func__);
-
-	/* register with usb-serial */
-	retval = usb_serial_register(&quatech2_device);
-
-	if (retval)
-		goto failed_usb_serial_register;
-
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-			DRIVER_DESC "\n");
-
-	/* register with usb */
-
-	retval = usb_register(&quausb2_usb_driver);
-	if (retval == 0)
-		return 0;
-
-	/* if we're here, usb_register() failed */
-	usb_serial_deregister(&quatech2_device);
-failed_usb_serial_register:
-		return retval;
-}
-
-static void __exit quausb2_usb_exit(void)
-{
-	usb_deregister(&quausb2_usb_driver);
-	usb_serial_deregister(&quatech2_device);
-}
-
-module_init(quausb2_usb_init);
-module_exit(quausb2_usb_exit);
+module_usb_serial_driver(quausb2_usb_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/staging/quickstart/quickstart.c b/drivers/staging/quickstart/quickstart.c
index c60911c..cac3207 100644
--- a/drivers/staging/quickstart/quickstart.c
+++ b/drivers/staging/quickstart/quickstart.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2007-2010 Angelo Arrifano <miknix@gmail.com>
  *
- *  Information gathered from disassebled dsdt and from here:
+ *  Information gathered from disassembled dsdt and from here:
  *  <http://www.microsoft.com/whdc/system/platform/firmware/DirAppLaunch.mspx>
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -23,7 +23,9 @@
  *
  */
 
-#define QUICKSTART_VERSION "1.03"
+#define QUICKSTART_VERSION "1.04"
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -37,41 +39,298 @@
 MODULE_DESCRIPTION("ACPI Direct App Launch driver");
 MODULE_LICENSE("GPL");
 
-#define QUICKSTART_ACPI_DEVICE_NAME   "quickstart"
-#define QUICKSTART_ACPI_CLASS         "quickstart"
-#define QUICKSTART_ACPI_HID           "PNP0C32"
+#define QUICKSTART_ACPI_DEVICE_NAME	"quickstart"
+#define QUICKSTART_ACPI_CLASS		"quickstart"
+#define QUICKSTART_ACPI_HID		"PNP0C32"
 
-#define QUICKSTART_PF_DRIVER_NAME     "quickstart"
-#define QUICKSTART_PF_DEVICE_NAME     "quickstart"
-#define QUICKSTART_PF_DEVATTR_NAME    "pressed_button"
+#define QUICKSTART_PF_DRIVER_NAME	"quickstart"
+#define QUICKSTART_PF_DEVICE_NAME	"quickstart"
 
-#define QUICKSTART_MAX_BTN_NAME_LEN   16
+/*
+ * There will be two events:
+ * 0x02 - A hot button was pressed while device was off/sleeping.
+ * 0x80 - A hot button was pressed while device was up.
+ */
+#define QUICKSTART_EVENT_WAKE		0x02
+#define QUICKSTART_EVENT_RUNTIME	0x80
 
-/* There will be two events:
-	 * 0x02 - A hot button was pressed while device was off/sleeping.
-	 * 0x80 - A hot button was pressed while device was up. */
-#define QUICKSTART_EVENT_WAKE         0x02
-#define QUICKSTART_EVENT_RUNTIME      0x80
-
-struct quickstart_btn {
+struct quickstart_button {
 	char *name;
 	unsigned int id;
-	struct quickstart_btn *next;
+	struct list_head list;
 };
 
-static struct quickstart_driver_data {
-	struct quickstart_btn *btn_lst;
-	struct quickstart_btn *pressed;
-} quickstart_data;
-
-/* ACPI driver Structs */
 struct quickstart_acpi {
 	struct acpi_device *device;
-	struct quickstart_btn *btn;
+	struct quickstart_button *button;
 };
-static int quickstart_acpi_add(struct acpi_device *device);
-static int quickstart_acpi_remove(struct acpi_device *device, int type);
-static const struct acpi_device_id  quickstart_device_ids[] = {
+
+static LIST_HEAD(buttons);
+static struct quickstart_button *pressed;
+
+static struct input_dev *quickstart_input;
+
+/* Platform driver functions */
+static ssize_t quickstart_buttons_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	int count = 0;
+	struct quickstart_button *b;
+
+	if (list_empty(&buttons))
+		return snprintf(buf, PAGE_SIZE, "none");
+
+	list_for_each_entry(b, &buttons, list) {
+		count += snprintf(buf + count, PAGE_SIZE - count, "%u\t%s\n",
+							b->id, b->name);
+
+		if (count >= PAGE_SIZE) {
+			count = PAGE_SIZE;
+			break;
+		}
+	}
+
+	return count;
+}
+
+static ssize_t quickstart_pressed_button_show(struct device *dev,
+						struct device_attribute *attr,
+						char *buf)
+{
+	return scnprintf(buf, PAGE_SIZE, "%s\n",
+					(pressed ? pressed->name : "none"));
+}
+
+
+static ssize_t quickstart_pressed_button_store(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	if (count < 2)
+		return -EINVAL;
+
+	if (strncasecmp(buf, "none", 4) != 0)
+		return -EINVAL;
+
+	pressed = NULL;
+	return count;
+}
+
+/* Helper functions */
+static struct quickstart_button *quickstart_buttons_add(void)
+{
+	struct quickstart_button *b;
+
+	b = kzalloc(sizeof(*b), GFP_KERNEL);
+	if (!b)
+		return NULL;
+
+	list_add_tail(&b->list, &buttons);
+
+	return b;
+}
+
+static void quickstart_button_del(struct quickstart_button *data)
+{
+	if (!data)
+		return;
+
+	list_del(&data->list);
+	kfree(data->name);
+	kfree(data);
+}
+
+static void quickstart_buttons_free(void)
+{
+	struct quickstart_button *b, *n;
+
+	list_for_each_entry_safe(b, n, &buttons, list)
+		quickstart_button_del(b);
+}
+
+/* ACPI Driver functions */
+static void quickstart_acpi_notify(acpi_handle handle, u32 event, void *data)
+{
+	struct quickstart_acpi *quickstart = data;
+
+	if (!quickstart)
+		return;
+
+	switch (event) {
+	case QUICKSTART_EVENT_WAKE:
+		pressed = quickstart->button;
+		break;
+	case QUICKSTART_EVENT_RUNTIME:
+		input_report_key(quickstart_input, quickstart->button->id, 1);
+		input_sync(quickstart_input);
+		input_report_key(quickstart_input, quickstart->button->id, 0);
+		input_sync(quickstart_input);
+		break;
+	default:
+		pr_err("Unexpected ACPI event notify (%u)\n", event);
+		break;
+	}
+}
+
+static int quickstart_acpi_ghid(struct quickstart_acpi *quickstart)
+{
+	acpi_status status;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	int ret = 0;
+
+	/*
+	 * This returns a buffer telling the button usage ID,
+	 * and triggers pending notify events (The ones before booting).
+	 */
+	status = acpi_evaluate_object(quickstart->device->handle, "GHID", NULL,
+								&buffer);
+	if (ACPI_FAILURE(status)) {
+		pr_err("%s GHID method failed\n", quickstart->button->name);
+		return -EINVAL;
+	}
+
+	/*
+	 * <<The GHID method can return a BYTE, WORD, or DWORD.
+	 * The value must be encoded in little-endian byte
+	 * order (least significant byte first).>>
+	 */
+	switch (buffer.length) {
+	case 1:
+		quickstart->button->id = *(uint8_t *)buffer.pointer;
+		break;
+	case 2:
+		quickstart->button->id = *(uint16_t *)buffer.pointer;
+		break;
+	case 4:
+		quickstart->button->id = *(uint32_t *)buffer.pointer;
+		break;
+	case 8:
+		quickstart->button->id = *(uint64_t *)buffer.pointer;
+		break;
+	default:
+		pr_err("%s GHID method returned buffer of unexpected length %lu\n",
+				quickstart->button->name,
+				(unsigned long)buffer.length);
+		ret = -EINVAL;
+		break;
+	}
+
+	kfree(buffer.pointer);
+
+	return ret;
+}
+
+static int quickstart_acpi_config(struct quickstart_acpi *quickstart)
+{
+	char *bid = acpi_device_bid(quickstart->device);
+	char *name;
+
+	name = kmalloc(strlen(bid) + 1, GFP_KERNEL);
+	if (!name)
+		return -ENOMEM;
+
+	/* Add new button to list */
+	quickstart->button = quickstart_buttons_add();
+	if (!quickstart->button) {
+		kfree(name);
+		return -ENOMEM;
+	}
+
+	quickstart->button->name = name;
+	strcpy(quickstart->button->name, bid);
+
+	return 0;
+}
+
+static int quickstart_acpi_add(struct acpi_device *device)
+{
+	int ret;
+	acpi_status status;
+	struct quickstart_acpi *quickstart;
+
+	if (!device)
+		return -EINVAL;
+
+	quickstart = kzalloc(sizeof(*quickstart), GFP_KERNEL);
+	if (!quickstart)
+		return -ENOMEM;
+
+	quickstart->device = device;
+
+	strcpy(acpi_device_name(device), QUICKSTART_ACPI_DEVICE_NAME);
+	strcpy(acpi_device_class(device), QUICKSTART_ACPI_CLASS);
+	device->driver_data = quickstart;
+
+	/* Add button to list and initialize some stuff */
+	ret = quickstart_acpi_config(quickstart);
+	if (ret < 0)
+		goto fail_config;
+
+	status = acpi_install_notify_handler(device->handle, ACPI_ALL_NOTIFY,
+						quickstart_acpi_notify,
+						quickstart);
+	if (ACPI_FAILURE(status)) {
+		pr_err("Notify handler install error\n");
+		ret = -ENODEV;
+		goto fail_installnotify;
+	}
+
+	ret = quickstart_acpi_ghid(quickstart);
+	if (ret < 0)
+		goto fail_ghid;
+
+	return 0;
+
+fail_ghid:
+	acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY,
+						quickstart_acpi_notify);
+
+fail_installnotify:
+	quickstart_button_del(quickstart->button);
+
+fail_config:
+
+	kfree(quickstart);
+
+	return ret;
+}
+
+static int quickstart_acpi_remove(struct acpi_device *device, int type)
+{
+	acpi_status status;
+	struct quickstart_acpi *quickstart;
+
+	if (!device)
+		return -EINVAL;
+
+	quickstart = acpi_driver_data(device);
+	if (!quickstart)
+		return -EINVAL;
+
+	status = acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY,
+						quickstart_acpi_notify);
+	if (ACPI_FAILURE(status))
+		pr_err("Error removing notify handler\n");
+
+	kfree(quickstart);
+
+	return 0;
+}
+
+/* Platform driver structs */
+static DEVICE_ATTR(pressed_button, 0666, quickstart_pressed_button_show,
+					 quickstart_pressed_button_store);
+static DEVICE_ATTR(buttons, 0444, quickstart_buttons_show, NULL);
+static struct platform_device *pf_device;
+static struct platform_driver pf_driver = {
+	.driver = {
+		.name = QUICKSTART_PF_DRIVER_NAME,
+		.owner = THIS_MODULE,
+	}
+};
+
+static const struct acpi_device_id quickstart_device_ids[] = {
 	{QUICKSTART_ACPI_HID, 0},
 	{"", 0},
 };
@@ -86,273 +345,7 @@
 		},
 };
 
-/* Input device structs */
-struct input_dev *quickstart_input;
-
-/* Platform driver structs */
-static ssize_t buttons_show(struct device *dev,
-					struct device_attribute *attr,
-					char *buf);
-static ssize_t pressed_button_show(struct device *dev,
-					struct device_attribute *attr,
-					char *buf);
-static ssize_t pressed_button_store(struct device *dev,
-					struct device_attribute *attr,
-					 const char *buf,
-					 size_t count);
-static DEVICE_ATTR(pressed_button, 0666, pressed_button_show,
-					 pressed_button_store);
-static DEVICE_ATTR(buttons, 0444, buttons_show, NULL);
-static struct platform_device *pf_device;
-static struct platform_driver pf_driver = {
-	.driver = {
-		.name = QUICKSTART_PF_DRIVER_NAME,
-		.owner = THIS_MODULE,
-	}
-};
-
-/*
- * Platform driver functions
- */
-static ssize_t buttons_show(struct device *dev,
-					 struct device_attribute *attr,
-					 char *buf)
-{
-	int count = 0;
-	struct quickstart_btn *ptr = quickstart_data.btn_lst;
-
-	if (!ptr)
-		return snprintf(buf, PAGE_SIZE, "none");
-
-	while (ptr && (count < PAGE_SIZE)) {
-		if (ptr->name) {
-			count += snprintf(buf + count,
-					PAGE_SIZE - count,
-					"%d\t%s\n", ptr->id, ptr->name);
-		}
-		ptr = ptr->next;
-	}
-
-	return count;
-}
-
-static ssize_t pressed_button_show(struct device *dev,
-					struct device_attribute *attr,
-					char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%s\n",
-			(quickstart_data.pressed ?
-			 quickstart_data.pressed->name : "none"));
-}
-
-
-static ssize_t pressed_button_store(struct device *dev,
-					 struct device_attribute *attr,
-					 const char *buf, size_t count)
-{
-	if (count < 2)
-		return -EINVAL;
-
-	if (strncasecmp(buf, "none", 4) != 0)
-		return -EINVAL;
-
-	quickstart_data.pressed = NULL;
-	return count;
-}
-
-/* Hotstart Helper functions */
-static int quickstart_btnlst_add(struct quickstart_btn **data)
-{
-	struct quickstart_btn **ptr = &quickstart_data.btn_lst;
-
-	while (*ptr)
-		ptr = &((*ptr)->next);
-
-	*ptr = kzalloc(sizeof(struct quickstart_btn), GFP_KERNEL);
-	if (!*ptr) {
-		*data = NULL;
-		return -ENOMEM;
-	}
-	*data = *ptr;
-
-	return 0;
-}
-
-static void quickstart_btnlst_del(struct quickstart_btn *data)
-{
-	struct quickstart_btn **ptr = &quickstart_data.btn_lst;
-
-	if (!data)
-		return;
-
-	while (*ptr) {
-		if (*ptr == data) {
-			*ptr = (*ptr)->next;
-			kfree(data);
-			return;
-		}
-		ptr = &((*ptr)->next);
-	}
-
-	return;
-}
-
-static void quickstart_btnlst_free(void)
-{
-	struct quickstart_btn *ptr = quickstart_data.btn_lst;
-	struct quickstart_btn *lptr = NULL;
-
-	while (ptr) {
-		lptr = ptr;
-		ptr = ptr->next;
-		kfree(lptr->name);
-		kfree(lptr);
-	}
-
-	return;
-}
-
-/* ACPI Driver functions */
-static void quickstart_acpi_notify(acpi_handle handle, u32 event, void *data)
-{
-	struct quickstart_acpi *quickstart = data;
-
-	if (!quickstart)
-		return;
-
-	if (event == QUICKSTART_EVENT_WAKE)
-		quickstart_data.pressed = quickstart->btn;
-	else if (event == QUICKSTART_EVENT_RUNTIME) {
-		input_report_key(quickstart_input, quickstart->btn->id, 1);
-		input_sync(quickstart_input);
-		input_report_key(quickstart_input, quickstart->btn->id, 0);
-		input_sync(quickstart_input);
-	}
-	return;
-}
-
-static void quickstart_acpi_ghid(struct quickstart_acpi *quickstart)
-{
-	acpi_status status;
-	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-	uint32_t usageid = 0;
-
-	if (!quickstart)
-		return;
-
-	/* This returns a buffer telling the button usage ID,
-	 * and triggers pending notify events (The ones before booting). */
-	status = acpi_evaluate_object(quickstart->device->handle,
-					"GHID", NULL, &buffer);
-	if (ACPI_FAILURE(status) || !buffer.pointer) {
-		printk(KERN_ERR "quickstart: %s GHID method failed.\n",
-		       quickstart->btn->name);
-		return;
-	}
-
-	if (buffer.length < 8)
-		return;
-
-	/* <<The GHID method can return a BYTE, WORD, or DWORD.
-	 * The value must be encoded in little-endian byte
-	 * order (least significant byte first).>> */
-	usageid = *((uint32_t *)(buffer.pointer + (buffer.length - 8)));
-	quickstart->btn->id = usageid;
-
-	kfree(buffer.pointer);
-}
-
-static int quickstart_acpi_config(struct quickstart_acpi *quickstart, char *bid)
-{
-	int len = strlen(bid);
-	int ret;
-
-	/* Add button to list */
-	ret = quickstart_btnlst_add(&quickstart->btn);
-	if (ret)
-		return ret;
-
-	quickstart->btn->name = kzalloc(len + 1, GFP_KERNEL);
-	if (!quickstart->btn->name) {
-		quickstart_btnlst_free();
-		return -ENOMEM;
-	}
-	strcpy(quickstart->btn->name, bid);
-
-	return 0;
-}
-
-static int quickstart_acpi_add(struct acpi_device *device)
-{
-	int ret = 0;
-	acpi_status status = AE_OK;
-	struct quickstart_acpi *quickstart = NULL;
-
-	if (!device)
-		return -EINVAL;
-
-	quickstart = kzalloc(sizeof(struct quickstart_acpi), GFP_KERNEL);
-	if (!quickstart)
-		return -ENOMEM;
-
-	quickstart->device = device;
-	strcpy(acpi_device_name(device), QUICKSTART_ACPI_DEVICE_NAME);
-	strcpy(acpi_device_class(device), QUICKSTART_ACPI_CLASS);
-	device->driver_data = quickstart;
-
-	/* Add button to list and initialize some stuff */
-	ret = quickstart_acpi_config(quickstart, acpi_device_bid(device));
-	if (ret)
-		goto fail_config;
-
-	status = acpi_install_notify_handler(device->handle,
-						ACPI_ALL_NOTIFY,
-						quickstart_acpi_notify,
-						quickstart);
-	if (ACPI_FAILURE(status)) {
-		printk(KERN_ERR "quickstart: Notify handler install error\n");
-		ret = -ENODEV;
-		goto fail_installnotify;
-	}
-
-	quickstart_acpi_ghid(quickstart);
-
-	return 0;
-
-fail_installnotify:
-	quickstart_btnlst_del(quickstart->btn);
-
-fail_config:
-
-	kfree(quickstart);
-
-	return ret;
-}
-
-static int quickstart_acpi_remove(struct acpi_device *device, int type)
-{
-	acpi_status status = 0;
-	struct quickstart_acpi *quickstart = NULL;
-
-	if (!device || !acpi_driver_data(device))
-		return -EINVAL;
-
-	quickstart = acpi_driver_data(device);
-
-	status = acpi_remove_notify_handler(device->handle,
-						 ACPI_ALL_NOTIFY,
-					    quickstart_acpi_notify);
-	if (ACPI_FAILURE(status))
-		printk(KERN_ERR "quickstart: Error removing notify handler\n");
-
-
-	kfree(quickstart);
-
-	return 0;
-}
-
 /* Module functions */
-
 static void quickstart_exit(void)
 {
 	input_unregister_device(quickstart_input);
@@ -366,15 +359,12 @@
 
 	acpi_bus_unregister_driver(&quickstart_acpi_driver);
 
-	quickstart_btnlst_free();
-
-	return;
+	quickstart_buttons_free();
 }
 
 static int __init quickstart_init_input(void)
 {
-	struct quickstart_btn **ptr = &quickstart_data.btn_lst;
-	int count;
+	struct quickstart_button *b;
 	int ret;
 
 	quickstart_input = input_allocate_device();
@@ -385,11 +375,9 @@
 	quickstart_input->name = "Quickstart ACPI Buttons";
 	quickstart_input->id.bustype = BUS_HOST;
 
-	while (*ptr) {
-		count++;
+	list_for_each_entry(b, &buttons, list) {
 		set_bit(EV_KEY, quickstart_input->evbit);
-		set_bit((*ptr)->id, quickstart_input->keybit);
-		ptr = &((*ptr)->next);
+		set_bit(b->id, quickstart_input->keybit);
 	}
 
 	ret = input_register_device(quickstart_input);
@@ -415,7 +403,7 @@
 		return ret;
 
 	/* If existing bus with no devices */
-	if (!quickstart_data.btn_lst) {
+	if (list_empty(&buttons)) {
 		ret = -ENODEV;
 		goto fail_pfdrv_reg;
 	}
@@ -444,14 +432,12 @@
 	if (ret)
 		goto fail_dev_file2;
 
-
 	/* Input device */
 	ret = quickstart_init_input();
 	if (ret)
 		goto fail_input;
 
-	printk(KERN_INFO "quickstart: ACPI Direct App Launch ver %s\n",
-						QUICKSTART_VERSION);
+	pr_info("ACPI Direct App Launch ver %s\n", QUICKSTART_VERSION);
 
 	return 0;
 fail_input:
diff --git a/drivers/staging/ramster/Kconfig b/drivers/staging/ramster/Kconfig
new file mode 100644
index 0000000..8b57b87
--- /dev/null
+++ b/drivers/staging/ramster/Kconfig
@@ -0,0 +1,17 @@
+# Dependency on CONFIG_BROKEN is because there is a commit dependency
+# on a cleancache naming change to be submitted by Konrad Wilk
+# a39c00ded70339603ffe1b0ffdf3ade85bcf009a "Merge branch 'stable/cleancache.v13'
+# into linux-next.  Once this commit is present, BROKEN can be removed
+config RAMSTER
+	bool "Cross-machine RAM capacity sharing, aka peer-to-peer tmem"
+	depends on (CLEANCACHE || FRONTSWAP) && CONFIGFS_FS=y && !ZCACHE && !XVMALLOC && !HIGHMEM && BROKEN
+	select LZO_COMPRESS
+	select LZO_DECOMPRESS
+	default n
+	help
+	  RAMster allows RAM on other machines in a cluster to be utilized
+	  dynamically and symmetrically instead of swapping to a local swap
+	  disk, thus improving performance on memory-constrained workloads
+	  while minimizing total RAM across the cluster.  RAMster, like
+	  zcache, compresses swap pages into local RAM, but then remotifies
+	  the compressed pages to another node in the RAMster cluster.
diff --git a/drivers/staging/ramster/Makefile b/drivers/staging/ramster/Makefile
new file mode 100644
index 0000000..bcc13c8
--- /dev/null
+++ b/drivers/staging/ramster/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_RAMSTER)	+=	zcache-main.o tmem.o r2net.o xvmalloc.o cluster/
diff --git a/drivers/staging/ramster/TODO b/drivers/staging/ramster/TODO
new file mode 100644
index 0000000..46fcf0c
--- /dev/null
+++ b/drivers/staging/ramster/TODO
@@ -0,0 +1,13 @@
+For this staging driver, RAMster duplicates code from drivers/staging/zcache
+then incorporates changes to the local copy of the code.  For V5, it also
+directly incorporates the soon-to-be-removed drivers/staging/zram/xvmalloc.[ch]
+as all testing has been done with xvmalloc rather than the new zsmalloc.
+Before RAMster can be promoted from staging, the zcache and RAMster drivers
+should be either merged or reorganized to separate out common code.
+
+Until V4, RAMster duplicated code from fs/ocfs2/cluster, but this made
+RAMster incompatible with ocfs2 running in the same kernel and included
+lots of code that could be removed.  As of V5, the ocfs2 code has been
+mined and made RAMster-specific, made to communicate with a userland
+ramster-tools package rather than ocfs2-tools, and can co-exist with ocfs2
+both in the same kernel and in userland on the same machine.
diff --git a/drivers/staging/ramster/cluster/Makefile b/drivers/staging/ramster/cluster/Makefile
new file mode 100644
index 0000000..9c69436
--- /dev/null
+++ b/drivers/staging/ramster/cluster/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_RAMSTER) += ramster_nodemanager.o
+
+ramster_nodemanager-objs := heartbeat.o masklog.o nodemanager.o tcp.o
diff --git a/drivers/staging/ramster/cluster/heartbeat.c b/drivers/staging/ramster/cluster/heartbeat.c
new file mode 100644
index 0000000..0020949
--- /dev/null
+++ b/drivers/staging/ramster/cluster/heartbeat.c
@@ -0,0 +1,464 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * Copyright (C) 2004, 2005, 2012 Oracle.  All rights reserved.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/configfs.h>
+
+#include "heartbeat.h"
+#include "tcp.h"
+#include "nodemanager.h"
+
+#include "masklog.h"
+
+/*
+ * The first heartbeat pass had one global thread that would serialize all hb
+ * callback calls.  This global serializing sem should only be removed once
+ * we've made sure that all callees can deal with being called concurrently
+ * from multiple hb region threads.
+ */
+static DECLARE_RWSEM(r2hb_callback_sem);
+
+/*
+ * multiple hb threads are watching multiple regions.  A node is live
+ * whenever any of the threads sees activity from the node in its region.
+ */
+static DEFINE_SPINLOCK(r2hb_live_lock);
+static unsigned long r2hb_live_node_bitmap[BITS_TO_LONGS(R2NM_MAX_NODES)];
+
+static struct r2hb_callback {
+	struct list_head list;
+} r2hb_callbacks[R2HB_NUM_CB];
+
+enum r2hb_heartbeat_modes {
+	R2HB_HEARTBEAT_LOCAL		= 0,
+	R2HB_HEARTBEAT_GLOBAL,
+	R2HB_HEARTBEAT_NUM_MODES,
+};
+
+char *r2hb_heartbeat_mode_desc[R2HB_HEARTBEAT_NUM_MODES] = {
+		"local",	/* R2HB_HEARTBEAT_LOCAL */
+		"global",	/* R2HB_HEARTBEAT_GLOBAL */
+};
+
+unsigned int r2hb_dead_threshold = R2HB_DEFAULT_DEAD_THRESHOLD;
+unsigned int r2hb_heartbeat_mode = R2HB_HEARTBEAT_LOCAL;
+
+/* Only sets a new threshold if there are no active regions.
+ *
+ * No locking or otherwise interesting code is required for reading
+ * r2hb_dead_threshold as it can't change once regions are active and
+ * it's not interesting to anyone until then anyway. */
+static void r2hb_dead_threshold_set(unsigned int threshold)
+{
+	if (threshold > R2HB_MIN_DEAD_THRESHOLD) {
+		spin_lock(&r2hb_live_lock);
+		r2hb_dead_threshold = threshold;
+		spin_unlock(&r2hb_live_lock);
+	}
+}
+
+static int r2hb_global_hearbeat_mode_set(unsigned int hb_mode)
+{
+	int ret = -1;
+
+	if (hb_mode < R2HB_HEARTBEAT_NUM_MODES) {
+		spin_lock(&r2hb_live_lock);
+		r2hb_heartbeat_mode = hb_mode;
+		ret = 0;
+		spin_unlock(&r2hb_live_lock);
+	}
+
+	return ret;
+}
+
+void r2hb_exit(void)
+{
+}
+
+int r2hb_init(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(r2hb_callbacks); i++)
+		INIT_LIST_HEAD(&r2hb_callbacks[i].list);
+
+	memset(r2hb_live_node_bitmap, 0, sizeof(r2hb_live_node_bitmap));
+
+	return 0;
+}
+
+/* if we're already in a callback then we're already serialized by the sem */
+static void r2hb_fill_node_map_from_callback(unsigned long *map,
+					     unsigned bytes)
+{
+	BUG_ON(bytes < (BITS_TO_LONGS(R2NM_MAX_NODES) * sizeof(unsigned long)));
+
+	memcpy(map, &r2hb_live_node_bitmap, bytes);
+}
+
+/*
+ * get a map of all nodes that are heartbeating in any regions
+ */
+void r2hb_fill_node_map(unsigned long *map, unsigned bytes)
+{
+	/* callers want to serialize this map and callbacks so that they
+	 * can trust that they don't miss nodes coming to the party */
+	down_read(&r2hb_callback_sem);
+	spin_lock(&r2hb_live_lock);
+	r2hb_fill_node_map_from_callback(map, bytes);
+	spin_unlock(&r2hb_live_lock);
+	up_read(&r2hb_callback_sem);
+}
+EXPORT_SYMBOL_GPL(r2hb_fill_node_map);
+
+/*
+ * heartbeat configfs bits.  The heartbeat set is a default set under
+ * the cluster set in nodemanager.c.
+ */
+
+/* heartbeat set */
+
+struct r2hb_hb_group {
+	struct config_group hs_group;
+	/* some stuff? */
+};
+
+static struct r2hb_hb_group *to_r2hb_hb_group(struct config_group *group)
+{
+	return group ?
+		container_of(group, struct r2hb_hb_group, hs_group)
+		: NULL;
+}
+
+static struct config_item r2hb_config_item;
+
+static struct config_item *r2hb_hb_group_make_item(struct config_group *group,
+							  const char *name)
+{
+	int ret;
+
+	if (strlen(name) > R2HB_MAX_REGION_NAME_LEN) {
+		ret = -ENAMETOOLONG;
+		goto free;
+	}
+
+	config_item_put(&r2hb_config_item);
+
+	return &r2hb_config_item;
+free:
+	return ERR_PTR(ret);
+}
+
+static void r2hb_hb_group_drop_item(struct config_group *group,
+					   struct config_item *item)
+{
+	if (r2hb_global_heartbeat_active()) {
+		printk(KERN_NOTICE "ramster: Heartbeat %s "
+			"on region %s (%s)\n",
+			"stopped/aborted", config_item_name(item),
+			"no region");
+	}
+
+	config_item_put(item);
+}
+
+struct r2hb_hb_group_attribute {
+	struct configfs_attribute attr;
+	ssize_t (*show)(struct r2hb_hb_group *, char *);
+	ssize_t (*store)(struct r2hb_hb_group *, const char *, size_t);
+};
+
+static ssize_t r2hb_hb_group_show(struct config_item *item,
+					 struct configfs_attribute *attr,
+					 char *page)
+{
+	struct r2hb_hb_group *reg = to_r2hb_hb_group(to_config_group(item));
+	struct r2hb_hb_group_attribute *r2hb_hb_group_attr =
+		container_of(attr, struct r2hb_hb_group_attribute, attr);
+	ssize_t ret = 0;
+
+	if (r2hb_hb_group_attr->show)
+		ret = r2hb_hb_group_attr->show(reg, page);
+	return ret;
+}
+
+static ssize_t r2hb_hb_group_store(struct config_item *item,
+					  struct configfs_attribute *attr,
+					  const char *page, size_t count)
+{
+	struct r2hb_hb_group *reg = to_r2hb_hb_group(to_config_group(item));
+	struct r2hb_hb_group_attribute *r2hb_hb_group_attr =
+		container_of(attr, struct r2hb_hb_group_attribute, attr);
+	ssize_t ret = -EINVAL;
+
+	if (r2hb_hb_group_attr->store)
+		ret = r2hb_hb_group_attr->store(reg, page, count);
+	return ret;
+}
+
+static ssize_t r2hb_hb_group_threshold_show(struct r2hb_hb_group *group,
+						     char *page)
+{
+	return sprintf(page, "%u\n", r2hb_dead_threshold);
+}
+
+static ssize_t r2hb_hb_group_threshold_store(struct r2hb_hb_group *group,
+						    const char *page,
+						    size_t count)
+{
+	unsigned long tmp;
+	char *p = (char *)page;
+	int err;
+
+	err = kstrtoul(p, 10, &tmp);
+	if (err)
+		return err;
+
+	/* this will validate ranges for us. */
+	r2hb_dead_threshold_set((unsigned int) tmp);
+
+	return count;
+}
+
+static
+ssize_t r2hb_hb_group_mode_show(struct r2hb_hb_group *group,
+				       char *page)
+{
+	return sprintf(page, "%s\n",
+		       r2hb_heartbeat_mode_desc[r2hb_heartbeat_mode]);
+}
+
+static
+ssize_t r2hb_hb_group_mode_store(struct r2hb_hb_group *group,
+					const char *page, size_t count)
+{
+	unsigned int i;
+	int ret;
+	size_t len;
+
+	len = (page[count - 1] == '\n') ? count - 1 : count;
+	if (!len)
+		return -EINVAL;
+
+	for (i = 0; i < R2HB_HEARTBEAT_NUM_MODES; ++i) {
+		if (strnicmp(page, r2hb_heartbeat_mode_desc[i], len))
+			continue;
+
+		ret = r2hb_global_hearbeat_mode_set(i);
+		if (!ret)
+			printk(KERN_NOTICE "ramster: Heartbeat mode "
+						"set to %s\n",
+			       r2hb_heartbeat_mode_desc[i]);
+		return count;
+	}
+
+	return -EINVAL;
+
+}
+
+static struct r2hb_hb_group_attribute r2hb_hb_group_attr_threshold = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "dead_threshold",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2hb_hb_group_threshold_show,
+	.store	= r2hb_hb_group_threshold_store,
+};
+
+static struct r2hb_hb_group_attribute r2hb_hb_group_attr_mode = {
+	.attr   = { .ca_owner = THIS_MODULE,
+		.ca_name = "mode",
+		.ca_mode = S_IRUGO | S_IWUSR },
+	.show   = r2hb_hb_group_mode_show,
+	.store  = r2hb_hb_group_mode_store,
+};
+
+static struct configfs_attribute *r2hb_hb_group_attrs[] = {
+	&r2hb_hb_group_attr_threshold.attr,
+	&r2hb_hb_group_attr_mode.attr,
+	NULL,
+};
+
+static struct configfs_item_operations r2hb_hearbeat_group_item_ops = {
+	.show_attribute		= r2hb_hb_group_show,
+	.store_attribute	= r2hb_hb_group_store,
+};
+
+static struct configfs_group_operations r2hb_hb_group_group_ops = {
+	.make_item	= r2hb_hb_group_make_item,
+	.drop_item	= r2hb_hb_group_drop_item,
+};
+
+static struct config_item_type r2hb_hb_group_type = {
+	.ct_group_ops	= &r2hb_hb_group_group_ops,
+	.ct_item_ops	= &r2hb_hearbeat_group_item_ops,
+	.ct_attrs	= r2hb_hb_group_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* this is just here to avoid touching group in heartbeat.h which the
+ * entire damn world #includes */
+struct config_group *r2hb_alloc_hb_set(void)
+{
+	struct r2hb_hb_group *hs = NULL;
+	struct config_group *ret = NULL;
+
+	hs = kzalloc(sizeof(struct r2hb_hb_group), GFP_KERNEL);
+	if (hs == NULL)
+		goto out;
+
+	config_group_init_type_name(&hs->hs_group, "heartbeat",
+				    &r2hb_hb_group_type);
+
+	ret = &hs->hs_group;
+out:
+	if (ret == NULL)
+		kfree(hs);
+	return ret;
+}
+
+void r2hb_free_hb_set(struct config_group *group)
+{
+	struct r2hb_hb_group *hs = to_r2hb_hb_group(group);
+	kfree(hs);
+}
+
+/* hb callback registration and issuing */
+
+static struct r2hb_callback *hbcall_from_type(enum r2hb_callback_type type)
+{
+	if (type == R2HB_NUM_CB)
+		return ERR_PTR(-EINVAL);
+
+	return &r2hb_callbacks[type];
+}
+
+void r2hb_setup_callback(struct r2hb_callback_func *hc,
+			 enum r2hb_callback_type type,
+			 r2hb_cb_func *func,
+			 void *data,
+			 int priority)
+{
+	INIT_LIST_HEAD(&hc->hc_item);
+	hc->hc_func = func;
+	hc->hc_data = data;
+	hc->hc_priority = priority;
+	hc->hc_type = type;
+	hc->hc_magic = R2HB_CB_MAGIC;
+}
+EXPORT_SYMBOL_GPL(r2hb_setup_callback);
+
+int r2hb_register_callback(const char *region_uuid,
+			   struct r2hb_callback_func *hc)
+{
+	struct r2hb_callback_func *tmp;
+	struct list_head *iter;
+	struct r2hb_callback *hbcall;
+	int ret;
+
+	BUG_ON(hc->hc_magic != R2HB_CB_MAGIC);
+	BUG_ON(!list_empty(&hc->hc_item));
+
+	hbcall = hbcall_from_type(hc->hc_type);
+	if (IS_ERR(hbcall)) {
+		ret = PTR_ERR(hbcall);
+		goto out;
+	}
+
+	down_write(&r2hb_callback_sem);
+
+	list_for_each(iter, &hbcall->list) {
+		tmp = list_entry(iter, struct r2hb_callback_func, hc_item);
+		if (hc->hc_priority < tmp->hc_priority) {
+			list_add_tail(&hc->hc_item, iter);
+			break;
+		}
+	}
+	if (list_empty(&hc->hc_item))
+		list_add_tail(&hc->hc_item, &hbcall->list);
+
+	up_write(&r2hb_callback_sem);
+	ret = 0;
+out:
+	mlog(ML_CLUSTER, "returning %d on behalf of %p for funcs %p\n",
+	     ret, __builtin_return_address(0), hc);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(r2hb_register_callback);
+
+void r2hb_unregister_callback(const char *region_uuid,
+			      struct r2hb_callback_func *hc)
+{
+	BUG_ON(hc->hc_magic != R2HB_CB_MAGIC);
+
+	mlog(ML_CLUSTER, "on behalf of %p for funcs %p\n",
+	     __builtin_return_address(0), hc);
+
+	/* XXX Can this happen _with_ a region reference? */
+	if (list_empty(&hc->hc_item))
+		return;
+
+	down_write(&r2hb_callback_sem);
+
+	list_del_init(&hc->hc_item);
+
+	up_write(&r2hb_callback_sem);
+}
+EXPORT_SYMBOL_GPL(r2hb_unregister_callback);
+
+int r2hb_check_node_heartbeating_from_callback(u8 node_num)
+{
+	unsigned long testing_map[BITS_TO_LONGS(R2NM_MAX_NODES)];
+
+	r2hb_fill_node_map_from_callback(testing_map, sizeof(testing_map));
+	if (!test_bit(node_num, testing_map)) {
+		mlog(ML_HEARTBEAT,
+		     "node (%u) does not have heartbeating enabled.\n",
+		     node_num);
+		return 0;
+	}
+
+	return 1;
+}
+EXPORT_SYMBOL_GPL(r2hb_check_node_heartbeating_from_callback);
+
+void r2hb_stop_all_regions(void)
+{
+}
+EXPORT_SYMBOL_GPL(r2hb_stop_all_regions);
+
+/*
+ * this is just a hack until we get the plumbing which flips file systems
+ * read only and drops the hb ref instead of killing the node dead.
+ */
+int r2hb_global_heartbeat_active(void)
+{
+	return (r2hb_heartbeat_mode == R2HB_HEARTBEAT_GLOBAL);
+}
+EXPORT_SYMBOL(r2hb_global_heartbeat_active);
+
+/* added for RAMster */
+void r2hb_manual_set_node_heartbeating(int node_num)
+{
+	if (node_num < R2NM_MAX_NODES)
+		set_bit(node_num, r2hb_live_node_bitmap);
+}
+EXPORT_SYMBOL(r2hb_manual_set_node_heartbeating);
diff --git a/drivers/staging/ramster/cluster/heartbeat.h b/drivers/staging/ramster/cluster/heartbeat.h
new file mode 100644
index 0000000..6cbc775
--- /dev/null
+++ b/drivers/staging/ramster/cluster/heartbeat.h
@@ -0,0 +1,87 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * heartbeat.h
+ *
+ * Function prototypes
+ *
+ * Copyright (C) 2004 Oracle.  All rights reserved.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ */
+
+#ifndef R2CLUSTER_HEARTBEAT_H
+#define R2CLUSTER_HEARTBEAT_H
+
+#define R2HB_REGION_TIMEOUT_MS		2000
+
+#define R2HB_MAX_REGION_NAME_LEN	32
+
+/* number of changes to be seen as live */
+#define R2HB_LIVE_THRESHOLD	   2
+/* number of equal samples to be seen as dead */
+extern unsigned int r2hb_dead_threshold;
+#define R2HB_DEFAULT_DEAD_THRESHOLD	   31
+/* Otherwise MAX_WRITE_TIMEOUT will be zero... */
+#define R2HB_MIN_DEAD_THRESHOLD	  2
+#define R2HB_MAX_WRITE_TIMEOUT_MS \
+	(R2HB_REGION_TIMEOUT_MS * (r2hb_dead_threshold - 1))
+
+#define R2HB_CB_MAGIC		0x51d1e4ec
+
+/* callback stuff */
+enum r2hb_callback_type {
+	R2HB_NODE_DOWN_CB = 0,
+	R2HB_NODE_UP_CB,
+	R2HB_NUM_CB
+};
+
+struct r2nm_node;
+typedef void (r2hb_cb_func)(struct r2nm_node *, int, void *);
+
+struct r2hb_callback_func {
+	u32			hc_magic;
+	struct list_head	hc_item;
+	r2hb_cb_func		*hc_func;
+	void			*hc_data;
+	int			hc_priority;
+	enum r2hb_callback_type hc_type;
+};
+
+struct config_group *r2hb_alloc_hb_set(void);
+void r2hb_free_hb_set(struct config_group *group);
+
+void r2hb_setup_callback(struct r2hb_callback_func *hc,
+			 enum r2hb_callback_type type,
+			 r2hb_cb_func *func,
+			 void *data,
+			 int priority);
+int r2hb_register_callback(const char *region_uuid,
+			   struct r2hb_callback_func *hc);
+void r2hb_unregister_callback(const char *region_uuid,
+			      struct r2hb_callback_func *hc);
+void r2hb_fill_node_map(unsigned long *map,
+			unsigned bytes);
+void r2hb_exit(void);
+int r2hb_init(void);
+int r2hb_check_node_heartbeating_from_callback(u8 node_num);
+void r2hb_stop_all_regions(void);
+int r2hb_get_all_regions(char *region_uuids, u8 numregions);
+int r2hb_global_heartbeat_active(void);
+void r2hb_manual_set_node_heartbeating(int);
+
+#endif /* R2CLUSTER_HEARTBEAT_H */
diff --git a/drivers/staging/ramster/cluster/masklog.c b/drivers/staging/ramster/cluster/masklog.c
new file mode 100644
index 0000000..1261d85
--- /dev/null
+++ b/drivers/staging/ramster/cluster/masklog.c
@@ -0,0 +1,155 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * Copyright (C) 2004, 2005, 2012 Oracle.  All rights reserved.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+
+#include "masklog.h"
+
+struct mlog_bits r2_mlog_and_bits = MLOG_BITS_RHS(MLOG_INITIAL_AND_MASK);
+EXPORT_SYMBOL_GPL(r2_mlog_and_bits);
+struct mlog_bits r2_mlog_not_bits = MLOG_BITS_RHS(0);
+EXPORT_SYMBOL_GPL(r2_mlog_not_bits);
+
+static ssize_t mlog_mask_show(u64 mask, char *buf)
+{
+	char *state;
+
+	if (__mlog_test_u64(mask, r2_mlog_and_bits))
+		state = "allow";
+	else if (__mlog_test_u64(mask, r2_mlog_not_bits))
+		state = "deny";
+	else
+		state = "off";
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", state);
+}
+
+static ssize_t mlog_mask_store(u64 mask, const char *buf, size_t count)
+{
+	if (!strnicmp(buf, "allow", 5)) {
+		__mlog_set_u64(mask, r2_mlog_and_bits);
+		__mlog_clear_u64(mask, r2_mlog_not_bits);
+	} else if (!strnicmp(buf, "deny", 4)) {
+		__mlog_set_u64(mask, r2_mlog_not_bits);
+		__mlog_clear_u64(mask, r2_mlog_and_bits);
+	} else if (!strnicmp(buf, "off", 3)) {
+		__mlog_clear_u64(mask, r2_mlog_not_bits);
+		__mlog_clear_u64(mask, r2_mlog_and_bits);
+	} else
+		return -EINVAL;
+
+	return count;
+}
+
+struct mlog_attribute {
+	struct attribute attr;
+	u64 mask;
+};
+
+#define to_mlog_attr(_attr) container_of(_attr, struct mlog_attribute, attr)
+
+#define define_mask(_name) {			\
+	.attr = {				\
+		.name = #_name,			\
+		.mode = S_IRUGO | S_IWUSR,	\
+	},					\
+	.mask = ML_##_name,			\
+}
+
+static struct mlog_attribute mlog_attrs[MLOG_MAX_BITS] = {
+	define_mask(TCP),
+	define_mask(MSG),
+	define_mask(SOCKET),
+	define_mask(HEARTBEAT),
+	define_mask(HB_BIO),
+	define_mask(DLMFS),
+	define_mask(DLM),
+	define_mask(DLM_DOMAIN),
+	define_mask(DLM_THREAD),
+	define_mask(DLM_MASTER),
+	define_mask(DLM_RECOVERY),
+	define_mask(DLM_GLUE),
+	define_mask(VOTE),
+	define_mask(CONN),
+	define_mask(QUORUM),
+	define_mask(BASTS),
+	define_mask(CLUSTER),
+	define_mask(ERROR),
+	define_mask(NOTICE),
+	define_mask(KTHREAD),
+};
+
+static struct attribute *mlog_attr_ptrs[MLOG_MAX_BITS] = {NULL, };
+
+static ssize_t mlog_show(struct kobject *obj, struct attribute *attr,
+			 char *buf)
+{
+	struct mlog_attribute *mlog_attr = to_mlog_attr(attr);
+
+	return mlog_mask_show(mlog_attr->mask, buf);
+}
+
+static ssize_t mlog_store(struct kobject *obj, struct attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct mlog_attribute *mlog_attr = to_mlog_attr(attr);
+
+	return mlog_mask_store(mlog_attr->mask, buf, count);
+}
+
+static const struct sysfs_ops mlog_attr_ops = {
+	.show  = mlog_show,
+	.store = mlog_store,
+};
+
+static struct kobj_type mlog_ktype = {
+	.default_attrs = mlog_attr_ptrs,
+	.sysfs_ops     = &mlog_attr_ops,
+};
+
+static struct kset mlog_kset = {
+	.kobj   = {.ktype = &mlog_ktype},
+};
+
+int r2_mlog_sys_init(struct kset *r2cb_kset)
+{
+	int i = 0;
+
+	while (mlog_attrs[i].attr.mode) {
+		mlog_attr_ptrs[i] = &mlog_attrs[i].attr;
+		i++;
+	}
+	mlog_attr_ptrs[i] = NULL;
+
+	kobject_set_name(&mlog_kset.kobj, "logmask");
+	mlog_kset.kobj.kset = r2cb_kset;
+	return kset_register(&mlog_kset);
+}
+
+void r2_mlog_sys_shutdown(void)
+{
+	kset_unregister(&mlog_kset);
+}
diff --git a/drivers/staging/ramster/cluster/masklog.h b/drivers/staging/ramster/cluster/masklog.h
new file mode 100644
index 0000000..918ae11
--- /dev/null
+++ b/drivers/staging/ramster/cluster/masklog.h
@@ -0,0 +1,220 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * Copyright (C) 2005, 2012 Oracle.  All rights reserved.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef R2CLUSTER_MASKLOG_H
+#define R2CLUSTER_MASKLOG_H
+
+/*
+ * For now this is a trivial wrapper around printk() that gives the critical
+ * ability to enable sets of debugging output at run-time.  In the future this
+ * will almost certainly be redirected to relayfs so that it can pay a
+ * substantially lower heisenberg tax.
+ *
+ * Callers associate the message with a bitmask and a global bitmask is
+ * maintained with help from /proc.  If any of the bits match the message is
+ * output.
+ *
+ * We must have efficient bit tests on i386 and it seems gcc still emits crazy
+ * code for the 64bit compare.  It emits very good code for the dual unsigned
+ * long tests, though, completely avoiding tests that can never pass if the
+ * caller gives a constant bitmask that fills one of the longs with all 0s.  So
+ * the desire is to have almost all of the calls decided on by comparing just
+ * one of the longs.  This leads to having infrequently given bits that are
+ * frequently matched in the high bits.
+ *
+ * _ERROR and _NOTICE are used for messages that always go to the console and
+ * have appropriate KERN_ prefixes.  We wrap these in our function instead of
+ * just calling printk() so that this can eventually make its way through
+ * relayfs along with the debugging messages.  Everything else gets KERN_DEBUG.
+ * The inline tests and macro dance give GCC the opportunity to quite cleverly
+ * only emit the appropriage printk() when the caller passes in a constant
+ * mask, as is almost always the case.
+ *
+ * All this bitmask nonsense is managed from the files under
+ * /sys/fs/r2cb/logmask/.  Reading the files gives a straightforward
+ * indication of which bits are allowed (allow) or denied (off/deny).
+ *	ENTRY deny
+ *	EXIT deny
+ *	TCP off
+ *	MSG off
+ *	SOCKET off
+ *	ERROR allow
+ *	NOTICE allow
+ *
+ * Writing changes the state of a given bit and requires a strictly formatted
+ * single write() call:
+ *
+ *	write(fd, "allow", 5);
+ *
+ * Echoing allow/deny/off string into the logmask files can flip the bits
+ * on or off as expected; here is the bash script for example:
+ *
+ * log_mask="/sys/fs/r2cb/log_mask"
+ * for node in ENTRY EXIT TCP MSG SOCKET ERROR NOTICE; do
+ *	echo allow >"$log_mask"/"$node"
+ * done
+ *
+ * The debugfs.ramster tool can also flip the bits with the -l option:
+ *
+ * debugfs.ramster -l TCP allow
+ */
+
+/* for task_struct */
+#include <linux/sched.h>
+
+/* bits that are frequently given and infrequently matched in the low word */
+/* NOTE: If you add a flag, you need to also update masklog.c! */
+#define ML_TCP		0x0000000000000001ULL /* net cluster/tcp.c */
+#define ML_MSG		0x0000000000000002ULL /* net network messages */
+#define ML_SOCKET	0x0000000000000004ULL /* net socket lifetime */
+#define ML_HEARTBEAT	0x0000000000000008ULL /* hb all heartbeat tracking */
+#define ML_HB_BIO	0x0000000000000010ULL /* hb io tracing */
+#define ML_DLMFS	0x0000000000000020ULL /* dlm user dlmfs */
+#define ML_DLM		0x0000000000000040ULL /* dlm general debugging */
+#define ML_DLM_DOMAIN	0x0000000000000080ULL /* dlm domain debugging */
+#define ML_DLM_THREAD	0x0000000000000100ULL /* dlm domain thread */
+#define ML_DLM_MASTER	0x0000000000000200ULL /* dlm master functions */
+#define ML_DLM_RECOVERY	0x0000000000000400ULL /* dlm master functions */
+#define ML_DLM_GLUE	0x0000000000000800ULL /* ramster dlm glue layer */
+#define ML_VOTE		0x0000000000001000ULL /* ramster node messaging  */
+#define ML_CONN		0x0000000000002000ULL /* net connection management */
+#define ML_QUORUM	0x0000000000004000ULL /* net connection quorum */
+#define ML_BASTS	0x0000000000008000ULL /* dlmglue asts and basts */
+#define ML_CLUSTER	0x0000000000010000ULL /* cluster stack */
+
+/* bits that are infrequently given and frequently matched in the high word */
+#define ML_ERROR	0x1000000000000000ULL /* sent to KERN_ERR */
+#define ML_NOTICE	0x2000000000000000ULL /* setn to KERN_NOTICE */
+#define ML_KTHREAD	0x4000000000000000ULL /* kernel thread activity */
+
+#define MLOG_INITIAL_AND_MASK (ML_ERROR|ML_NOTICE)
+#ifndef MLOG_MASK_PREFIX
+#define MLOG_MASK_PREFIX 0
+#endif
+
+/*
+ * When logging is disabled, force the bit test to 0 for anything other
+ * than errors and notices, allowing gcc to remove the code completely.
+ * When enabled, allow all masks.
+ */
+#if defined(CONFIG_RAMSTER_DEBUG_MASKLOG)
+#define ML_ALLOWED_BITS (~0)
+#else
+#define ML_ALLOWED_BITS (ML_ERROR|ML_NOTICE)
+#endif
+
+#define MLOG_MAX_BITS 64
+
+struct mlog_bits {
+	unsigned long words[MLOG_MAX_BITS / BITS_PER_LONG];
+};
+
+extern struct mlog_bits r2_mlog_and_bits, r2_mlog_not_bits;
+
+#if BITS_PER_LONG == 32
+
+#define __mlog_test_u64(mask, bits)			\
+	((u32)(mask & 0xffffffff) & bits.words[0] ||	\
+	  ((u64)(mask) >> 32) & bits.words[1])
+#define __mlog_set_u64(mask, bits) do {			\
+	bits.words[0] |= (u32)(mask & 0xffffffff);	\
+	bits.words[1] |= (u64)(mask) >> 32;		\
+} while (0)
+#define __mlog_clear_u64(mask, bits) do {		\
+	bits.words[0] &= ~((u32)(mask & 0xffffffff));	\
+	bits.words[1] &= ~((u64)(mask) >> 32);		\
+} while (0)
+#define MLOG_BITS_RHS(mask) {				\
+	{						\
+		[0] = (u32)(mask & 0xffffffff),		\
+		[1] = (u64)(mask) >> 32,		\
+	}						\
+}
+
+#else /* 32bit long above, 64bit long below */
+
+#define __mlog_test_u64(mask, bits)	((mask) & bits.words[0])
+#define __mlog_set_u64(mask, bits) do {		\
+	bits.words[0] |= (mask);		\
+} while (0)
+#define __mlog_clear_u64(mask, bits) do {	\
+	bits.words[0] &= ~(mask);		\
+} while (0)
+#define MLOG_BITS_RHS(mask) { { (mask) } }
+
+#endif
+
+/*
+ * smp_processor_id() "helpfully" screams when called outside preemptible
+ * regions in current kernels.  sles doesn't have the variants that don't
+ * scream.  just do this instead of trying to guess which we're building
+ * against.. *sigh*.
+ */
+#define __mlog_cpu_guess ({		\
+	unsigned long _cpu = get_cpu();	\
+	put_cpu();			\
+	_cpu;				\
+})
+
+/* In the following two macros, the whitespace after the ',' just
+ * before ##args is intentional. Otherwise, gcc 2.95 will eat the
+ * previous token if args expands to nothing.
+ */
+#define __mlog_printk(level, fmt, args...)				\
+	printk(level "(%s,%u,%lu):%s:%d " fmt, current->comm,		\
+	       task_pid_nr(current), __mlog_cpu_guess,			\
+	       __PRETTY_FUNCTION__, __LINE__ , ##args)
+
+#define mlog(mask, fmt, args...) do {					\
+	u64 __m = MLOG_MASK_PREFIX | (mask);				\
+	if ((__m & ML_ALLOWED_BITS) &&					\
+	    __mlog_test_u64(__m, r2_mlog_and_bits) &&			\
+	    !__mlog_test_u64(__m, r2_mlog_not_bits)) {			\
+		if (__m & ML_ERROR)					\
+			__mlog_printk(KERN_ERR, "ERROR: "fmt , ##args);	\
+		else if (__m & ML_NOTICE)				\
+			__mlog_printk(KERN_NOTICE, fmt , ##args);	\
+		else							\
+			__mlog_printk(KERN_INFO, fmt , ##args);		\
+	}								\
+} while (0)
+
+#define mlog_errno(st) do {						\
+	int _st = (st);							\
+	if (_st != -ERESTARTSYS && _st != -EINTR &&			\
+	    _st != AOP_TRUNCATED_PAGE && _st != -ENOSPC)		\
+		mlog(ML_ERROR, "status = %lld\n", (long long)_st);	\
+} while (0)
+
+#define mlog_bug_on_msg(cond, fmt, args...) do {			\
+	if (cond) {							\
+		mlog(ML_ERROR, "bug expression: " #cond "\n");		\
+		mlog(ML_ERROR, fmt, ##args);				\
+		BUG();							\
+	}								\
+} while (0)
+
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+int r2_mlog_sys_init(struct kset *r2cb_subsys);
+void r2_mlog_sys_shutdown(void);
+
+#endif /* R2CLUSTER_MASKLOG_H */
diff --git a/drivers/staging/ramster/cluster/nodemanager.c b/drivers/staging/ramster/cluster/nodemanager.c
new file mode 100644
index 0000000..de0e5c8
--- /dev/null
+++ b/drivers/staging/ramster/cluster/nodemanager.c
@@ -0,0 +1,992 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * Copyright (C) 2004, 2005, 2012 Oracle.  All rights reserved.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/configfs.h>
+
+#include "tcp.h"
+#include "nodemanager.h"
+#include "heartbeat.h"
+#include "masklog.h"
+
+/* for now we operate under the assertion that there can be only one
+ * cluster active at a time.  Changing this will require trickling
+ * cluster references throughout where nodes are looked up */
+struct r2nm_cluster *r2nm_single_cluster;
+
+char *r2nm_fence_method_desc[R2NM_FENCE_METHODS] = {
+		"reset",	/* R2NM_FENCE_RESET */
+		"panic",	/* R2NM_FENCE_PANIC */
+};
+
+struct r2nm_node *r2nm_get_node_by_num(u8 node_num)
+{
+	struct r2nm_node *node = NULL;
+
+	if (node_num >= R2NM_MAX_NODES || r2nm_single_cluster == NULL)
+		goto out;
+
+	read_lock(&r2nm_single_cluster->cl_nodes_lock);
+	node = r2nm_single_cluster->cl_nodes[node_num];
+	if (node)
+		config_item_get(&node->nd_item);
+	read_unlock(&r2nm_single_cluster->cl_nodes_lock);
+out:
+	return node;
+}
+EXPORT_SYMBOL_GPL(r2nm_get_node_by_num);
+
+int r2nm_configured_node_map(unsigned long *map, unsigned bytes)
+{
+	struct r2nm_cluster *cluster = r2nm_single_cluster;
+
+	BUG_ON(bytes < (sizeof(cluster->cl_nodes_bitmap)));
+
+	if (cluster == NULL)
+		return -EINVAL;
+
+	read_lock(&cluster->cl_nodes_lock);
+	memcpy(map, cluster->cl_nodes_bitmap, sizeof(cluster->cl_nodes_bitmap));
+	read_unlock(&cluster->cl_nodes_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(r2nm_configured_node_map);
+
+static struct r2nm_node *r2nm_node_ip_tree_lookup(struct r2nm_cluster *cluster,
+						  __be32 ip_needle,
+						  struct rb_node ***ret_p,
+						  struct rb_node **ret_parent)
+{
+	struct rb_node **p = &cluster->cl_node_ip_tree.rb_node;
+	struct rb_node *parent = NULL;
+	struct r2nm_node *node, *ret = NULL;
+
+	while (*p) {
+		int cmp;
+
+		parent = *p;
+		node = rb_entry(parent, struct r2nm_node, nd_ip_node);
+
+		cmp = memcmp(&ip_needle, &node->nd_ipv4_address,
+				sizeof(ip_needle));
+		if (cmp < 0)
+			p = &(*p)->rb_left;
+		else if (cmp > 0)
+			p = &(*p)->rb_right;
+		else {
+			ret = node;
+			break;
+		}
+	}
+
+	if (ret_p != NULL)
+		*ret_p = p;
+	if (ret_parent != NULL)
+		*ret_parent = parent;
+
+	return ret;
+}
+
+struct r2nm_node *r2nm_get_node_by_ip(__be32 addr)
+{
+	struct r2nm_node *node = NULL;
+	struct r2nm_cluster *cluster = r2nm_single_cluster;
+
+	if (cluster == NULL)
+		goto out;
+
+	read_lock(&cluster->cl_nodes_lock);
+	node = r2nm_node_ip_tree_lookup(cluster, addr, NULL, NULL);
+	if (node)
+		config_item_get(&node->nd_item);
+	read_unlock(&cluster->cl_nodes_lock);
+
+out:
+	return node;
+}
+EXPORT_SYMBOL_GPL(r2nm_get_node_by_ip);
+
+void r2nm_node_put(struct r2nm_node *node)
+{
+	config_item_put(&node->nd_item);
+}
+EXPORT_SYMBOL_GPL(r2nm_node_put);
+
+void r2nm_node_get(struct r2nm_node *node)
+{
+	config_item_get(&node->nd_item);
+}
+EXPORT_SYMBOL_GPL(r2nm_node_get);
+
+u8 r2nm_this_node(void)
+{
+	u8 node_num = R2NM_MAX_NODES;
+
+	if (r2nm_single_cluster && r2nm_single_cluster->cl_has_local)
+		node_num = r2nm_single_cluster->cl_local_node;
+
+	return node_num;
+}
+EXPORT_SYMBOL_GPL(r2nm_this_node);
+
+/* node configfs bits */
+
+static struct r2nm_cluster *to_r2nm_cluster(struct config_item *item)
+{
+	return item ?
+		container_of(to_config_group(item), struct r2nm_cluster,
+			     cl_group)
+		: NULL;
+}
+
+static struct r2nm_node *to_r2nm_node(struct config_item *item)
+{
+	return item ? container_of(item, struct r2nm_node, nd_item) : NULL;
+}
+
+static void r2nm_node_release(struct config_item *item)
+{
+	struct r2nm_node *node = to_r2nm_node(item);
+	kfree(node);
+}
+
+static ssize_t r2nm_node_num_read(struct r2nm_node *node, char *page)
+{
+	return sprintf(page, "%d\n", node->nd_num);
+}
+
+static struct r2nm_cluster *to_r2nm_cluster_from_node(struct r2nm_node *node)
+{
+	/* through the first node_set .parent
+	 * mycluster/nodes/mynode == r2nm_cluster->r2nm_node_group->r2nm_node */
+	return to_r2nm_cluster(node->nd_item.ci_parent->ci_parent);
+}
+
+enum {
+	R2NM_NODE_ATTR_NUM = 0,
+	R2NM_NODE_ATTR_PORT,
+	R2NM_NODE_ATTR_ADDRESS,
+	R2NM_NODE_ATTR_LOCAL,
+};
+
+static ssize_t r2nm_node_num_write(struct r2nm_node *node, const char *page,
+				   size_t count)
+{
+	struct r2nm_cluster *cluster = to_r2nm_cluster_from_node(node);
+	unsigned long tmp;
+	char *p = (char *)page;
+	int err;
+
+	err = kstrtoul(p, 10, &tmp);
+	if (err)
+		return err;
+
+	if (tmp >= R2NM_MAX_NODES)
+		return -ERANGE;
+
+	/* once we're in the cl_nodes tree networking can look us up by
+	 * node number and try to use our address and port attributes
+	 * to connect to this node.. make sure that they've been set
+	 * before writing the node attribute? */
+	if (!test_bit(R2NM_NODE_ATTR_ADDRESS, &node->nd_set_attributes) ||
+	    !test_bit(R2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
+		return -EINVAL; /* XXX */
+
+	write_lock(&cluster->cl_nodes_lock);
+	if (cluster->cl_nodes[tmp])
+		p = NULL;
+	else  {
+		cluster->cl_nodes[tmp] = node;
+		node->nd_num = tmp;
+		set_bit(tmp, cluster->cl_nodes_bitmap);
+	}
+	write_unlock(&cluster->cl_nodes_lock);
+	if (p == NULL)
+		return -EEXIST;
+
+	return count;
+}
+static ssize_t r2nm_node_ipv4_port_read(struct r2nm_node *node, char *page)
+{
+	return sprintf(page, "%u\n", ntohs(node->nd_ipv4_port));
+}
+
+static ssize_t r2nm_node_ipv4_port_write(struct r2nm_node *node,
+					 const char *page, size_t count)
+{
+	unsigned long tmp;
+	char *p = (char *)page;
+	int err;
+
+	err = kstrtoul(p, 10, &tmp);
+	if (err)
+		return err;
+
+	if (tmp == 0)
+		return -EINVAL;
+	if (tmp >= (u16)-1)
+		return -ERANGE;
+
+	node->nd_ipv4_port = htons(tmp);
+
+	return count;
+}
+
+static ssize_t r2nm_node_ipv4_address_read(struct r2nm_node *node, char *page)
+{
+	return sprintf(page, "%pI4\n", &node->nd_ipv4_address);
+}
+
+static ssize_t r2nm_node_ipv4_address_write(struct r2nm_node *node,
+					    const char *page,
+					    size_t count)
+{
+	struct r2nm_cluster *cluster = to_r2nm_cluster_from_node(node);
+	int ret, i;
+	struct rb_node **p, *parent;
+	unsigned int octets[4];
+	__be32 ipv4_addr = 0;
+
+	ret = sscanf(page, "%3u.%3u.%3u.%3u", &octets[3], &octets[2],
+		     &octets[1], &octets[0]);
+	if (ret != 4)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(octets); i++) {
+		if (octets[i] > 255)
+			return -ERANGE;
+		be32_add_cpu(&ipv4_addr, octets[i] << (i * 8));
+	}
+
+	ret = 0;
+	write_lock(&cluster->cl_nodes_lock);
+	if (r2nm_node_ip_tree_lookup(cluster, ipv4_addr, &p, &parent))
+		ret = -EEXIST;
+	else {
+		rb_link_node(&node->nd_ip_node, parent, p);
+		rb_insert_color(&node->nd_ip_node, &cluster->cl_node_ip_tree);
+	}
+	write_unlock(&cluster->cl_nodes_lock);
+	if (ret)
+		return ret;
+
+	memcpy(&node->nd_ipv4_address, &ipv4_addr, sizeof(ipv4_addr));
+
+	return count;
+}
+
+static ssize_t r2nm_node_local_read(struct r2nm_node *node, char *page)
+{
+	return sprintf(page, "%d\n", node->nd_local);
+}
+
+static ssize_t r2nm_node_local_write(struct r2nm_node *node, const char *page,
+				     size_t count)
+{
+	struct r2nm_cluster *cluster = to_r2nm_cluster_from_node(node);
+	unsigned long tmp;
+	char *p = (char *)page;
+	ssize_t ret;
+	int err;
+
+	err = kstrtoul(p, 10, &tmp);
+	if (err)
+		return err;
+
+	tmp = !!tmp; /* boolean of whether this node wants to be local */
+
+	/* setting local turns on networking rx for now so we require having
+	 * set everything else first */
+	if (!test_bit(R2NM_NODE_ATTR_ADDRESS, &node->nd_set_attributes) ||
+	    !test_bit(R2NM_NODE_ATTR_NUM, &node->nd_set_attributes) ||
+	    !test_bit(R2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
+		return -EINVAL; /* XXX */
+
+	/* the only failure case is trying to set a new local node
+	 * when a different one is already set */
+	if (tmp && tmp == cluster->cl_has_local &&
+	    cluster->cl_local_node != node->nd_num)
+		return -EBUSY;
+
+	/* bring up the rx thread if we're setting the new local node. */
+	if (tmp && !cluster->cl_has_local) {
+		ret = r2net_start_listening(node);
+		if (ret)
+			return ret;
+	}
+
+	if (!tmp && cluster->cl_has_local &&
+	    cluster->cl_local_node == node->nd_num) {
+		r2net_stop_listening(node);
+		cluster->cl_local_node = R2NM_INVALID_NODE_NUM;
+	}
+
+	node->nd_local = tmp;
+	if (node->nd_local) {
+		cluster->cl_has_local = tmp;
+		cluster->cl_local_node = node->nd_num;
+	}
+
+	return count;
+}
+
+struct r2nm_node_attribute {
+	struct configfs_attribute attr;
+	ssize_t (*show)(struct r2nm_node *, char *);
+	ssize_t (*store)(struct r2nm_node *, const char *, size_t);
+};
+
+static struct r2nm_node_attribute r2nm_node_attr_num = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "num",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2nm_node_num_read,
+	.store	= r2nm_node_num_write,
+};
+
+static struct r2nm_node_attribute r2nm_node_attr_ipv4_port = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "ipv4_port",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2nm_node_ipv4_port_read,
+	.store	= r2nm_node_ipv4_port_write,
+};
+
+static struct r2nm_node_attribute r2nm_node_attr_ipv4_address = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "ipv4_address",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2nm_node_ipv4_address_read,
+	.store	= r2nm_node_ipv4_address_write,
+};
+
+static struct r2nm_node_attribute r2nm_node_attr_local = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "local",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2nm_node_local_read,
+	.store	= r2nm_node_local_write,
+};
+
+static struct configfs_attribute *r2nm_node_attrs[] = {
+	[R2NM_NODE_ATTR_NUM] = &r2nm_node_attr_num.attr,
+	[R2NM_NODE_ATTR_PORT] = &r2nm_node_attr_ipv4_port.attr,
+	[R2NM_NODE_ATTR_ADDRESS] = &r2nm_node_attr_ipv4_address.attr,
+	[R2NM_NODE_ATTR_LOCAL] = &r2nm_node_attr_local.attr,
+	NULL,
+};
+
+static int r2nm_attr_index(struct configfs_attribute *attr)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(r2nm_node_attrs); i++) {
+		if (attr == r2nm_node_attrs[i])
+			return i;
+	}
+	BUG();
+	return 0;
+}
+
+static ssize_t r2nm_node_show(struct config_item *item,
+			      struct configfs_attribute *attr,
+			      char *page)
+{
+	struct r2nm_node *node = to_r2nm_node(item);
+	struct r2nm_node_attribute *r2nm_node_attr =
+		container_of(attr, struct r2nm_node_attribute, attr);
+	ssize_t ret = 0;
+
+	if (r2nm_node_attr->show)
+		ret = r2nm_node_attr->show(node, page);
+	return ret;
+}
+
+static ssize_t r2nm_node_store(struct config_item *item,
+			       struct configfs_attribute *attr,
+			       const char *page, size_t count)
+{
+	struct r2nm_node *node = to_r2nm_node(item);
+	struct r2nm_node_attribute *r2nm_node_attr =
+		container_of(attr, struct r2nm_node_attribute, attr);
+	ssize_t ret;
+	int attr_index = r2nm_attr_index(attr);
+
+	if (r2nm_node_attr->store == NULL) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (test_bit(attr_index, &node->nd_set_attributes))
+		return -EBUSY;
+
+	ret = r2nm_node_attr->store(node, page, count);
+	if (ret < count)
+		goto out;
+
+	set_bit(attr_index, &node->nd_set_attributes);
+out:
+	return ret;
+}
+
+static struct configfs_item_operations r2nm_node_item_ops = {
+	.release		= r2nm_node_release,
+	.show_attribute		= r2nm_node_show,
+	.store_attribute	= r2nm_node_store,
+};
+
+static struct config_item_type r2nm_node_type = {
+	.ct_item_ops	= &r2nm_node_item_ops,
+	.ct_attrs	= r2nm_node_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* node set */
+
+struct r2nm_node_group {
+	struct config_group ns_group;
+	/* some stuff? */
+};
+
+#if 0
+static struct r2nm_node_group *to_r2nm_node_group(struct config_group *group)
+{
+	return group ?
+		container_of(group, struct r2nm_node_group, ns_group)
+		: NULL;
+}
+#endif
+
+struct r2nm_cluster_attribute {
+	struct configfs_attribute attr;
+	ssize_t (*show)(struct r2nm_cluster *, char *);
+	ssize_t (*store)(struct r2nm_cluster *, const char *, size_t);
+};
+
+static ssize_t r2nm_cluster_attr_write(const char *page, ssize_t count,
+					unsigned int *val)
+{
+	unsigned long tmp;
+	char *p = (char *)page;
+	int err;
+
+	err = kstrtoul(p, 10, &tmp);
+	if (err)
+		return err;
+
+	if (tmp == 0)
+		return -EINVAL;
+	if (tmp >= (u32)-1)
+		return -ERANGE;
+
+	*val = tmp;
+
+	return count;
+}
+
+static ssize_t r2nm_cluster_attr_idle_timeout_ms_read(
+	struct r2nm_cluster *cluster, char *page)
+{
+	return sprintf(page, "%u\n", cluster->cl_idle_timeout_ms);
+}
+
+static ssize_t r2nm_cluster_attr_idle_timeout_ms_write(
+	struct r2nm_cluster *cluster, const char *page, size_t count)
+{
+	ssize_t ret;
+	unsigned int val = 0;
+
+	ret =  r2nm_cluster_attr_write(page, count, &val);
+
+	if (ret > 0) {
+		if (cluster->cl_idle_timeout_ms != val
+			&& r2net_num_connected_peers()) {
+			mlog(ML_NOTICE,
+			     "r2net: cannot change idle timeout after "
+			     "the first peer has agreed to it."
+			     "  %d connected peers\n",
+			     r2net_num_connected_peers());
+			ret = -EINVAL;
+		} else if (val <= cluster->cl_keepalive_delay_ms) {
+			mlog(ML_NOTICE, "r2net: idle timeout must be larger "
+			     "than keepalive delay\n");
+			ret = -EINVAL;
+		} else {
+			cluster->cl_idle_timeout_ms = val;
+		}
+	}
+
+	return ret;
+}
+
+static ssize_t r2nm_cluster_attr_keepalive_delay_ms_read(
+	struct r2nm_cluster *cluster, char *page)
+{
+	return sprintf(page, "%u\n", cluster->cl_keepalive_delay_ms);
+}
+
+static ssize_t r2nm_cluster_attr_keepalive_delay_ms_write(
+	struct r2nm_cluster *cluster, const char *page, size_t count)
+{
+	ssize_t ret;
+	unsigned int val = 0;
+
+	ret =  r2nm_cluster_attr_write(page, count, &val);
+
+	if (ret > 0) {
+		if (cluster->cl_keepalive_delay_ms != val
+		    && r2net_num_connected_peers()) {
+			mlog(ML_NOTICE,
+			     "r2net: cannot change keepalive delay after"
+			     " the first peer has agreed to it."
+			     "  %d connected peers\n",
+			     r2net_num_connected_peers());
+			ret = -EINVAL;
+		} else if (val >= cluster->cl_idle_timeout_ms) {
+			mlog(ML_NOTICE, "r2net: keepalive delay must be "
+			     "smaller than idle timeout\n");
+			ret = -EINVAL;
+		} else {
+			cluster->cl_keepalive_delay_ms = val;
+		}
+	}
+
+	return ret;
+}
+
+static ssize_t r2nm_cluster_attr_reconnect_delay_ms_read(
+	struct r2nm_cluster *cluster, char *page)
+{
+	return sprintf(page, "%u\n", cluster->cl_reconnect_delay_ms);
+}
+
+static ssize_t r2nm_cluster_attr_reconnect_delay_ms_write(
+	struct r2nm_cluster *cluster, const char *page, size_t count)
+{
+	return r2nm_cluster_attr_write(page, count,
+					&cluster->cl_reconnect_delay_ms);
+}
+
+static ssize_t r2nm_cluster_attr_fence_method_read(
+	struct r2nm_cluster *cluster, char *page)
+{
+	ssize_t ret = 0;
+
+	if (cluster)
+		ret = sprintf(page, "%s\n",
+			      r2nm_fence_method_desc[cluster->cl_fence_method]);
+	return ret;
+}
+
+static ssize_t r2nm_cluster_attr_fence_method_write(
+	struct r2nm_cluster *cluster, const char *page, size_t count)
+{
+	unsigned int i;
+
+	if (page[count - 1] != '\n')
+		goto bail;
+
+	for (i = 0; i < R2NM_FENCE_METHODS; ++i) {
+		if (count != strlen(r2nm_fence_method_desc[i]) + 1)
+			continue;
+		if (strncasecmp(page, r2nm_fence_method_desc[i], count - 1))
+			continue;
+		if (cluster->cl_fence_method != i) {
+			printk(KERN_INFO "ramster: Changing fence method to %s\n",
+			       r2nm_fence_method_desc[i]);
+			cluster->cl_fence_method = i;
+		}
+		return count;
+	}
+
+bail:
+	return -EINVAL;
+}
+
+static struct r2nm_cluster_attribute r2nm_cluster_attr_idle_timeout_ms = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "idle_timeout_ms",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2nm_cluster_attr_idle_timeout_ms_read,
+	.store	= r2nm_cluster_attr_idle_timeout_ms_write,
+};
+
+static struct r2nm_cluster_attribute r2nm_cluster_attr_keepalive_delay_ms = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "keepalive_delay_ms",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2nm_cluster_attr_keepalive_delay_ms_read,
+	.store	= r2nm_cluster_attr_keepalive_delay_ms_write,
+};
+
+static struct r2nm_cluster_attribute r2nm_cluster_attr_reconnect_delay_ms = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "reconnect_delay_ms",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2nm_cluster_attr_reconnect_delay_ms_read,
+	.store	= r2nm_cluster_attr_reconnect_delay_ms_write,
+};
+
+static struct r2nm_cluster_attribute r2nm_cluster_attr_fence_method = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "fence_method",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2nm_cluster_attr_fence_method_read,
+	.store	= r2nm_cluster_attr_fence_method_write,
+};
+
+static struct configfs_attribute *r2nm_cluster_attrs[] = {
+	&r2nm_cluster_attr_idle_timeout_ms.attr,
+	&r2nm_cluster_attr_keepalive_delay_ms.attr,
+	&r2nm_cluster_attr_reconnect_delay_ms.attr,
+	&r2nm_cluster_attr_fence_method.attr,
+	NULL,
+};
+static ssize_t r2nm_cluster_show(struct config_item *item,
+					struct configfs_attribute *attr,
+					char *page)
+{
+	struct r2nm_cluster *cluster = to_r2nm_cluster(item);
+	struct r2nm_cluster_attribute *r2nm_cluster_attr =
+		container_of(attr, struct r2nm_cluster_attribute, attr);
+	ssize_t ret = 0;
+
+	if (r2nm_cluster_attr->show)
+		ret = r2nm_cluster_attr->show(cluster, page);
+	return ret;
+}
+
+static ssize_t r2nm_cluster_store(struct config_item *item,
+					struct configfs_attribute *attr,
+					const char *page, size_t count)
+{
+	struct r2nm_cluster *cluster = to_r2nm_cluster(item);
+	struct r2nm_cluster_attribute *r2nm_cluster_attr =
+		container_of(attr, struct r2nm_cluster_attribute, attr);
+	ssize_t ret;
+
+	if (r2nm_cluster_attr->store == NULL) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = r2nm_cluster_attr->store(cluster, page, count);
+	if (ret < count)
+		goto out;
+out:
+	return ret;
+}
+
+static struct config_item *r2nm_node_group_make_item(struct config_group *group,
+						     const char *name)
+{
+	struct r2nm_node *node = NULL;
+
+	if (strlen(name) > R2NM_MAX_NAME_LEN)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	node = kzalloc(sizeof(struct r2nm_node), GFP_KERNEL);
+	if (node == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	strcpy(node->nd_name, name); /* use item.ci_namebuf instead? */
+	config_item_init_type_name(&node->nd_item, name, &r2nm_node_type);
+	spin_lock_init(&node->nd_lock);
+
+	mlog(ML_CLUSTER, "r2nm: Registering node %s\n", name);
+
+	return &node->nd_item;
+}
+
+static void r2nm_node_group_drop_item(struct config_group *group,
+				      struct config_item *item)
+{
+	struct r2nm_node *node = to_r2nm_node(item);
+	struct r2nm_cluster *cluster =
+				to_r2nm_cluster(group->cg_item.ci_parent);
+
+	r2net_disconnect_node(node);
+
+	if (cluster->cl_has_local &&
+	    (cluster->cl_local_node == node->nd_num)) {
+		cluster->cl_has_local = 0;
+		cluster->cl_local_node = R2NM_INVALID_NODE_NUM;
+		r2net_stop_listening(node);
+	}
+
+	/* XXX call into net to stop this node from trading messages */
+
+	write_lock(&cluster->cl_nodes_lock);
+
+	/* XXX sloppy */
+	if (node->nd_ipv4_address)
+		rb_erase(&node->nd_ip_node, &cluster->cl_node_ip_tree);
+
+	/* nd_num might be 0 if the node number hasn't been set.. */
+	if (cluster->cl_nodes[node->nd_num] == node) {
+		cluster->cl_nodes[node->nd_num] = NULL;
+		clear_bit(node->nd_num, cluster->cl_nodes_bitmap);
+	}
+	write_unlock(&cluster->cl_nodes_lock);
+
+	mlog(ML_CLUSTER, "r2nm: Unregistered node %s\n",
+	     config_item_name(&node->nd_item));
+
+	config_item_put(item);
+}
+
+static struct configfs_group_operations r2nm_node_group_group_ops = {
+	.make_item	= r2nm_node_group_make_item,
+	.drop_item	= r2nm_node_group_drop_item,
+};
+
+static struct config_item_type r2nm_node_group_type = {
+	.ct_group_ops	= &r2nm_node_group_group_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* cluster */
+
+static void r2nm_cluster_release(struct config_item *item)
+{
+	struct r2nm_cluster *cluster = to_r2nm_cluster(item);
+
+	kfree(cluster->cl_group.default_groups);
+	kfree(cluster);
+}
+
+static struct configfs_item_operations r2nm_cluster_item_ops = {
+	.release	= r2nm_cluster_release,
+	.show_attribute		= r2nm_cluster_show,
+	.store_attribute	= r2nm_cluster_store,
+};
+
+static struct config_item_type r2nm_cluster_type = {
+	.ct_item_ops	= &r2nm_cluster_item_ops,
+	.ct_attrs	= r2nm_cluster_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* cluster set */
+
+struct r2nm_cluster_group {
+	struct configfs_subsystem cs_subsys;
+	/* some stuff? */
+};
+
+#if 0
+static struct r2nm_cluster_group *
+to_r2nm_cluster_group(struct config_group *group)
+{
+	return group ?
+		container_of(to_configfs_subsystem(group),
+				struct r2nm_cluster_group, cs_subsys)
+	       : NULL;
+}
+#endif
+
+static struct config_group *
+r2nm_cluster_group_make_group(struct config_group *group,
+							  const char *name)
+{
+	struct r2nm_cluster *cluster = NULL;
+	struct r2nm_node_group *ns = NULL;
+	struct config_group *r2hb_group = NULL, *ret = NULL;
+	void *defs = NULL;
+
+	/* this runs under the parent dir's i_mutex; there can be only
+	 * one caller in here at a time */
+	if (r2nm_single_cluster)
+		return ERR_PTR(-ENOSPC);
+
+	cluster = kzalloc(sizeof(struct r2nm_cluster), GFP_KERNEL);
+	ns = kzalloc(sizeof(struct r2nm_node_group), GFP_KERNEL);
+	defs = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL);
+	r2hb_group = r2hb_alloc_hb_set();
+	if (cluster == NULL || ns == NULL || r2hb_group == NULL || defs == NULL)
+		goto out;
+
+	config_group_init_type_name(&cluster->cl_group, name,
+				    &r2nm_cluster_type);
+	config_group_init_type_name(&ns->ns_group, "node",
+				    &r2nm_node_group_type);
+
+	cluster->cl_group.default_groups = defs;
+	cluster->cl_group.default_groups[0] = &ns->ns_group;
+	cluster->cl_group.default_groups[1] = r2hb_group;
+	cluster->cl_group.default_groups[2] = NULL;
+	rwlock_init(&cluster->cl_nodes_lock);
+	cluster->cl_node_ip_tree = RB_ROOT;
+	cluster->cl_reconnect_delay_ms = R2NET_RECONNECT_DELAY_MS_DEFAULT;
+	cluster->cl_idle_timeout_ms    = R2NET_IDLE_TIMEOUT_MS_DEFAULT;
+	cluster->cl_keepalive_delay_ms = R2NET_KEEPALIVE_DELAY_MS_DEFAULT;
+	cluster->cl_fence_method       = R2NM_FENCE_RESET;
+
+	ret = &cluster->cl_group;
+	r2nm_single_cluster = cluster;
+
+out:
+	if (ret == NULL) {
+		kfree(cluster);
+		kfree(ns);
+		r2hb_free_hb_set(r2hb_group);
+		kfree(defs);
+		ret = ERR_PTR(-ENOMEM);
+	}
+
+	return ret;
+}
+
+static void r2nm_cluster_group_drop_item(struct config_group *group,
+						struct config_item *item)
+{
+	struct r2nm_cluster *cluster = to_r2nm_cluster(item);
+	int i;
+	struct config_item *killme;
+
+	BUG_ON(r2nm_single_cluster != cluster);
+	r2nm_single_cluster = NULL;
+
+	for (i = 0; cluster->cl_group.default_groups[i]; i++) {
+		killme = &cluster->cl_group.default_groups[i]->cg_item;
+		cluster->cl_group.default_groups[i] = NULL;
+		config_item_put(killme);
+	}
+
+	config_item_put(item);
+}
+
+static struct configfs_group_operations r2nm_cluster_group_group_ops = {
+	.make_group	= r2nm_cluster_group_make_group,
+	.drop_item	= r2nm_cluster_group_drop_item,
+};
+
+static struct config_item_type r2nm_cluster_group_type = {
+	.ct_group_ops	= &r2nm_cluster_group_group_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct r2nm_cluster_group r2nm_cluster_group = {
+	.cs_subsys = {
+		.su_group = {
+			.cg_item = {
+				.ci_namebuf = "cluster",
+				.ci_type = &r2nm_cluster_group_type,
+			},
+		},
+	},
+};
+
+int r2nm_depend_item(struct config_item *item)
+{
+	return configfs_depend_item(&r2nm_cluster_group.cs_subsys, item);
+}
+
+void r2nm_undepend_item(struct config_item *item)
+{
+	configfs_undepend_item(&r2nm_cluster_group.cs_subsys, item);
+}
+
+int r2nm_depend_this_node(void)
+{
+	int ret = 0;
+	struct r2nm_node *local_node;
+
+	local_node = r2nm_get_node_by_num(r2nm_this_node());
+	if (!local_node) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = r2nm_depend_item(&local_node->nd_item);
+	r2nm_node_put(local_node);
+
+out:
+	return ret;
+}
+
+void r2nm_undepend_this_node(void)
+{
+	struct r2nm_node *local_node;
+
+	local_node = r2nm_get_node_by_num(r2nm_this_node());
+	BUG_ON(!local_node);
+
+	r2nm_undepend_item(&local_node->nd_item);
+	r2nm_node_put(local_node);
+}
+
+
+static void __exit exit_r2nm(void)
+{
+	/* XXX sync with hb callbacks and shut down hb? */
+	r2net_unregister_hb_callbacks();
+	configfs_unregister_subsystem(&r2nm_cluster_group.cs_subsys);
+
+	r2net_exit();
+	r2hb_exit();
+}
+
+static int __init init_r2nm(void)
+{
+	int ret = -1;
+
+	ret = r2hb_init();
+	if (ret)
+		goto out;
+
+	ret = r2net_init();
+	if (ret)
+		goto out_r2hb;
+
+	ret = r2net_register_hb_callbacks();
+	if (ret)
+		goto out_r2net;
+
+	config_group_init(&r2nm_cluster_group.cs_subsys.su_group);
+	mutex_init(&r2nm_cluster_group.cs_subsys.su_mutex);
+	ret = configfs_register_subsystem(&r2nm_cluster_group.cs_subsys);
+	if (ret) {
+		printk(KERN_ERR "nodemanager: Registration returned %d\n", ret);
+		goto out_callbacks;
+	}
+
+	if (!ret)
+		goto out;
+
+	configfs_unregister_subsystem(&r2nm_cluster_group.cs_subsys);
+out_callbacks:
+	r2net_unregister_hb_callbacks();
+out_r2net:
+	r2net_exit();
+out_r2hb:
+	r2hb_exit();
+out:
+	return ret;
+}
+
+MODULE_AUTHOR("Oracle");
+MODULE_LICENSE("GPL");
+
+module_init(init_r2nm)
+module_exit(exit_r2nm)
diff --git a/drivers/staging/ramster/cluster/nodemanager.h b/drivers/staging/ramster/cluster/nodemanager.h
new file mode 100644
index 0000000..41a04df
--- /dev/null
+++ b/drivers/staging/ramster/cluster/nodemanager.h
@@ -0,0 +1,88 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * nodemanager.h
+ *
+ * Function prototypes
+ *
+ * Copyright (C) 2004 Oracle.  All rights reserved.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ */
+
+#ifndef R2CLUSTER_NODEMANAGER_H
+#define R2CLUSTER_NODEMANAGER_H
+
+#include "ramster_nodemanager.h"
+
+/* This totally doesn't belong here. */
+#include <linux/configfs.h>
+#include <linux/rbtree.h>
+
+enum r2nm_fence_method {
+	R2NM_FENCE_RESET	= 0,
+	R2NM_FENCE_PANIC,
+	R2NM_FENCE_METHODS,	/* Number of fence methods */
+};
+
+struct r2nm_node {
+	spinlock_t		nd_lock;
+	struct config_item	nd_item;
+	char			nd_name[R2NM_MAX_NAME_LEN+1]; /* replace? */
+	__u8			nd_num;
+	/* only one address per node, as attributes, for now. */
+	__be32			nd_ipv4_address;
+	__be16			nd_ipv4_port;
+	struct rb_node		nd_ip_node;
+	/* there can be only one local node for now */
+	int			nd_local;
+
+	unsigned long		nd_set_attributes;
+};
+
+struct r2nm_cluster {
+	struct config_group	cl_group;
+	unsigned		cl_has_local:1;
+	u8			cl_local_node;
+	rwlock_t		cl_nodes_lock;
+	struct r2nm_node	*cl_nodes[R2NM_MAX_NODES];
+	struct rb_root		cl_node_ip_tree;
+	unsigned int		cl_idle_timeout_ms;
+	unsigned int		cl_keepalive_delay_ms;
+	unsigned int		cl_reconnect_delay_ms;
+	enum r2nm_fence_method	cl_fence_method;
+
+	/* part of a hack for disk bitmap.. will go eventually. - zab */
+	unsigned long	cl_nodes_bitmap[BITS_TO_LONGS(R2NM_MAX_NODES)];
+};
+
+extern struct r2nm_cluster *r2nm_single_cluster;
+
+u8 r2nm_this_node(void);
+
+int r2nm_configured_node_map(unsigned long *map, unsigned bytes);
+struct r2nm_node *r2nm_get_node_by_num(u8 node_num);
+struct r2nm_node *r2nm_get_node_by_ip(__be32 addr);
+void r2nm_node_get(struct r2nm_node *node);
+void r2nm_node_put(struct r2nm_node *node);
+
+int r2nm_depend_item(struct config_item *item);
+void r2nm_undepend_item(struct config_item *item);
+int r2nm_depend_this_node(void);
+void r2nm_undepend_this_node(void);
+
+#endif /* R2CLUSTER_NODEMANAGER_H */
diff --git a/drivers/staging/ramster/cluster/ramster_nodemanager.h b/drivers/staging/ramster/cluster/ramster_nodemanager.h
new file mode 100644
index 0000000..49f879d
--- /dev/null
+++ b/drivers/staging/ramster/cluster/ramster_nodemanager.h
@@ -0,0 +1,39 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * ramster_nodemanager.h
+ *
+ * Header describing the interface between userspace and the kernel
+ * for the ramster_nodemanager module.
+ *
+ * Copyright (C) 2002, 2004, 2012 Oracle.  All rights reserved.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ */
+
+#ifndef _RAMSTER_NODEMANAGER_H
+#define _RAMSTER_NODEMANAGER_H
+
+#define R2NM_API_VERSION	5
+
+#define R2NM_MAX_NODES		255
+#define R2NM_INVALID_NODE_NUM	255
+
+/* host name, group name, cluster name all 64 bytes */
+#define R2NM_MAX_NAME_LEN        64    /* __NEW_UTS_LEN */
+
+#endif /* _RAMSTER_NODEMANAGER_H */
diff --git a/drivers/staging/ramster/cluster/tcp.c b/drivers/staging/ramster/cluster/tcp.c
new file mode 100644
index 0000000..3af1b2c
--- /dev/null
+++ b/drivers/staging/ramster/cluster/tcp.c
@@ -0,0 +1,2256 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ *
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * Copyright (C) 2004 Oracle.  All rights reserved.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ * ----
+ *
+ * Callers for this were originally written against a very simple synchronus
+ * API.  This implementation reflects those simple callers.  Some day I'm sure
+ * we'll need to move to a more robust posting/callback mechanism.
+ *
+ * Transmit calls pass in kernel virtual addresses and block copying this into
+ * the socket's tx buffers via a usual blocking sendmsg.  They'll block waiting
+ * for a failed socket to timeout.  TX callers can also pass in a poniter to an
+ * 'int' which gets filled with an errno off the wire in response to the
+ * message they send.
+ *
+ * Handlers for unsolicited messages are registered.  Each socket has a page
+ * that incoming data is copied into.  First the header, then the data.
+ * Handlers are called from only one thread with a reference to this per-socket
+ * page.  This page is destroyed after the handler call, so it can't be
+ * referenced beyond the call.  Handlers may block but are discouraged from
+ * doing so.
+ *
+ * Any framing errors (bad magic, large payload lengths) close a connection.
+ *
+ * Our sock_container holds the state we associate with a socket.  It's current
+ * framing state is held there as well as the refcounting we do around when it
+ * is safe to tear down the socket.  The socket is only finally torn down from
+ * the container when the container loses all of its references -- so as long
+ * as you hold a ref on the container you can trust that the socket is valid
+ * for use with kernel socket APIs.
+ *
+ * Connections are initiated between a pair of nodes when the node with the
+ * higher node number gets a heartbeat callback which indicates that the lower
+ * numbered node has started heartbeating.  The lower numbered node is passive
+ * and only accepts the connection if the higher numbered node is heartbeating.
+ */
+
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include <linux/kref.h>
+#include <linux/net.h>
+#include <linux/export.h>
+#include <linux/uaccess.h>
+#include <net/tcp.h>
+
+
+#include "heartbeat.h"
+#include "tcp.h"
+#include "nodemanager.h"
+#define MLOG_MASK_PREFIX ML_TCP
+#include "masklog.h"
+
+#include "tcp_internal.h"
+
+#define SC_NODEF_FMT "node %s (num %u) at %pI4:%u"
+
+/*
+ * In the following two log macros, the whitespace after the ',' just
+ * before ##args is intentional. Otherwise, gcc 2.95 will eat the
+ * previous token if args expands to nothing.
+ */
+#define msglog(hdr, fmt, args...) do {					\
+	typeof(hdr) __hdr = (hdr);					\
+	mlog(ML_MSG, "[mag %u len %u typ %u stat %d sys_stat %d "	\
+	     "key %08x num %u] " fmt,					\
+	be16_to_cpu(__hdr->magic), be16_to_cpu(__hdr->data_len),	\
+	     be16_to_cpu(__hdr->msg_type), be32_to_cpu(__hdr->status),	\
+	     be32_to_cpu(__hdr->sys_status), be32_to_cpu(__hdr->key),	\
+	     be32_to_cpu(__hdr->msg_num) ,  ##args);			\
+} while (0)
+
+#define sclog(sc, fmt, args...) do {					\
+	typeof(sc) __sc = (sc);						\
+	mlog(ML_SOCKET, "[sc %p refs %d sock %p node %u page %p "	\
+	     "pg_off %zu] " fmt, __sc,					\
+	     atomic_read(&__sc->sc_kref.refcount), __sc->sc_sock,	\
+	    __sc->sc_node->nd_num, __sc->sc_page, __sc->sc_page_off ,	\
+	    ##args);							\
+} while (0)
+
+static DEFINE_RWLOCK(r2net_handler_lock);
+static struct rb_root r2net_handler_tree = RB_ROOT;
+
+static struct r2net_node r2net_nodes[R2NM_MAX_NODES];
+
+/* XXX someday we'll need better accounting */
+static struct socket *r2net_listen_sock;
+
+/*
+ * listen work is only queued by the listening socket callbacks on the
+ * r2net_wq.  teardown detaches the callbacks before destroying the workqueue.
+ * quorum work is queued as sock containers are shutdown.. stop_listening
+ * tears down all the node's sock containers, preventing future shutdowns
+ * and queued quroum work, before canceling delayed quorum work and
+ * destroying the work queue.
+ */
+static struct workqueue_struct *r2net_wq;
+static struct work_struct r2net_listen_work;
+
+static struct r2hb_callback_func r2net_hb_up, r2net_hb_down;
+#define R2NET_HB_PRI 0x1
+
+static struct r2net_handshake *r2net_hand;
+static struct r2net_msg *r2net_keep_req, *r2net_keep_resp;
+
+static int r2net_sys_err_translations[R2NET_ERR_MAX] = {
+		[R2NET_ERR_NONE]	= 0,
+		[R2NET_ERR_NO_HNDLR]	= -ENOPROTOOPT,
+		[R2NET_ERR_OVERFLOW]	= -EOVERFLOW,
+		[R2NET_ERR_DIED]	= -EHOSTDOWN,};
+
+/* can't quite avoid *all* internal declarations :/ */
+static void r2net_sc_connect_completed(struct work_struct *work);
+static void r2net_rx_until_empty(struct work_struct *work);
+static void r2net_shutdown_sc(struct work_struct *work);
+static void r2net_listen_data_ready(struct sock *sk, int bytes);
+static void r2net_sc_send_keep_req(struct work_struct *work);
+static void r2net_idle_timer(unsigned long data);
+static void r2net_sc_postpone_idle(struct r2net_sock_container *sc);
+static void r2net_sc_reset_idle_timer(struct r2net_sock_container *sc);
+
+#ifdef CONFIG_DEBUG_FS
+static void r2net_init_nst(struct r2net_send_tracking *nst, u32 msgtype,
+			   u32 msgkey, struct task_struct *task, u8 node)
+{
+	INIT_LIST_HEAD(&nst->st_net_debug_item);
+	nst->st_task = task;
+	nst->st_msg_type = msgtype;
+	nst->st_msg_key = msgkey;
+	nst->st_node = node;
+}
+
+static inline void r2net_set_nst_sock_time(struct r2net_send_tracking *nst)
+{
+	nst->st_sock_time = ktime_get();
+}
+
+static inline void r2net_set_nst_send_time(struct r2net_send_tracking *nst)
+{
+	nst->st_send_time = ktime_get();
+}
+
+static inline void r2net_set_nst_status_time(struct r2net_send_tracking *nst)
+{
+	nst->st_status_time = ktime_get();
+}
+
+static inline void r2net_set_nst_sock_container(struct r2net_send_tracking *nst,
+						struct r2net_sock_container *sc)
+{
+	nst->st_sc = sc;
+}
+
+static inline void r2net_set_nst_msg_id(struct r2net_send_tracking *nst,
+					u32 msg_id)
+{
+	nst->st_id = msg_id;
+}
+
+static inline void r2net_set_sock_timer(struct r2net_sock_container *sc)
+{
+	sc->sc_tv_timer = ktime_get();
+}
+
+static inline void r2net_set_data_ready_time(struct r2net_sock_container *sc)
+{
+	sc->sc_tv_data_ready = ktime_get();
+}
+
+static inline void r2net_set_advance_start_time(struct r2net_sock_container *sc)
+{
+	sc->sc_tv_advance_start = ktime_get();
+}
+
+static inline void r2net_set_advance_stop_time(struct r2net_sock_container *sc)
+{
+	sc->sc_tv_advance_stop = ktime_get();
+}
+
+static inline void r2net_set_func_start_time(struct r2net_sock_container *sc)
+{
+	sc->sc_tv_func_start = ktime_get();
+}
+
+static inline void r2net_set_func_stop_time(struct r2net_sock_container *sc)
+{
+	sc->sc_tv_func_stop = ktime_get();
+}
+
+#else  /* CONFIG_DEBUG_FS */
+# define r2net_init_nst(a, b, c, d, e)
+# define r2net_set_nst_sock_time(a)
+# define r2net_set_nst_send_time(a)
+# define r2net_set_nst_status_time(a)
+# define r2net_set_nst_sock_container(a, b)
+# define r2net_set_nst_msg_id(a, b)
+# define r2net_set_sock_timer(a)
+# define r2net_set_data_ready_time(a)
+# define r2net_set_advance_start_time(a)
+# define r2net_set_advance_stop_time(a)
+# define r2net_set_func_start_time(a)
+# define r2net_set_func_stop_time(a)
+#endif /* CONFIG_DEBUG_FS */
+
+#ifdef CONFIG_RAMSTER_FS_STATS
+static ktime_t r2net_get_func_run_time(struct r2net_sock_container *sc)
+{
+	return ktime_sub(sc->sc_tv_func_stop, sc->sc_tv_func_start);
+}
+
+static void r2net_update_send_stats(struct r2net_send_tracking *nst,
+				    struct r2net_sock_container *sc)
+{
+	sc->sc_tv_status_total = ktime_add(sc->sc_tv_status_total,
+					   ktime_sub(ktime_get(),
+						     nst->st_status_time));
+	sc->sc_tv_send_total = ktime_add(sc->sc_tv_send_total,
+					 ktime_sub(nst->st_status_time,
+						   nst->st_send_time));
+	sc->sc_tv_acquiry_total = ktime_add(sc->sc_tv_acquiry_total,
+					    ktime_sub(nst->st_send_time,
+						      nst->st_sock_time));
+	sc->sc_send_count++;
+}
+
+static void r2net_update_recv_stats(struct r2net_sock_container *sc)
+{
+	sc->sc_tv_process_total = ktime_add(sc->sc_tv_process_total,
+					    r2net_get_func_run_time(sc));
+	sc->sc_recv_count++;
+}
+
+#else
+
+# define r2net_update_send_stats(a, b)
+
+# define r2net_update_recv_stats(sc)
+
+#endif /* CONFIG_RAMSTER_FS_STATS */
+
+static inline int r2net_reconnect_delay(void)
+{
+	return r2nm_single_cluster->cl_reconnect_delay_ms;
+}
+
+static inline int r2net_keepalive_delay(void)
+{
+	return r2nm_single_cluster->cl_keepalive_delay_ms;
+}
+
+static inline int r2net_idle_timeout(void)
+{
+	return r2nm_single_cluster->cl_idle_timeout_ms;
+}
+
+static inline int r2net_sys_err_to_errno(enum r2net_system_error err)
+{
+	int trans;
+	BUG_ON(err >= R2NET_ERR_MAX);
+	trans = r2net_sys_err_translations[err];
+
+	/* Just in case we mess up the translation table above */
+	BUG_ON(err != R2NET_ERR_NONE && trans == 0);
+	return trans;
+}
+
+struct r2net_node *r2net_nn_from_num(u8 node_num)
+{
+	BUG_ON(node_num >= ARRAY_SIZE(r2net_nodes));
+	return &r2net_nodes[node_num];
+}
+
+static u8 r2net_num_from_nn(struct r2net_node *nn)
+{
+	BUG_ON(nn == NULL);
+	return nn - r2net_nodes;
+}
+
+/* ------------------------------------------------------------ */
+
+static int r2net_prep_nsw(struct r2net_node *nn, struct r2net_status_wait *nsw)
+{
+	int ret = 0;
+
+	do {
+		if (!idr_pre_get(&nn->nn_status_idr, GFP_ATOMIC)) {
+			ret = -EAGAIN;
+			break;
+		}
+		spin_lock(&nn->nn_lock);
+		ret = idr_get_new(&nn->nn_status_idr, nsw, &nsw->ns_id);
+		if (ret == 0)
+			list_add_tail(&nsw->ns_node_item,
+				      &nn->nn_status_list);
+		spin_unlock(&nn->nn_lock);
+	} while (ret == -EAGAIN);
+
+	if (ret == 0)  {
+		init_waitqueue_head(&nsw->ns_wq);
+		nsw->ns_sys_status = R2NET_ERR_NONE;
+		nsw->ns_status = 0;
+	}
+
+	return ret;
+}
+
+static void r2net_complete_nsw_locked(struct r2net_node *nn,
+				      struct r2net_status_wait *nsw,
+				      enum r2net_system_error sys_status,
+				      s32 status)
+{
+	assert_spin_locked(&nn->nn_lock);
+
+	if (!list_empty(&nsw->ns_node_item)) {
+		list_del_init(&nsw->ns_node_item);
+		nsw->ns_sys_status = sys_status;
+		nsw->ns_status = status;
+		idr_remove(&nn->nn_status_idr, nsw->ns_id);
+		wake_up(&nsw->ns_wq);
+	}
+}
+
+static void r2net_complete_nsw(struct r2net_node *nn,
+			       struct r2net_status_wait *nsw,
+			       u64 id, enum r2net_system_error sys_status,
+			       s32 status)
+{
+	spin_lock(&nn->nn_lock);
+	if (nsw == NULL) {
+		if (id > INT_MAX)
+			goto out;
+
+		nsw = idr_find(&nn->nn_status_idr, id);
+		if (nsw == NULL)
+			goto out;
+	}
+
+	r2net_complete_nsw_locked(nn, nsw, sys_status, status);
+
+out:
+	spin_unlock(&nn->nn_lock);
+	return;
+}
+
+static void r2net_complete_nodes_nsw(struct r2net_node *nn)
+{
+	struct r2net_status_wait *nsw, *tmp;
+	unsigned int num_kills = 0;
+
+	assert_spin_locked(&nn->nn_lock);
+
+	list_for_each_entry_safe(nsw, tmp, &nn->nn_status_list, ns_node_item) {
+		r2net_complete_nsw_locked(nn, nsw, R2NET_ERR_DIED, 0);
+		num_kills++;
+	}
+
+	mlog(0, "completed %d messages for node %u\n", num_kills,
+	     r2net_num_from_nn(nn));
+}
+
+static int r2net_nsw_completed(struct r2net_node *nn,
+			       struct r2net_status_wait *nsw)
+{
+	int completed;
+	spin_lock(&nn->nn_lock);
+	completed = list_empty(&nsw->ns_node_item);
+	spin_unlock(&nn->nn_lock);
+	return completed;
+}
+
+/* ------------------------------------------------------------ */
+
+static void sc_kref_release(struct kref *kref)
+{
+	struct r2net_sock_container *sc = container_of(kref,
+					struct r2net_sock_container, sc_kref);
+	BUG_ON(timer_pending(&sc->sc_idle_timeout));
+
+	sclog(sc, "releasing\n");
+
+	if (sc->sc_sock) {
+		sock_release(sc->sc_sock);
+		sc->sc_sock = NULL;
+	}
+
+	r2nm_undepend_item(&sc->sc_node->nd_item);
+	r2nm_node_put(sc->sc_node);
+	sc->sc_node = NULL;
+
+	r2net_debug_del_sc(sc);
+	kfree(sc);
+}
+
+static void sc_put(struct r2net_sock_container *sc)
+{
+	sclog(sc, "put\n");
+	kref_put(&sc->sc_kref, sc_kref_release);
+}
+static void sc_get(struct r2net_sock_container *sc)
+{
+	sclog(sc, "get\n");
+	kref_get(&sc->sc_kref);
+}
+static struct r2net_sock_container *sc_alloc(struct r2nm_node *node)
+{
+	struct r2net_sock_container *sc, *ret = NULL;
+	struct page *page = NULL;
+	int status = 0;
+
+	page = alloc_page(GFP_NOFS);
+	sc = kzalloc(sizeof(*sc), GFP_NOFS);
+	if (sc == NULL || page == NULL)
+		goto out;
+
+	kref_init(&sc->sc_kref);
+	r2nm_node_get(node);
+	sc->sc_node = node;
+
+	/* pin the node item of the remote node */
+	status = r2nm_depend_item(&node->nd_item);
+	if (status) {
+		mlog_errno(status);
+		r2nm_node_put(node);
+		goto out;
+	}
+	INIT_WORK(&sc->sc_connect_work, r2net_sc_connect_completed);
+	INIT_WORK(&sc->sc_rx_work, r2net_rx_until_empty);
+	INIT_WORK(&sc->sc_shutdown_work, r2net_shutdown_sc);
+	INIT_DELAYED_WORK(&sc->sc_keepalive_work, r2net_sc_send_keep_req);
+
+	init_timer(&sc->sc_idle_timeout);
+	sc->sc_idle_timeout.function = r2net_idle_timer;
+	sc->sc_idle_timeout.data = (unsigned long)sc;
+
+	sclog(sc, "alloced\n");
+
+	ret = sc;
+	sc->sc_page = page;
+	r2net_debug_add_sc(sc);
+	sc = NULL;
+	page = NULL;
+
+out:
+	if (page)
+		__free_page(page);
+	kfree(sc);
+
+	return ret;
+}
+
+/* ------------------------------------------------------------ */
+
+static void r2net_sc_queue_work(struct r2net_sock_container *sc,
+				struct work_struct *work)
+{
+	sc_get(sc);
+	if (!queue_work(r2net_wq, work))
+		sc_put(sc);
+}
+static void r2net_sc_queue_delayed_work(struct r2net_sock_container *sc,
+					struct delayed_work *work,
+					int delay)
+{
+	sc_get(sc);
+	if (!queue_delayed_work(r2net_wq, work, delay))
+		sc_put(sc);
+}
+static void r2net_sc_cancel_delayed_work(struct r2net_sock_container *sc,
+					 struct delayed_work *work)
+{
+	if (cancel_delayed_work(work))
+		sc_put(sc);
+}
+
+static atomic_t r2net_connected_peers = ATOMIC_INIT(0);
+
+int r2net_num_connected_peers(void)
+{
+	return atomic_read(&r2net_connected_peers);
+}
+
+static void r2net_set_nn_state(struct r2net_node *nn,
+			       struct r2net_sock_container *sc,
+			       unsigned valid, int err)
+{
+	int was_valid = nn->nn_sc_valid;
+	int was_err = nn->nn_persistent_error;
+	struct r2net_sock_container *old_sc = nn->nn_sc;
+
+	assert_spin_locked(&nn->nn_lock);
+
+	if (old_sc && !sc)
+		atomic_dec(&r2net_connected_peers);
+	else if (!old_sc && sc)
+		atomic_inc(&r2net_connected_peers);
+
+	/* the node num comparison and single connect/accept path should stop
+	 * an non-null sc from being overwritten with another */
+	BUG_ON(sc && nn->nn_sc && nn->nn_sc != sc);
+	mlog_bug_on_msg(err && valid, "err %d valid %u\n", err, valid);
+	mlog_bug_on_msg(valid && !sc, "valid %u sc %p\n", valid, sc);
+
+	if (was_valid && !valid && err == 0)
+		err = -ENOTCONN;
+
+	mlog(ML_CONN, "node %u sc: %p -> %p, valid %u -> %u, err %d -> %d\n",
+	     r2net_num_from_nn(nn), nn->nn_sc, sc, nn->nn_sc_valid, valid,
+	     nn->nn_persistent_error, err);
+
+	nn->nn_sc = sc;
+	nn->nn_sc_valid = valid ? 1 : 0;
+	nn->nn_persistent_error = err;
+
+	/* mirrors r2net_tx_can_proceed() */
+	if (nn->nn_persistent_error || nn->nn_sc_valid)
+		wake_up(&nn->nn_sc_wq);
+
+	if (!was_err && nn->nn_persistent_error) {
+		queue_delayed_work(r2net_wq, &nn->nn_still_up,
+				   msecs_to_jiffies(R2NET_QUORUM_DELAY_MS));
+	}
+
+	if (was_valid && !valid) {
+		printk(KERN_NOTICE "ramster: No longer connected to "
+		       SC_NODEF_FMT "\n",
+			old_sc->sc_node->nd_name, old_sc->sc_node->nd_num,
+			&old_sc->sc_node->nd_ipv4_address,
+			ntohs(old_sc->sc_node->nd_ipv4_port));
+		r2net_complete_nodes_nsw(nn);
+	}
+
+	if (!was_valid && valid) {
+		cancel_delayed_work(&nn->nn_connect_expired);
+		printk(KERN_NOTICE "ramster: %s " SC_NODEF_FMT "\n",
+		       r2nm_this_node() > sc->sc_node->nd_num ?
+		       "Connected to" : "Accepted connection from",
+		       sc->sc_node->nd_name, sc->sc_node->nd_num,
+			&sc->sc_node->nd_ipv4_address,
+			ntohs(sc->sc_node->nd_ipv4_port));
+	}
+
+	/* trigger the connecting worker func as long as we're not valid,
+	 * it will back off if it shouldn't connect.  This can be called
+	 * from node config teardown and so needs to be careful about
+	 * the work queue actually being up. */
+	if (!valid && r2net_wq) {
+		unsigned long delay;
+		/* delay if we're within a RECONNECT_DELAY of the
+		 * last attempt */
+		delay = (nn->nn_last_connect_attempt +
+			 msecs_to_jiffies(r2net_reconnect_delay()))
+			- jiffies;
+		if (delay > msecs_to_jiffies(r2net_reconnect_delay()))
+			delay = 0;
+		mlog(ML_CONN, "queueing conn attempt in %lu jiffies\n", delay);
+		queue_delayed_work(r2net_wq, &nn->nn_connect_work, delay);
+
+		/*
+		 * Delay the expired work after idle timeout.
+		 *
+		 * We might have lots of failed connection attempts that run
+		 * through here but we only cancel the connect_expired work when
+		 * a connection attempt succeeds.  So only the first enqueue of
+		 * the connect_expired work will do anything.  The rest will see
+		 * that it's already queued and do nothing.
+		 */
+		delay += msecs_to_jiffies(r2net_idle_timeout());
+		queue_delayed_work(r2net_wq, &nn->nn_connect_expired, delay);
+	}
+
+	/* keep track of the nn's sc ref for the caller */
+	if ((old_sc == NULL) && sc)
+		sc_get(sc);
+	if (old_sc && (old_sc != sc)) {
+		r2net_sc_queue_work(old_sc, &old_sc->sc_shutdown_work);
+		sc_put(old_sc);
+	}
+}
+
+/* see r2net_register_callbacks() */
+static void r2net_data_ready(struct sock *sk, int bytes)
+{
+	void (*ready)(struct sock *sk, int bytes);
+
+	read_lock(&sk->sk_callback_lock);
+	if (sk->sk_user_data) {
+		struct r2net_sock_container *sc = sk->sk_user_data;
+		sclog(sc, "data_ready hit\n");
+		r2net_set_data_ready_time(sc);
+		r2net_sc_queue_work(sc, &sc->sc_rx_work);
+		ready = sc->sc_data_ready;
+	} else {
+		ready = sk->sk_data_ready;
+	}
+	read_unlock(&sk->sk_callback_lock);
+
+	ready(sk, bytes);
+}
+
+/* see r2net_register_callbacks() */
+static void r2net_state_change(struct sock *sk)
+{
+	void (*state_change)(struct sock *sk);
+	struct r2net_sock_container *sc;
+
+	read_lock(&sk->sk_callback_lock);
+	sc = sk->sk_user_data;
+	if (sc == NULL) {
+		state_change = sk->sk_state_change;
+		goto out;
+	}
+
+	sclog(sc, "state_change to %d\n", sk->sk_state);
+
+	state_change = sc->sc_state_change;
+
+	switch (sk->sk_state) {
+
+	/* ignore connecting sockets as they make progress */
+	case TCP_SYN_SENT:
+	case TCP_SYN_RECV:
+		break;
+	case TCP_ESTABLISHED:
+		r2net_sc_queue_work(sc, &sc->sc_connect_work);
+		break;
+	default:
+		printk(KERN_INFO "ramster: Connection to "
+			SC_NODEF_FMT " shutdown, state %d\n",
+			sc->sc_node->nd_name, sc->sc_node->nd_num,
+			&sc->sc_node->nd_ipv4_address,
+			ntohs(sc->sc_node->nd_ipv4_port), sk->sk_state);
+		r2net_sc_queue_work(sc, &sc->sc_shutdown_work);
+		break;
+
+	}
+out:
+	read_unlock(&sk->sk_callback_lock);
+	state_change(sk);
+}
+
+/*
+ * we register callbacks so we can queue work on events before calling
+ * the original callbacks.  our callbacks our careful to test user_data
+ * to discover when they've reaced with r2net_unregister_callbacks().
+ */
+static void r2net_register_callbacks(struct sock *sk,
+				     struct r2net_sock_container *sc)
+{
+	write_lock_bh(&sk->sk_callback_lock);
+
+	/* accepted sockets inherit the old listen socket data ready */
+	if (sk->sk_data_ready == r2net_listen_data_ready) {
+		sk->sk_data_ready = sk->sk_user_data;
+		sk->sk_user_data = NULL;
+	}
+
+	BUG_ON(sk->sk_user_data != NULL);
+	sk->sk_user_data = sc;
+	sc_get(sc);
+
+	sc->sc_data_ready = sk->sk_data_ready;
+	sc->sc_state_change = sk->sk_state_change;
+	sk->sk_data_ready = r2net_data_ready;
+	sk->sk_state_change = r2net_state_change;
+
+	mutex_init(&sc->sc_send_lock);
+
+	write_unlock_bh(&sk->sk_callback_lock);
+}
+
+static int r2net_unregister_callbacks(struct sock *sk,
+					struct r2net_sock_container *sc)
+{
+	int ret = 0;
+
+	write_lock_bh(&sk->sk_callback_lock);
+	if (sk->sk_user_data == sc) {
+		ret = 1;
+		sk->sk_user_data = NULL;
+		sk->sk_data_ready = sc->sc_data_ready;
+		sk->sk_state_change = sc->sc_state_change;
+	}
+	write_unlock_bh(&sk->sk_callback_lock);
+
+	return ret;
+}
+
+/*
+ * this is a little helper that is called by callers who have seen a problem
+ * with an sc and want to detach it from the nn if someone already hasn't beat
+ * them to it.  if an error is given then the shutdown will be persistent
+ * and pending transmits will be canceled.
+ */
+static void r2net_ensure_shutdown(struct r2net_node *nn,
+					struct r2net_sock_container *sc,
+				   int err)
+{
+	spin_lock(&nn->nn_lock);
+	if (nn->nn_sc == sc)
+		r2net_set_nn_state(nn, NULL, 0, err);
+	spin_unlock(&nn->nn_lock);
+}
+
+/*
+ * This work queue function performs the blocking parts of socket shutdown.  A
+ * few paths lead here.  set_nn_state will trigger this callback if it sees an
+ * sc detached from the nn.  state_change will also trigger this callback
+ * directly when it sees errors.  In that case we need to call set_nn_state
+ * ourselves as state_change couldn't get the nn_lock and call set_nn_state
+ * itself.
+ */
+static void r2net_shutdown_sc(struct work_struct *work)
+{
+	struct r2net_sock_container *sc =
+		container_of(work, struct r2net_sock_container,
+			     sc_shutdown_work);
+	struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
+
+	sclog(sc, "shutting down\n");
+
+	/* drop the callbacks ref and call shutdown only once */
+	if (r2net_unregister_callbacks(sc->sc_sock->sk, sc)) {
+		/* we shouldn't flush as we're in the thread, the
+		 * races with pending sc work structs are harmless */
+		del_timer_sync(&sc->sc_idle_timeout);
+		r2net_sc_cancel_delayed_work(sc, &sc->sc_keepalive_work);
+		sc_put(sc);
+		kernel_sock_shutdown(sc->sc_sock, SHUT_RDWR);
+	}
+
+	/* not fatal so failed connects before the other guy has our
+	 * heartbeat can be retried */
+	r2net_ensure_shutdown(nn, sc, 0);
+	sc_put(sc);
+}
+
+/* ------------------------------------------------------------ */
+
+static int r2net_handler_cmp(struct r2net_msg_handler *nmh, u32 msg_type,
+			     u32 key)
+{
+	int ret = memcmp(&nmh->nh_key, &key, sizeof(key));
+
+	if (ret == 0)
+		ret = memcmp(&nmh->nh_msg_type, &msg_type, sizeof(msg_type));
+
+	return ret;
+}
+
+static struct r2net_msg_handler *
+r2net_handler_tree_lookup(u32 msg_type, u32 key, struct rb_node ***ret_p,
+				struct rb_node **ret_parent)
+{
+	struct rb_node **p = &r2net_handler_tree.rb_node;
+	struct rb_node *parent = NULL;
+	struct r2net_msg_handler *nmh, *ret = NULL;
+	int cmp;
+
+	while (*p) {
+		parent = *p;
+		nmh = rb_entry(parent, struct r2net_msg_handler, nh_node);
+		cmp = r2net_handler_cmp(nmh, msg_type, key);
+
+		if (cmp < 0)
+			p = &(*p)->rb_left;
+		else if (cmp > 0)
+			p = &(*p)->rb_right;
+		else {
+			ret = nmh;
+			break;
+		}
+	}
+
+	if (ret_p != NULL)
+		*ret_p = p;
+	if (ret_parent != NULL)
+		*ret_parent = parent;
+
+	return ret;
+}
+
+static void r2net_handler_kref_release(struct kref *kref)
+{
+	struct r2net_msg_handler *nmh;
+	nmh = container_of(kref, struct r2net_msg_handler, nh_kref);
+
+	kfree(nmh);
+}
+
+static void r2net_handler_put(struct r2net_msg_handler *nmh)
+{
+	kref_put(&nmh->nh_kref, r2net_handler_kref_release);
+}
+
+/* max_len is protection for the handler func.  incoming messages won't
+ * be given to the handler if their payload is longer than the max. */
+int r2net_register_handler(u32 msg_type, u32 key, u32 max_len,
+			   r2net_msg_handler_func *func, void *data,
+			   r2net_post_msg_handler_func *post_func,
+			   struct list_head *unreg_list)
+{
+	struct r2net_msg_handler *nmh = NULL;
+	struct rb_node **p, *parent;
+	int ret = 0;
+
+	if (max_len > R2NET_MAX_PAYLOAD_BYTES) {
+		mlog(0, "max_len for message handler out of range: %u\n",
+			max_len);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (!msg_type) {
+		mlog(0, "no message type provided: %u, %p\n", msg_type, func);
+		ret = -EINVAL;
+		goto out;
+
+	}
+	if (!func) {
+		mlog(0, "no message handler provided: %u, %p\n",
+		       msg_type, func);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	nmh = kzalloc(sizeof(struct r2net_msg_handler), GFP_NOFS);
+	if (nmh == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	nmh->nh_func = func;
+	nmh->nh_func_data = data;
+	nmh->nh_post_func = post_func;
+	nmh->nh_msg_type = msg_type;
+	nmh->nh_max_len = max_len;
+	nmh->nh_key = key;
+	/* the tree and list get this ref.. they're both removed in
+	 * unregister when this ref is dropped */
+	kref_init(&nmh->nh_kref);
+	INIT_LIST_HEAD(&nmh->nh_unregister_item);
+
+	write_lock(&r2net_handler_lock);
+	if (r2net_handler_tree_lookup(msg_type, key, &p, &parent))
+		ret = -EEXIST;
+	else {
+		rb_link_node(&nmh->nh_node, parent, p);
+		rb_insert_color(&nmh->nh_node, &r2net_handler_tree);
+		list_add_tail(&nmh->nh_unregister_item, unreg_list);
+
+		mlog(ML_TCP, "registered handler func %p type %u key %08x\n",
+		     func, msg_type, key);
+		/* we've had some trouble with handlers seemingly vanishing. */
+		mlog_bug_on_msg(r2net_handler_tree_lookup(msg_type, key, &p,
+							  &parent) == NULL,
+				"couldn't find handler we *just* registered "
+				"for type %u key %08x\n", msg_type, key);
+	}
+	write_unlock(&r2net_handler_lock);
+	if (ret)
+		goto out;
+
+out:
+	if (ret)
+		kfree(nmh);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(r2net_register_handler);
+
+void r2net_unregister_handler_list(struct list_head *list)
+{
+	struct r2net_msg_handler *nmh, *n;
+
+	write_lock(&r2net_handler_lock);
+	list_for_each_entry_safe(nmh, n, list, nh_unregister_item) {
+		mlog(ML_TCP, "unregistering handler func %p type %u key %08x\n",
+		     nmh->nh_func, nmh->nh_msg_type, nmh->nh_key);
+		rb_erase(&nmh->nh_node, &r2net_handler_tree);
+		list_del_init(&nmh->nh_unregister_item);
+		kref_put(&nmh->nh_kref, r2net_handler_kref_release);
+	}
+	write_unlock(&r2net_handler_lock);
+}
+EXPORT_SYMBOL_GPL(r2net_unregister_handler_list);
+
+static struct r2net_msg_handler *r2net_handler_get(u32 msg_type, u32 key)
+{
+	struct r2net_msg_handler *nmh;
+
+	read_lock(&r2net_handler_lock);
+	nmh = r2net_handler_tree_lookup(msg_type, key, NULL, NULL);
+	if (nmh)
+		kref_get(&nmh->nh_kref);
+	read_unlock(&r2net_handler_lock);
+
+	return nmh;
+}
+
+/* ------------------------------------------------------------ */
+
+static int r2net_recv_tcp_msg(struct socket *sock, void *data, size_t len)
+{
+	int ret;
+	mm_segment_t oldfs;
+	struct kvec vec = {
+		.iov_len = len,
+		.iov_base = data,
+	};
+	struct msghdr msg = {
+		.msg_iovlen = 1,
+		.msg_iov = (struct iovec *)&vec,
+		.msg_flags = MSG_DONTWAIT,
+	};
+
+	oldfs = get_fs();
+	set_fs(get_ds());
+	ret = sock_recvmsg(sock, &msg, len, msg.msg_flags);
+	set_fs(oldfs);
+
+	return ret;
+}
+
+static int r2net_send_tcp_msg(struct socket *sock, struct kvec *vec,
+			      size_t veclen, size_t total)
+{
+	int ret;
+	mm_segment_t oldfs;
+	struct msghdr msg = {
+		.msg_iov = (struct iovec *)vec,
+		.msg_iovlen = veclen,
+	};
+
+	if (sock == NULL) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	oldfs = get_fs();
+	set_fs(get_ds());
+	ret = sock_sendmsg(sock, &msg, total);
+	set_fs(oldfs);
+	if (ret != total) {
+		mlog(ML_ERROR, "sendmsg returned %d instead of %zu\n", ret,
+		     total);
+		if (ret >= 0)
+			ret = -EPIPE; /* should be smarter, I bet */
+		goto out;
+	}
+
+	ret = 0;
+out:
+	if (ret < 0)
+		mlog(0, "returning error: %d\n", ret);
+	return ret;
+}
+
+static void r2net_sendpage(struct r2net_sock_container *sc,
+			   void *kmalloced_virt,
+			   size_t size)
+{
+	struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
+	ssize_t ret;
+
+	while (1) {
+		mutex_lock(&sc->sc_send_lock);
+		ret = sc->sc_sock->ops->sendpage(sc->sc_sock,
+					virt_to_page(kmalloced_virt),
+					(long)kmalloced_virt & ~PAGE_MASK,
+					size, MSG_DONTWAIT);
+		mutex_unlock(&sc->sc_send_lock);
+		if (ret == size)
+			break;
+		if (ret == (ssize_t)-EAGAIN) {
+			mlog(0, "sendpage of size %zu to " SC_NODEF_FMT
+			     " returned EAGAIN\n", size, sc->sc_node->nd_name,
+				sc->sc_node->nd_num,
+				&sc->sc_node->nd_ipv4_address,
+				ntohs(sc->sc_node->nd_ipv4_port));
+			cond_resched();
+			continue;
+		}
+		mlog(ML_ERROR, "sendpage of size %zu to " SC_NODEF_FMT
+		     " failed with %zd\n", size, sc->sc_node->nd_name,
+			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
+			ntohs(sc->sc_node->nd_ipv4_port), ret);
+		r2net_ensure_shutdown(nn, sc, 0);
+		break;
+	}
+}
+
+static void r2net_init_msg(struct r2net_msg *msg, u16 data_len,
+				u16 msg_type, u32 key)
+{
+	memset(msg, 0, sizeof(struct r2net_msg));
+	msg->magic = cpu_to_be16(R2NET_MSG_MAGIC);
+	msg->data_len = cpu_to_be16(data_len);
+	msg->msg_type = cpu_to_be16(msg_type);
+	msg->sys_status = cpu_to_be32(R2NET_ERR_NONE);
+	msg->status = 0;
+	msg->key = cpu_to_be32(key);
+}
+
+static int r2net_tx_can_proceed(struct r2net_node *nn,
+				struct r2net_sock_container **sc_ret,
+				int *error)
+{
+	int ret = 0;
+
+	spin_lock(&nn->nn_lock);
+	if (nn->nn_persistent_error) {
+		ret = 1;
+		*sc_ret = NULL;
+		*error = nn->nn_persistent_error;
+	} else if (nn->nn_sc_valid) {
+		kref_get(&nn->nn_sc->sc_kref);
+
+		ret = 1;
+		*sc_ret = nn->nn_sc;
+		*error = 0;
+	}
+	spin_unlock(&nn->nn_lock);
+
+	return ret;
+}
+
+/* Get a map of all nodes to which this node is currently connected to */
+void r2net_fill_node_map(unsigned long *map, unsigned bytes)
+{
+	struct r2net_sock_container *sc;
+	int node, ret;
+
+	BUG_ON(bytes < (BITS_TO_LONGS(R2NM_MAX_NODES) * sizeof(unsigned long)));
+
+	memset(map, 0, bytes);
+	for (node = 0; node < R2NM_MAX_NODES; ++node) {
+		r2net_tx_can_proceed(r2net_nn_from_num(node), &sc, &ret);
+		if (!ret) {
+			set_bit(node, map);
+			sc_put(sc);
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(r2net_fill_node_map);
+
+int r2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec,
+			   size_t caller_veclen, u8 target_node, int *status)
+{
+	int ret = 0;
+	struct r2net_msg *msg = NULL;
+	size_t veclen, caller_bytes = 0;
+	struct kvec *vec = NULL;
+	struct r2net_sock_container *sc = NULL;
+	struct r2net_node *nn = r2net_nn_from_num(target_node);
+	struct r2net_status_wait nsw = {
+		.ns_node_item = LIST_HEAD_INIT(nsw.ns_node_item),
+	};
+	struct r2net_send_tracking nst;
+
+	/* this may be a general bug fix */
+	init_waitqueue_head(&nsw.ns_wq);
+
+	r2net_init_nst(&nst, msg_type, key, current, target_node);
+
+	if (r2net_wq == NULL) {
+		mlog(0, "attempt to tx without r2netd running\n");
+		ret = -ESRCH;
+		goto out;
+	}
+
+	if (caller_veclen == 0) {
+		mlog(0, "bad kvec array length\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	caller_bytes = iov_length((struct iovec *)caller_vec, caller_veclen);
+	if (caller_bytes > R2NET_MAX_PAYLOAD_BYTES) {
+		mlog(0, "total payload len %zu too large\n", caller_bytes);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (target_node == r2nm_this_node()) {
+		ret = -ELOOP;
+		goto out;
+	}
+
+	r2net_debug_add_nst(&nst);
+
+	r2net_set_nst_sock_time(&nst);
+
+	wait_event(nn->nn_sc_wq, r2net_tx_can_proceed(nn, &sc, &ret));
+	if (ret)
+		goto out;
+
+	r2net_set_nst_sock_container(&nst, sc);
+
+	veclen = caller_veclen + 1;
+	vec = kmalloc(sizeof(struct kvec) * veclen, GFP_ATOMIC);
+	if (vec == NULL) {
+		mlog(0, "failed to %zu element kvec!\n", veclen);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	msg = kmalloc(sizeof(struct r2net_msg), GFP_ATOMIC);
+	if (!msg) {
+		mlog(0, "failed to allocate a r2net_msg!\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	r2net_init_msg(msg, caller_bytes, msg_type, key);
+
+	vec[0].iov_len = sizeof(struct r2net_msg);
+	vec[0].iov_base = msg;
+	memcpy(&vec[1], caller_vec, caller_veclen * sizeof(struct kvec));
+
+	ret = r2net_prep_nsw(nn, &nsw);
+	if (ret)
+		goto out;
+
+	msg->msg_num = cpu_to_be32(nsw.ns_id);
+	r2net_set_nst_msg_id(&nst, nsw.ns_id);
+
+	r2net_set_nst_send_time(&nst);
+
+	/* finally, convert the message header to network byte-order
+	 * and send */
+	mutex_lock(&sc->sc_send_lock);
+	ret = r2net_send_tcp_msg(sc->sc_sock, vec, veclen,
+				 sizeof(struct r2net_msg) + caller_bytes);
+	mutex_unlock(&sc->sc_send_lock);
+	msglog(msg, "sending returned %d\n", ret);
+	if (ret < 0) {
+		mlog(0, "error returned from r2net_send_tcp_msg=%d\n", ret);
+		goto out;
+	}
+
+	/* wait on other node's handler */
+	r2net_set_nst_status_time(&nst);
+	wait_event(nsw.ns_wq, r2net_nsw_completed(nn, &nsw));
+
+	r2net_update_send_stats(&nst, sc);
+
+	/* Note that we avoid overwriting the callers status return
+	 * variable if a system error was reported on the other
+	 * side. Callers beware. */
+	ret = r2net_sys_err_to_errno(nsw.ns_sys_status);
+	if (status && !ret)
+		*status = nsw.ns_status;
+
+	mlog(0, "woken, returning system status %d, user status %d\n",
+	     ret, nsw.ns_status);
+out:
+	r2net_debug_del_nst(&nst); /* must be before dropping sc and node */
+	if (sc)
+		sc_put(sc);
+	kfree(vec);
+	kfree(msg);
+	r2net_complete_nsw(nn, &nsw, 0, 0, 0);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(r2net_send_message_vec);
+
+int r2net_send_message(u32 msg_type, u32 key, void *data, u32 len,
+		       u8 target_node, int *status)
+{
+	struct kvec vec = {
+		.iov_base = data,
+		.iov_len = len,
+	};
+	return r2net_send_message_vec(msg_type, key, &vec, 1,
+				      target_node, status);
+}
+EXPORT_SYMBOL_GPL(r2net_send_message);
+
+static int r2net_send_status_magic(struct socket *sock, struct r2net_msg *hdr,
+				   enum r2net_system_error syserr, int err)
+{
+	struct kvec vec = {
+		.iov_base = hdr,
+		.iov_len = sizeof(struct r2net_msg),
+	};
+
+	BUG_ON(syserr >= R2NET_ERR_MAX);
+
+	/* leave other fields intact from the incoming message, msg_num
+	 * in particular */
+	hdr->sys_status = cpu_to_be32(syserr);
+	hdr->status = cpu_to_be32(err);
+	/* twiddle the magic */
+	hdr->magic = cpu_to_be16(R2NET_MSG_STATUS_MAGIC);
+	hdr->data_len = 0;
+
+	msglog(hdr, "about to send status magic %d\n", err);
+	/* hdr has been in host byteorder this whole time */
+	return r2net_send_tcp_msg(sock, &vec, 1, sizeof(struct r2net_msg));
+}
+
+/*
+ * "data magic" is a long version of "status magic" where the message
+ * payload actually contains data to be passed in reply to certain messages
+ */
+static int r2net_send_data_magic(struct r2net_sock_container *sc,
+			  struct r2net_msg *hdr,
+			  void *data, size_t data_len,
+			  enum r2net_system_error syserr, int err)
+{
+	struct kvec vec[2];
+	int ret;
+
+	vec[0].iov_base = hdr;
+	vec[0].iov_len = sizeof(struct r2net_msg);
+	vec[1].iov_base = data;
+	vec[1].iov_len = data_len;
+
+	BUG_ON(syserr >= R2NET_ERR_MAX);
+
+	/* leave other fields intact from the incoming message, msg_num
+	 * in particular */
+	hdr->sys_status = cpu_to_be32(syserr);
+	hdr->status = cpu_to_be32(err);
+	hdr->magic = cpu_to_be16(R2NET_MSG_DATA_MAGIC);  /* twiddle magic */
+	hdr->data_len = cpu_to_be16(data_len);
+
+	msglog(hdr, "about to send data magic %d\n", err);
+	/* hdr has been in host byteorder this whole time */
+	ret = r2net_send_tcp_msg(sc->sc_sock, vec, 2,
+			sizeof(struct r2net_msg) + data_len);
+	return ret;
+}
+
+/*
+ * called by a message handler to convert an otherwise normal reply
+ * message into a "data magic" message
+ */
+void r2net_force_data_magic(struct r2net_msg *hdr, u16 msgtype, u32 msgkey)
+{
+	hdr->magic = cpu_to_be16(R2NET_MSG_DATA_MAGIC);
+	hdr->msg_type = cpu_to_be16(msgtype);
+	hdr->key = cpu_to_be32(msgkey);
+}
+
+/* this returns -errno if the header was unknown or too large, etc.
+ * after this is called the buffer us reused for the next message */
+static int r2net_process_message(struct r2net_sock_container *sc,
+				 struct r2net_msg *hdr)
+{
+	struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
+	int ret = 0, handler_status;
+	enum  r2net_system_error syserr;
+	struct r2net_msg_handler *nmh = NULL;
+	void *ret_data = NULL;
+	int data_magic = 0;
+
+	msglog(hdr, "processing message\n");
+
+	r2net_sc_postpone_idle(sc);
+
+	switch (be16_to_cpu(hdr->magic)) {
+
+	case R2NET_MSG_STATUS_MAGIC:
+		/* special type for returning message status */
+		r2net_complete_nsw(nn, NULL, be32_to_cpu(hdr->msg_num),
+						be32_to_cpu(hdr->sys_status),
+						be32_to_cpu(hdr->status));
+		goto out;
+	case R2NET_MSG_KEEP_REQ_MAGIC:
+		r2net_sendpage(sc, r2net_keep_resp, sizeof(*r2net_keep_resp));
+		goto out;
+	case R2NET_MSG_KEEP_RESP_MAGIC:
+		goto out;
+	case R2NET_MSG_MAGIC:
+		break;
+	case R2NET_MSG_DATA_MAGIC:
+		/*
+		 * unlike a normal status magic, a data magic DOES
+		 * (MUST) have a handler, so the control flow is
+		 * a little funky here as a result
+		 */
+		data_magic = 1;
+		break;
+	default:
+		msglog(hdr, "bad magic\n");
+		ret = -EINVAL;
+		goto out;
+		break;
+	}
+
+	/* find a handler for it */
+	handler_status = 0;
+	nmh = r2net_handler_get(be16_to_cpu(hdr->msg_type),
+				be32_to_cpu(hdr->key));
+	if (!nmh) {
+		mlog(ML_TCP, "couldn't find handler for type %u key %08x\n",
+		     be16_to_cpu(hdr->msg_type), be32_to_cpu(hdr->key));
+		syserr = R2NET_ERR_NO_HNDLR;
+		goto out_respond;
+	}
+
+	syserr = R2NET_ERR_NONE;
+
+	if (be16_to_cpu(hdr->data_len) > nmh->nh_max_len)
+		syserr = R2NET_ERR_OVERFLOW;
+
+	if (syserr != R2NET_ERR_NONE)
+		goto out_respond;
+
+	r2net_set_func_start_time(sc);
+	sc->sc_msg_key = be32_to_cpu(hdr->key);
+	sc->sc_msg_type = be16_to_cpu(hdr->msg_type);
+	handler_status = (nmh->nh_func)(hdr, sizeof(struct r2net_msg) +
+					     be16_to_cpu(hdr->data_len),
+					nmh->nh_func_data, &ret_data);
+	if (data_magic) {
+		/*
+		 * handler handled data sent in reply to request
+		 * so complete the transaction
+		 */
+		r2net_complete_nsw(nn, NULL, be32_to_cpu(hdr->msg_num),
+			be32_to_cpu(hdr->sys_status), handler_status);
+		goto out;
+	}
+	/*
+	 * handler changed magic to DATA_MAGIC to reply to request for data,
+	 * implies ret_data points to data to return and handler_status
+	 * is the number of bytes of data
+	 */
+	if (be16_to_cpu(hdr->magic) == R2NET_MSG_DATA_MAGIC) {
+		ret = r2net_send_data_magic(sc, hdr,
+						ret_data, handler_status,
+						syserr, 0);
+		hdr = NULL;
+		mlog(0, "sending data reply %d, syserr %d returned %d\n",
+			handler_status, syserr, ret);
+		r2net_set_func_stop_time(sc);
+
+		r2net_update_recv_stats(sc);
+		goto out;
+	}
+	r2net_set_func_stop_time(sc);
+
+	r2net_update_recv_stats(sc);
+
+out_respond:
+	/* this destroys the hdr, so don't use it after this */
+	mutex_lock(&sc->sc_send_lock);
+	ret = r2net_send_status_magic(sc->sc_sock, hdr, syserr,
+				      handler_status);
+	mutex_unlock(&sc->sc_send_lock);
+	hdr = NULL;
+	mlog(0, "sending handler status %d, syserr %d returned %d\n",
+	     handler_status, syserr, ret);
+
+	if (nmh) {
+		BUG_ON(ret_data != NULL && nmh->nh_post_func == NULL);
+		if (nmh->nh_post_func)
+			(nmh->nh_post_func)(handler_status, nmh->nh_func_data,
+					    ret_data);
+	}
+
+out:
+	if (nmh)
+		r2net_handler_put(nmh);
+	return ret;
+}
+
+static int r2net_check_handshake(struct r2net_sock_container *sc)
+{
+	struct r2net_handshake *hand = page_address(sc->sc_page);
+	struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
+
+	if (hand->protocol_version != cpu_to_be64(R2NET_PROTOCOL_VERSION)) {
+		printk(KERN_NOTICE "ramster: " SC_NODEF_FMT " Advertised net "
+		       "protocol version %llu but %llu is required. "
+		       "Disconnecting.\n", sc->sc_node->nd_name,
+			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
+			ntohs(sc->sc_node->nd_ipv4_port),
+		       (unsigned long long)be64_to_cpu(hand->protocol_version),
+		       R2NET_PROTOCOL_VERSION);
+
+		/* don't bother reconnecting if its the wrong version. */
+		r2net_ensure_shutdown(nn, sc, -ENOTCONN);
+		return -1;
+	}
+
+	/*
+	 * Ensure timeouts are consistent with other nodes, otherwise
+	 * we can end up with one node thinking that the other must be down,
+	 * but isn't. This can ultimately cause corruption.
+	 */
+	if (be32_to_cpu(hand->r2net_idle_timeout_ms) !=
+				r2net_idle_timeout()) {
+		printk(KERN_NOTICE "ramster: " SC_NODEF_FMT " uses a network "
+		       "idle timeout of %u ms, but we use %u ms locally. "
+		       "Disconnecting.\n", sc->sc_node->nd_name,
+			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
+			ntohs(sc->sc_node->nd_ipv4_port),
+		       be32_to_cpu(hand->r2net_idle_timeout_ms),
+		       r2net_idle_timeout());
+		r2net_ensure_shutdown(nn, sc, -ENOTCONN);
+		return -1;
+	}
+
+	if (be32_to_cpu(hand->r2net_keepalive_delay_ms) !=
+			r2net_keepalive_delay()) {
+		printk(KERN_NOTICE "ramster: " SC_NODEF_FMT " uses a keepalive "
+		       "delay of %u ms, but we use %u ms locally. "
+		       "Disconnecting.\n", sc->sc_node->nd_name,
+			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
+			ntohs(sc->sc_node->nd_ipv4_port),
+		       be32_to_cpu(hand->r2net_keepalive_delay_ms),
+		       r2net_keepalive_delay());
+		r2net_ensure_shutdown(nn, sc, -ENOTCONN);
+		return -1;
+	}
+
+	if (be32_to_cpu(hand->r2hb_heartbeat_timeout_ms) !=
+			R2HB_MAX_WRITE_TIMEOUT_MS) {
+		printk(KERN_NOTICE "ramster: " SC_NODEF_FMT " uses a heartbeat "
+		       "timeout of %u ms, but we use %u ms locally. "
+		       "Disconnecting.\n", sc->sc_node->nd_name,
+			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
+			ntohs(sc->sc_node->nd_ipv4_port),
+		       be32_to_cpu(hand->r2hb_heartbeat_timeout_ms),
+		       R2HB_MAX_WRITE_TIMEOUT_MS);
+		r2net_ensure_shutdown(nn, sc, -ENOTCONN);
+		return -1;
+	}
+
+	sc->sc_handshake_ok = 1;
+
+	spin_lock(&nn->nn_lock);
+	/* set valid and queue the idle timers only if it hasn't been
+	 * shut down already */
+	if (nn->nn_sc == sc) {
+		r2net_sc_reset_idle_timer(sc);
+		atomic_set(&nn->nn_timeout, 0);
+		r2net_set_nn_state(nn, sc, 1, 0);
+	}
+	spin_unlock(&nn->nn_lock);
+
+	/* shift everything up as though it wasn't there */
+	sc->sc_page_off -= sizeof(struct r2net_handshake);
+	if (sc->sc_page_off)
+		memmove(hand, hand + 1, sc->sc_page_off);
+
+	return 0;
+}
+
+/* this demuxes the queued rx bytes into header or payload bits and calls
+ * handlers as each full message is read off the socket.  it returns -error,
+ * == 0 eof, or > 0 for progress made.*/
+static int r2net_advance_rx(struct r2net_sock_container *sc)
+{
+	struct r2net_msg *hdr;
+	int ret = 0;
+	void *data;
+	size_t datalen;
+
+	sclog(sc, "receiving\n");
+	r2net_set_advance_start_time(sc);
+
+	if (unlikely(sc->sc_handshake_ok == 0)) {
+		if (sc->sc_page_off < sizeof(struct r2net_handshake)) {
+			data = page_address(sc->sc_page) + sc->sc_page_off;
+			datalen = sizeof(struct r2net_handshake) -
+							sc->sc_page_off;
+			ret = r2net_recv_tcp_msg(sc->sc_sock, data, datalen);
+			if (ret > 0)
+				sc->sc_page_off += ret;
+		}
+
+		if (sc->sc_page_off == sizeof(struct r2net_handshake)) {
+			r2net_check_handshake(sc);
+			if (unlikely(sc->sc_handshake_ok == 0))
+				ret = -EPROTO;
+		}
+		goto out;
+	}
+
+	/* do we need more header? */
+	if (sc->sc_page_off < sizeof(struct r2net_msg)) {
+		data = page_address(sc->sc_page) + sc->sc_page_off;
+		datalen = sizeof(struct r2net_msg) - sc->sc_page_off;
+		ret = r2net_recv_tcp_msg(sc->sc_sock, data, datalen);
+		if (ret > 0) {
+			sc->sc_page_off += ret;
+			/* only swab incoming here.. we can
+			 * only get here once as we cross from
+			 * being under to over */
+			if (sc->sc_page_off == sizeof(struct r2net_msg)) {
+				hdr = page_address(sc->sc_page);
+				if (be16_to_cpu(hdr->data_len) >
+				    R2NET_MAX_PAYLOAD_BYTES)
+					ret = -EOVERFLOW;
+			}
+		}
+		if (ret <= 0)
+			goto out;
+	}
+
+	if (sc->sc_page_off < sizeof(struct r2net_msg)) {
+		/* oof, still don't have a header */
+		goto out;
+	}
+
+	/* this was swabbed above when we first read it */
+	hdr = page_address(sc->sc_page);
+
+	msglog(hdr, "at page_off %zu\n", sc->sc_page_off);
+
+	/* do we need more payload? */
+	if (sc->sc_page_off - sizeof(struct r2net_msg) <
+					be16_to_cpu(hdr->data_len)) {
+		/* need more payload */
+		data = page_address(sc->sc_page) + sc->sc_page_off;
+		datalen = (sizeof(struct r2net_msg) +
+				be16_to_cpu(hdr->data_len)) -
+				sc->sc_page_off;
+		ret = r2net_recv_tcp_msg(sc->sc_sock, data, datalen);
+		if (ret > 0)
+			sc->sc_page_off += ret;
+		if (ret <= 0)
+			goto out;
+	}
+
+	if (sc->sc_page_off - sizeof(struct r2net_msg) ==
+						be16_to_cpu(hdr->data_len)) {
+		/* we can only get here once, the first time we read
+		 * the payload.. so set ret to progress if the handler
+		 * works out. after calling this the message is toast */
+		ret = r2net_process_message(sc, hdr);
+		if (ret == 0)
+			ret = 1;
+		sc->sc_page_off = 0;
+	}
+
+out:
+	sclog(sc, "ret = %d\n", ret);
+	r2net_set_advance_stop_time(sc);
+	return ret;
+}
+
+/* this work func is triggerd by data ready.  it reads until it can read no
+ * more.  it interprets 0, eof, as fatal.  if data_ready hits while we're doing
+ * our work the work struct will be marked and we'll be called again. */
+static void r2net_rx_until_empty(struct work_struct *work)
+{
+	struct r2net_sock_container *sc =
+		container_of(work, struct r2net_sock_container, sc_rx_work);
+	int ret;
+
+	do {
+		ret = r2net_advance_rx(sc);
+	} while (ret > 0);
+
+	if (ret <= 0 && ret != -EAGAIN) {
+		struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
+		sclog(sc, "saw error %d, closing\n", ret);
+		/* not permanent so read failed handshake can retry */
+		r2net_ensure_shutdown(nn, sc, 0);
+	}
+
+	sc_put(sc);
+}
+
+static int r2net_set_nodelay(struct socket *sock)
+{
+	int ret, val = 1;
+	mm_segment_t oldfs;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+
+	/*
+	 * Dear unsuspecting programmer,
+	 *
+	 * Don't use sock_setsockopt() for SOL_TCP.  It doesn't check its level
+	 * argument and assumes SOL_SOCKET so, say, your TCP_NODELAY will
+	 * silently turn into SO_DEBUG.
+	 *
+	 * Yours,
+	 * Keeper of hilariously fragile interfaces.
+	 */
+	ret = sock->ops->setsockopt(sock, SOL_TCP, TCP_NODELAY,
+				    (char __user *)&val, sizeof(val));
+
+	set_fs(oldfs);
+	return ret;
+}
+
+static void r2net_initialize_handshake(void)
+{
+	r2net_hand->r2hb_heartbeat_timeout_ms = cpu_to_be32(
+		R2HB_MAX_WRITE_TIMEOUT_MS);
+	r2net_hand->r2net_idle_timeout_ms = cpu_to_be32(r2net_idle_timeout());
+	r2net_hand->r2net_keepalive_delay_ms = cpu_to_be32(
+		r2net_keepalive_delay());
+	r2net_hand->r2net_reconnect_delay_ms = cpu_to_be32(
+		r2net_reconnect_delay());
+}
+
+/* ------------------------------------------------------------ */
+
+/* called when a connect completes and after a sock is accepted.  the
+ * rx path will see the response and mark the sc valid */
+static void r2net_sc_connect_completed(struct work_struct *work)
+{
+	struct r2net_sock_container *sc =
+			container_of(work, struct r2net_sock_container,
+			     sc_connect_work);
+
+	mlog(ML_MSG, "sc sending handshake with ver %llu id %llx\n",
+		(unsigned long long)R2NET_PROTOCOL_VERSION,
+		(unsigned long long)be64_to_cpu(r2net_hand->connector_id));
+
+	r2net_initialize_handshake();
+	r2net_sendpage(sc, r2net_hand, sizeof(*r2net_hand));
+	sc_put(sc);
+}
+
+/* this is called as a work_struct func. */
+static void r2net_sc_send_keep_req(struct work_struct *work)
+{
+	struct r2net_sock_container *sc =
+		container_of(work, struct r2net_sock_container,
+			     sc_keepalive_work.work);
+
+	r2net_sendpage(sc, r2net_keep_req, sizeof(*r2net_keep_req));
+	sc_put(sc);
+}
+
+/* socket shutdown does a del_timer_sync against this as it tears down.
+ * we can't start this timer until we've got to the point in sc buildup
+ * where shutdown is going to be involved */
+static void r2net_idle_timer(unsigned long data)
+{
+	struct r2net_sock_container *sc = (struct r2net_sock_container *)data;
+#ifdef CONFIG_DEBUG_FS
+	unsigned long msecs = ktime_to_ms(ktime_get()) -
+		ktime_to_ms(sc->sc_tv_timer);
+#else
+	unsigned long msecs = r2net_idle_timeout();
+#endif
+
+	printk(KERN_NOTICE "ramster: Connection to " SC_NODEF_FMT " has been "
+	       "idle for %lu.%lu secs, shutting it down.\n",
+		sc->sc_node->nd_name, sc->sc_node->nd_num,
+		&sc->sc_node->nd_ipv4_address, ntohs(sc->sc_node->nd_ipv4_port),
+	       msecs / 1000, msecs % 1000);
+
+	/*
+	 * Initialize the nn_timeout so that the next connection attempt
+	 * will continue in r2net_start_connect.
+	 */
+	/* Avoid spurious shutdowns... not sure if this is still necessary */
+	pr_err("ramster_idle_timer, skipping shutdown work\n");
+#if 0
+	/* old code used to do these two lines */
+	atomic_set(&nn->nn_timeout, 1);
+	r2net_sc_queue_work(sc, &sc->sc_shutdown_work);
+#endif
+}
+
+static void r2net_sc_reset_idle_timer(struct r2net_sock_container *sc)
+{
+	r2net_sc_cancel_delayed_work(sc, &sc->sc_keepalive_work);
+	r2net_sc_queue_delayed_work(sc, &sc->sc_keepalive_work,
+		      msecs_to_jiffies(r2net_keepalive_delay()));
+	r2net_set_sock_timer(sc);
+	mod_timer(&sc->sc_idle_timeout,
+	       jiffies + msecs_to_jiffies(r2net_idle_timeout()));
+}
+
+static void r2net_sc_postpone_idle(struct r2net_sock_container *sc)
+{
+	/* Only push out an existing timer */
+	if (timer_pending(&sc->sc_idle_timeout))
+		r2net_sc_reset_idle_timer(sc);
+}
+
+/* this work func is kicked whenever a path sets the nn state which doesn't
+ * have valid set.  This includes seeing hb come up, losing a connection,
+ * having a connect attempt fail, etc. This centralizes the logic which decides
+ * if a connect attempt should be made or if we should give up and all future
+ * transmit attempts should fail */
+static void r2net_start_connect(struct work_struct *work)
+{
+	struct r2net_node *nn =
+		container_of(work, struct r2net_node, nn_connect_work.work);
+	struct r2net_sock_container *sc = NULL;
+	struct r2nm_node *node = NULL, *mynode = NULL;
+	struct socket *sock = NULL;
+	struct sockaddr_in myaddr = {0, }, remoteaddr = {0, };
+	int ret = 0, stop;
+	unsigned int timeout;
+
+	/* if we're greater we initiate tx, otherwise we accept */
+	if (r2nm_this_node() <= r2net_num_from_nn(nn))
+		goto out;
+
+	/* watch for racing with tearing a node down */
+	node = r2nm_get_node_by_num(r2net_num_from_nn(nn));
+	if (node == NULL) {
+		ret = 0;
+		goto out;
+	}
+
+	mynode = r2nm_get_node_by_num(r2nm_this_node());
+	if (mynode == NULL) {
+		ret = 0;
+		goto out;
+	}
+
+	spin_lock(&nn->nn_lock);
+	/*
+	 * see if we already have one pending or have given up.
+	 * For nn_timeout, it is set when we close the connection
+	 * because of the idle time out. So it means that we have
+	 * at least connected to that node successfully once,
+	 * now try to connect to it again.
+	 */
+	timeout = atomic_read(&nn->nn_timeout);
+	stop = (nn->nn_sc ||
+		(nn->nn_persistent_error &&
+		(nn->nn_persistent_error != -ENOTCONN || timeout == 0)));
+	spin_unlock(&nn->nn_lock);
+	if (stop)
+		goto out;
+
+	nn->nn_last_connect_attempt = jiffies;
+
+	sc = sc_alloc(node);
+	if (sc == NULL) {
+		mlog(0, "couldn't allocate sc\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
+	if (ret < 0) {
+		mlog(0, "can't create socket: %d\n", ret);
+		goto out;
+	}
+	sc->sc_sock = sock; /* freed by sc_kref_release */
+
+	sock->sk->sk_allocation = GFP_ATOMIC;
+
+	myaddr.sin_family = AF_INET;
+	myaddr.sin_addr.s_addr = mynode->nd_ipv4_address;
+	myaddr.sin_port = htons(0); /* any port */
+
+	ret = sock->ops->bind(sock, (struct sockaddr *)&myaddr,
+			      sizeof(myaddr));
+	if (ret) {
+		mlog(ML_ERROR, "bind failed with %d at address %pI4\n",
+		     ret, &mynode->nd_ipv4_address);
+		goto out;
+	}
+
+	ret = r2net_set_nodelay(sc->sc_sock);
+	if (ret) {
+		mlog(ML_ERROR, "setting TCP_NODELAY failed with %d\n", ret);
+		goto out;
+	}
+
+	r2net_register_callbacks(sc->sc_sock->sk, sc);
+
+	spin_lock(&nn->nn_lock);
+	/* handshake completion will set nn->nn_sc_valid */
+	r2net_set_nn_state(nn, sc, 0, 0);
+	spin_unlock(&nn->nn_lock);
+
+	remoteaddr.sin_family = AF_INET;
+	remoteaddr.sin_addr.s_addr = node->nd_ipv4_address;
+	remoteaddr.sin_port = node->nd_ipv4_port;
+
+	ret = sc->sc_sock->ops->connect(sc->sc_sock,
+					(struct sockaddr *)&remoteaddr,
+					sizeof(remoteaddr),
+					O_NONBLOCK);
+	if (ret == -EINPROGRESS)
+		ret = 0;
+
+out:
+	if (ret) {
+		printk(KERN_NOTICE "ramster: Connect attempt to " SC_NODEF_FMT
+		       " failed with errno %d\n", sc->sc_node->nd_name,
+			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
+			ntohs(sc->sc_node->nd_ipv4_port), ret);
+		/* 0 err so that another will be queued and attempted
+		 * from set_nn_state */
+		if (sc)
+			r2net_ensure_shutdown(nn, sc, 0);
+	}
+	if (sc)
+		sc_put(sc);
+	if (node)
+		r2nm_node_put(node);
+	if (mynode)
+		r2nm_node_put(mynode);
+
+	return;
+}
+
+static void r2net_connect_expired(struct work_struct *work)
+{
+	struct r2net_node *nn =
+		container_of(work, struct r2net_node, nn_connect_expired.work);
+
+	spin_lock(&nn->nn_lock);
+	if (!nn->nn_sc_valid) {
+		printk(KERN_NOTICE "ramster: No connection established with "
+		       "node %u after %u.%u seconds, giving up.\n",
+		     r2net_num_from_nn(nn),
+		     r2net_idle_timeout() / 1000,
+		     r2net_idle_timeout() % 1000);
+
+		r2net_set_nn_state(nn, NULL, 0, -ENOTCONN);
+	}
+	spin_unlock(&nn->nn_lock);
+}
+
+static void r2net_still_up(struct work_struct *work)
+{
+}
+
+/* ------------------------------------------------------------ */
+
+void r2net_disconnect_node(struct r2nm_node *node)
+{
+	struct r2net_node *nn = r2net_nn_from_num(node->nd_num);
+
+	/* don't reconnect until it's heartbeating again */
+	spin_lock(&nn->nn_lock);
+	atomic_set(&nn->nn_timeout, 0);
+	r2net_set_nn_state(nn, NULL, 0, -ENOTCONN);
+	spin_unlock(&nn->nn_lock);
+
+	if (r2net_wq) {
+		cancel_delayed_work(&nn->nn_connect_expired);
+		cancel_delayed_work(&nn->nn_connect_work);
+		cancel_delayed_work(&nn->nn_still_up);
+		flush_workqueue(r2net_wq);
+	}
+}
+
+static void r2net_hb_node_down_cb(struct r2nm_node *node, int node_num,
+				  void *data)
+{
+	if (!node)
+		return;
+
+	if (node_num != r2nm_this_node())
+		r2net_disconnect_node(node);
+
+	BUG_ON(atomic_read(&r2net_connected_peers) < 0);
+}
+
+static void r2net_hb_node_up_cb(struct r2nm_node *node, int node_num,
+				void *data)
+{
+	struct r2net_node *nn = r2net_nn_from_num(node_num);
+
+	BUG_ON(!node);
+
+	/* ensure an immediate connect attempt */
+	nn->nn_last_connect_attempt = jiffies -
+		(msecs_to_jiffies(r2net_reconnect_delay()) + 1);
+
+	if (node_num != r2nm_this_node()) {
+		/* believe it or not, accept and node hearbeating testing
+		 * can succeed for this node before we got here.. so
+		 * only use set_nn_state to clear the persistent error
+		 * if that hasn't already happened */
+		spin_lock(&nn->nn_lock);
+		atomic_set(&nn->nn_timeout, 0);
+		if (nn->nn_persistent_error)
+			r2net_set_nn_state(nn, NULL, 0, 0);
+		spin_unlock(&nn->nn_lock);
+	}
+}
+
+void r2net_unregister_hb_callbacks(void)
+{
+	r2hb_unregister_callback(NULL, &r2net_hb_up);
+	r2hb_unregister_callback(NULL, &r2net_hb_down);
+}
+
+int r2net_register_hb_callbacks(void)
+{
+	int ret;
+
+	r2hb_setup_callback(&r2net_hb_down, R2HB_NODE_DOWN_CB,
+			    r2net_hb_node_down_cb, NULL, R2NET_HB_PRI);
+	r2hb_setup_callback(&r2net_hb_up, R2HB_NODE_UP_CB,
+			    r2net_hb_node_up_cb, NULL, R2NET_HB_PRI);
+
+	ret = r2hb_register_callback(NULL, &r2net_hb_up);
+	if (ret == 0)
+		ret = r2hb_register_callback(NULL, &r2net_hb_down);
+
+	if (ret)
+		r2net_unregister_hb_callbacks();
+
+	return ret;
+}
+
+/* ------------------------------------------------------------ */
+
+static int r2net_accept_one(struct socket *sock)
+{
+	int ret, slen;
+	struct sockaddr_in sin;
+	struct socket *new_sock = NULL;
+	struct r2nm_node *node = NULL;
+	struct r2nm_node *local_node = NULL;
+	struct r2net_sock_container *sc = NULL;
+	struct r2net_node *nn;
+
+	BUG_ON(sock == NULL);
+	ret = sock_create_lite(sock->sk->sk_family, sock->sk->sk_type,
+			       sock->sk->sk_protocol, &new_sock);
+	if (ret)
+		goto out;
+
+	new_sock->type = sock->type;
+	new_sock->ops = sock->ops;
+	ret = sock->ops->accept(sock, new_sock, O_NONBLOCK);
+	if (ret < 0)
+		goto out;
+
+	new_sock->sk->sk_allocation = GFP_ATOMIC;
+
+	ret = r2net_set_nodelay(new_sock);
+	if (ret) {
+		mlog(ML_ERROR, "setting TCP_NODELAY failed with %d\n", ret);
+		goto out;
+	}
+
+	slen = sizeof(sin);
+	ret = new_sock->ops->getname(new_sock, (struct sockaddr *) &sin,
+				       &slen, 1);
+	if (ret < 0)
+		goto out;
+
+	node = r2nm_get_node_by_ip(sin.sin_addr.s_addr);
+	if (node == NULL) {
+		printk(KERN_NOTICE "ramster: Attempt to connect from unknown "
+		       "node at %pI4:%d\n", &sin.sin_addr.s_addr,
+		       ntohs(sin.sin_port));
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (r2nm_this_node() >= node->nd_num) {
+		local_node = r2nm_get_node_by_num(r2nm_this_node());
+		printk(KERN_NOTICE "ramster: Unexpected connect attempt seen "
+		       "at node '%s' (%u, %pI4:%d) from node '%s' (%u, "
+		       "%pI4:%d)\n", local_node->nd_name, local_node->nd_num,
+		       &(local_node->nd_ipv4_address),
+		       ntohs(local_node->nd_ipv4_port), node->nd_name,
+		       node->nd_num, &sin.sin_addr.s_addr, ntohs(sin.sin_port));
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* this happens all the time when the other node sees our heartbeat
+	 * and tries to connect before we see their heartbeat */
+	if (!r2hb_check_node_heartbeating_from_callback(node->nd_num)) {
+		mlog(ML_CONN, "attempt to connect from node '%s' at "
+		     "%pI4:%d but it isn't heartbeating\n",
+		     node->nd_name, &sin.sin_addr.s_addr,
+		     ntohs(sin.sin_port));
+		ret = -EINVAL;
+		goto out;
+	}
+
+	nn = r2net_nn_from_num(node->nd_num);
+
+	spin_lock(&nn->nn_lock);
+	if (nn->nn_sc)
+		ret = -EBUSY;
+	else
+		ret = 0;
+	spin_unlock(&nn->nn_lock);
+	if (ret) {
+		printk(KERN_NOTICE "ramster: Attempt to connect from node '%s' "
+		       "at %pI4:%d but it already has an open connection\n",
+		       node->nd_name, &sin.sin_addr.s_addr,
+		       ntohs(sin.sin_port));
+		goto out;
+	}
+
+	sc = sc_alloc(node);
+	if (sc == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	sc->sc_sock = new_sock;
+	new_sock = NULL;
+
+	spin_lock(&nn->nn_lock);
+	atomic_set(&nn->nn_timeout, 0);
+	r2net_set_nn_state(nn, sc, 0, 0);
+	spin_unlock(&nn->nn_lock);
+
+	r2net_register_callbacks(sc->sc_sock->sk, sc);
+	r2net_sc_queue_work(sc, &sc->sc_rx_work);
+
+	r2net_initialize_handshake();
+	r2net_sendpage(sc, r2net_hand, sizeof(*r2net_hand));
+
+out:
+	if (new_sock)
+		sock_release(new_sock);
+	if (node)
+		r2nm_node_put(node);
+	if (local_node)
+		r2nm_node_put(local_node);
+	if (sc)
+		sc_put(sc);
+	return ret;
+}
+
+static void r2net_accept_many(struct work_struct *work)
+{
+	struct socket *sock = r2net_listen_sock;
+	while (r2net_accept_one(sock) == 0)
+		cond_resched();
+}
+
+static void r2net_listen_data_ready(struct sock *sk, int bytes)
+{
+	void (*ready)(struct sock *sk, int bytes);
+
+	read_lock(&sk->sk_callback_lock);
+	ready = sk->sk_user_data;
+	if (ready == NULL) { /* check for teardown race */
+		ready = sk->sk_data_ready;
+		goto out;
+	}
+
+	/* ->sk_data_ready is also called for a newly established child socket
+	 * before it has been accepted and the acceptor has set up their
+	 * data_ready.. we only want to queue listen work for our listening
+	 * socket */
+	if (sk->sk_state == TCP_LISTEN) {
+		mlog(ML_TCP, "bytes: %d\n", bytes);
+		queue_work(r2net_wq, &r2net_listen_work);
+	}
+
+out:
+	read_unlock(&sk->sk_callback_lock);
+	ready(sk, bytes);
+}
+
+static int r2net_open_listening_sock(__be32 addr, __be16 port)
+{
+	struct socket *sock = NULL;
+	int ret;
+	struct sockaddr_in sin = {
+		.sin_family = PF_INET,
+		.sin_addr = { .s_addr = addr },
+		.sin_port = port,
+	};
+
+	ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
+	if (ret < 0) {
+		printk(KERN_ERR "ramster: Error %d while creating socket\n",
+			ret);
+		goto out;
+	}
+
+	sock->sk->sk_allocation = GFP_ATOMIC;
+
+	write_lock_bh(&sock->sk->sk_callback_lock);
+	sock->sk->sk_user_data = sock->sk->sk_data_ready;
+	sock->sk->sk_data_ready = r2net_listen_data_ready;
+	write_unlock_bh(&sock->sk->sk_callback_lock);
+
+	r2net_listen_sock = sock;
+	INIT_WORK(&r2net_listen_work, r2net_accept_many);
+
+	sock->sk->sk_reuse = 1;
+	ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin));
+	if (ret < 0) {
+		printk(KERN_ERR "ramster: Error %d while binding socket at "
+			"%pI4:%u\n", ret, &addr, ntohs(port));
+		goto out;
+	}
+
+	ret = sock->ops->listen(sock, 64);
+	if (ret < 0)
+		printk(KERN_ERR "ramster: Error %d while listening on %pI4:%u\n",
+		       ret, &addr, ntohs(port));
+
+out:
+	if (ret) {
+		r2net_listen_sock = NULL;
+		if (sock)
+			sock_release(sock);
+	}
+	return ret;
+}
+
+/*
+ * called from node manager when we should bring up our network listening
+ * socket.  node manager handles all the serialization to only call this
+ * once and to match it with r2net_stop_listening().  note,
+ * r2nm_this_node() doesn't work yet as we're being called while it
+ * is being set up.
+ */
+int r2net_start_listening(struct r2nm_node *node)
+{
+	int ret = 0;
+
+	BUG_ON(r2net_wq != NULL);
+	BUG_ON(r2net_listen_sock != NULL);
+
+	mlog(ML_KTHREAD, "starting r2net thread...\n");
+	r2net_wq = create_singlethread_workqueue("r2net");
+	if (r2net_wq == NULL) {
+		mlog(ML_ERROR, "unable to launch r2net thread\n");
+		return -ENOMEM; /* ? */
+	}
+
+	ret = r2net_open_listening_sock(node->nd_ipv4_address,
+					node->nd_ipv4_port);
+	if (ret) {
+		destroy_workqueue(r2net_wq);
+		r2net_wq = NULL;
+	}
+
+	return ret;
+}
+
+/* again, r2nm_this_node() doesn't work here as we're involved in
+ * tearing it down */
+void r2net_stop_listening(struct r2nm_node *node)
+{
+	struct socket *sock = r2net_listen_sock;
+	size_t i;
+
+	BUG_ON(r2net_wq == NULL);
+	BUG_ON(r2net_listen_sock == NULL);
+
+	/* stop the listening socket from generating work */
+	write_lock_bh(&sock->sk->sk_callback_lock);
+	sock->sk->sk_data_ready = sock->sk->sk_user_data;
+	sock->sk->sk_user_data = NULL;
+	write_unlock_bh(&sock->sk->sk_callback_lock);
+
+	for (i = 0; i < ARRAY_SIZE(r2net_nodes); i++) {
+		struct r2nm_node *node = r2nm_get_node_by_num(i);
+		if (node) {
+			r2net_disconnect_node(node);
+			r2nm_node_put(node);
+		}
+	}
+
+	/* finish all work and tear down the work queue */
+	mlog(ML_KTHREAD, "waiting for r2net thread to exit....\n");
+	destroy_workqueue(r2net_wq);
+	r2net_wq = NULL;
+
+	sock_release(r2net_listen_sock);
+	r2net_listen_sock = NULL;
+}
+
+void r2net_hb_node_up_manual(int node_num)
+{
+	struct r2nm_node dummy;
+	if (r2nm_single_cluster == NULL)
+		pr_err("ramster: cluster not alive, node_up_manual ignored\n");
+	else {
+		r2hb_manual_set_node_heartbeating(node_num);
+		r2net_hb_node_up_cb(&dummy, node_num, NULL);
+	}
+}
+
+/* ------------------------------------------------------------ */
+
+int r2net_init(void)
+{
+	unsigned long i;
+
+	if (r2net_debugfs_init())
+		return -ENOMEM;
+
+	r2net_hand = kzalloc(sizeof(struct r2net_handshake), GFP_KERNEL);
+	r2net_keep_req = kzalloc(sizeof(struct r2net_msg), GFP_KERNEL);
+	r2net_keep_resp = kzalloc(sizeof(struct r2net_msg), GFP_KERNEL);
+	if (!r2net_hand || !r2net_keep_req || !r2net_keep_resp) {
+		kfree(r2net_hand);
+		kfree(r2net_keep_req);
+		kfree(r2net_keep_resp);
+		return -ENOMEM;
+	}
+
+	r2net_hand->protocol_version = cpu_to_be64(R2NET_PROTOCOL_VERSION);
+	r2net_hand->connector_id = cpu_to_be64(1);
+
+	r2net_keep_req->magic = cpu_to_be16(R2NET_MSG_KEEP_REQ_MAGIC);
+	r2net_keep_resp->magic = cpu_to_be16(R2NET_MSG_KEEP_RESP_MAGIC);
+
+	for (i = 0; i < ARRAY_SIZE(r2net_nodes); i++) {
+		struct r2net_node *nn = r2net_nn_from_num(i);
+
+		atomic_set(&nn->nn_timeout, 0);
+		spin_lock_init(&nn->nn_lock);
+		INIT_DELAYED_WORK(&nn->nn_connect_work, r2net_start_connect);
+		INIT_DELAYED_WORK(&nn->nn_connect_expired,
+				  r2net_connect_expired);
+		INIT_DELAYED_WORK(&nn->nn_still_up, r2net_still_up);
+		/* until we see hb from a node we'll return einval */
+		nn->nn_persistent_error = -ENOTCONN;
+		init_waitqueue_head(&nn->nn_sc_wq);
+		idr_init(&nn->nn_status_idr);
+		INIT_LIST_HEAD(&nn->nn_status_list);
+	}
+
+	return 0;
+}
+
+void r2net_exit(void)
+{
+	kfree(r2net_hand);
+	kfree(r2net_keep_req);
+	kfree(r2net_keep_resp);
+	r2net_debugfs_exit();
+}
diff --git a/drivers/staging/ramster/cluster/tcp.h b/drivers/staging/ramster/cluster/tcp.h
new file mode 100644
index 0000000..9d05833
--- /dev/null
+++ b/drivers/staging/ramster/cluster/tcp.h
@@ -0,0 +1,159 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * tcp.h
+ *
+ * Function prototypes
+ *
+ * Copyright (C) 2004 Oracle.  All rights reserved.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ */
+
+#ifndef R2CLUSTER_TCP_H
+#define R2CLUSTER_TCP_H
+
+#include <linux/socket.h>
+#ifdef __KERNEL__
+#include <net/sock.h>
+#include <linux/tcp.h>
+#else
+#include <sys/socket.h>
+#endif
+#include <linux/inet.h>
+#include <linux/in.h>
+
+struct r2net_msg {
+	__be16 magic;
+	__be16 data_len;
+	__be16 msg_type;
+	__be16 pad1;
+	__be32 sys_status;
+	__be32 status;
+	__be32 key;
+	__be32 msg_num;
+	__u8  buf[0];
+};
+
+typedef int (r2net_msg_handler_func)(struct r2net_msg *msg, u32 len, void *data,
+				     void **ret_data);
+typedef void (r2net_post_msg_handler_func)(int status, void *data,
+					   void *ret_data);
+
+#define R2NET_MAX_PAYLOAD_BYTES  (4096 - sizeof(struct r2net_msg))
+
+/* same as hb delay, we're waiting for another node to recognize our hb */
+#define R2NET_RECONNECT_DELAY_MS_DEFAULT	2000
+
+#define R2NET_KEEPALIVE_DELAY_MS_DEFAULT	2000
+#define R2NET_IDLE_TIMEOUT_MS_DEFAULT		30000
+
+
+/* TODO: figure this out.... */
+static inline int r2net_link_down(int err, struct socket *sock)
+{
+	if (sock) {
+		if (sock->sk->sk_state != TCP_ESTABLISHED &&
+			sock->sk->sk_state != TCP_CLOSE_WAIT)
+			return 1;
+	}
+
+	if (err >= 0)
+		return 0;
+	switch (err) {
+
+	/* ????????????????????????? */
+	case -ERESTARTSYS:
+	case -EBADF:
+	/* When the server has died, an ICMP port unreachable
+	 * message prompts ECONNREFUSED. */
+	case -ECONNREFUSED:
+	case -ENOTCONN:
+	case -ECONNRESET:
+	case -EPIPE:
+		return 1;
+
+	}
+	return 0;
+}
+
+enum {
+	R2NET_DRIVER_UNINITED,
+	R2NET_DRIVER_READY,
+};
+
+int r2net_send_message(u32 msg_type, u32 key, void *data, u32 len,
+		       u8 target_node, int *status);
+int r2net_send_message_vec(u32 msg_type, u32 key, struct kvec *vec,
+			   size_t veclen, u8 target_node, int *status);
+
+int r2net_register_handler(u32 msg_type, u32 key, u32 max_len,
+			   r2net_msg_handler_func *func, void *data,
+			   r2net_post_msg_handler_func *post_func,
+			   struct list_head *unreg_list);
+void r2net_unregister_handler_list(struct list_head *list);
+
+void r2net_fill_node_map(unsigned long *map, unsigned bytes);
+
+void r2net_force_data_magic(struct r2net_msg *, u16, u32);
+void r2net_hb_node_up_manual(int);
+struct r2net_node *r2net_nn_from_num(u8);
+
+struct r2nm_node;
+int r2net_register_hb_callbacks(void);
+void r2net_unregister_hb_callbacks(void);
+int r2net_start_listening(struct r2nm_node *node);
+void r2net_stop_listening(struct r2nm_node *node);
+void r2net_disconnect_node(struct r2nm_node *node);
+int r2net_num_connected_peers(void);
+
+int r2net_init(void);
+void r2net_exit(void);
+
+struct r2net_send_tracking;
+struct r2net_sock_container;
+
+#if 0
+int r2net_debugfs_init(void);
+void r2net_debugfs_exit(void);
+void r2net_debug_add_nst(struct r2net_send_tracking *nst);
+void r2net_debug_del_nst(struct r2net_send_tracking *nst);
+void r2net_debug_add_sc(struct r2net_sock_container *sc);
+void r2net_debug_del_sc(struct r2net_sock_container *sc);
+#else
+static inline int r2net_debugfs_init(void)
+{
+	return 0;
+}
+static inline void r2net_debugfs_exit(void)
+{
+}
+static inline void r2net_debug_add_nst(struct r2net_send_tracking *nst)
+{
+}
+static inline void r2net_debug_del_nst(struct r2net_send_tracking *nst)
+{
+}
+static inline void r2net_debug_add_sc(struct r2net_sock_container *sc)
+{
+}
+static inline void r2net_debug_del_sc(struct r2net_sock_container *sc)
+{
+}
+#endif	/* CONFIG_DEBUG_FS */
+
+#endif /* R2CLUSTER_TCP_H */
diff --git a/drivers/staging/ramster/cluster/tcp_internal.h b/drivers/staging/ramster/cluster/tcp_internal.h
new file mode 100644
index 0000000..4d8cc9f
--- /dev/null
+++ b/drivers/staging/ramster/cluster/tcp_internal.h
@@ -0,0 +1,248 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * Copyright (C) 2005 Oracle.  All rights reserved.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef R2CLUSTER_TCP_INTERNAL_H
+#define R2CLUSTER_TCP_INTERNAL_H
+
+#define R2NET_MSG_MAGIC           ((u16)0xfa55)
+#define R2NET_MSG_STATUS_MAGIC    ((u16)0xfa56)
+#define R2NET_MSG_KEEP_REQ_MAGIC  ((u16)0xfa57)
+#define R2NET_MSG_KEEP_RESP_MAGIC ((u16)0xfa58)
+/*
+ * "data magic" is a long version of "status magic" where the message
+ * payload actually contains data to be passed in reply to certain messages
+ */
+#define R2NET_MSG_DATA_MAGIC      ((u16)0xfa59)
+
+/* we're delaying our quorum decision so that heartbeat will have timed
+ * out truly dead nodes by the time we come around to making decisions
+ * on their number */
+#define R2NET_QUORUM_DELAY_MS	\
+		((r2hb_dead_threshold + 2) * R2HB_REGION_TIMEOUT_MS)
+
+/*
+ * This version number represents quite a lot, unfortunately.  It not
+ * only represents the raw network message protocol on the wire but also
+ * locking semantics of the file system using the protocol.  It should
+ * be somewhere else, I'm sure, but right now it isn't.
+ *
+ * With version 11, we separate out the filesystem locking portion.  The
+ * filesystem now has a major.minor version it negotiates.  Version 11
+ * introduces this negotiation to the r2dlm protocol, and as such the
+ * version here in tcp_internal.h should not need to be bumped for
+ * filesystem locking changes.
+ *
+ * New in version 11
+ *	- Negotiation of filesystem locking in the dlm join.
+ *
+ * New in version 10:
+ *	- Meta/data locks combined
+ *
+ * New in version 9:
+ *	- All votes removed
+ *
+ * New in version 8:
+ *	- Replace delete inode votes with a cluster lock
+ *
+ * New in version 7:
+ *	- DLM join domain includes the live nodemap
+ *
+ * New in version 6:
+ *	- DLM lockres remote refcount fixes.
+ *
+ * New in version 5:
+ *	- Network timeout checking protocol
+ *
+ * New in version 4:
+ *	- Remove i_generation from lock names for better stat performance.
+ *
+ * New in version 3:
+ *	- Replace dentry votes with a cluster lock
+ *
+ * New in version 2:
+ *	- full 64 bit i_size in the metadata lock lvbs
+ *	- introduction of "rw" lock and pushing meta/data locking down
+ */
+#define R2NET_PROTOCOL_VERSION 11ULL
+struct r2net_handshake {
+	__be64	protocol_version;
+	__be64	connector_id;
+	__be32  r2hb_heartbeat_timeout_ms;
+	__be32  r2net_idle_timeout_ms;
+	__be32  r2net_keepalive_delay_ms;
+	__be32  r2net_reconnect_delay_ms;
+};
+
+struct r2net_node {
+	/* this is never called from int/bh */
+	spinlock_t			nn_lock;
+
+	/* set the moment an sc is allocated and a connect is started */
+	struct r2net_sock_container	*nn_sc;
+	/* _valid is only set after the handshake passes and tx can happen */
+	unsigned			nn_sc_valid:1;
+	/* if this is set tx just returns it */
+	int				nn_persistent_error;
+	/* It is only set to 1 after the idle time out. */
+	atomic_t			nn_timeout;
+
+	/* threads waiting for an sc to arrive wait on the wq for generation
+	 * to increase.  it is increased when a connecting socket succeeds
+	 * or fails or when an accepted socket is attached. */
+	wait_queue_head_t		nn_sc_wq;
+
+	struct idr			nn_status_idr;
+	struct list_head		nn_status_list;
+
+	/* connects are attempted from when heartbeat comes up until either hb
+	 * goes down, the node is unconfigured, no connect attempts succeed
+	 * before R2NET_CONN_IDLE_DELAY, or a connect succeeds.  connect_work
+	 * is queued from set_nn_state both from hb up and from itself if a
+	 * connect attempt fails and so can be self-arming.  shutdown is
+	 * careful to first mark the nn such that no connects will be attempted
+	 * before canceling delayed connect work and flushing the queue. */
+	struct delayed_work		nn_connect_work;
+	unsigned long			nn_last_connect_attempt;
+
+	/* this is queued as nodes come up and is canceled when a connection is
+	 * established.  this expiring gives up on the node and errors out
+	 * transmits */
+	struct delayed_work		nn_connect_expired;
+
+	/* after we give up on a socket we wait a while before deciding
+	 * that it is still heartbeating and that we should do some
+	 * quorum work */
+	struct delayed_work		nn_still_up;
+};
+
+struct r2net_sock_container {
+	struct kref		sc_kref;
+	/* the next two are valid for the life time of the sc */
+	struct socket		*sc_sock;
+	struct r2nm_node	*sc_node;
+
+	/* all of these sc work structs hold refs on the sc while they are
+	 * queued.  they should not be able to ref a freed sc.  the teardown
+	 * race is with r2net_wq destruction in r2net_stop_listening() */
+
+	/* rx and connect work are generated from socket callbacks.  sc
+	 * shutdown removes the callbacks and then flushes the work queue */
+	struct work_struct	sc_rx_work;
+	struct work_struct	sc_connect_work;
+	/* shutdown work is triggered in two ways.  the simple way is
+	 * for a code path calls ensure_shutdown which gets a lock, removes
+	 * the sc from the nn, and queues the work.  in this case the
+	 * work is single-shot.  the work is also queued from a sock
+	 * callback, though, and in this case the work will find the sc
+	 * still on the nn and will call ensure_shutdown itself.. this
+	 * ends up triggering the shutdown work again, though nothing
+	 * will be done in that second iteration.  so work queue teardown
+	 * has to be careful to remove the sc from the nn before waiting
+	 * on the work queue so that the shutdown work doesn't remove the
+	 * sc and rearm itself.
+	 */
+	struct work_struct	sc_shutdown_work;
+
+	struct timer_list	sc_idle_timeout;
+	struct delayed_work	sc_keepalive_work;
+
+	unsigned		sc_handshake_ok:1;
+
+	struct page		*sc_page;
+	size_t			sc_page_off;
+
+	/* original handlers for the sockets */
+	void			(*sc_state_change)(struct sock *sk);
+	void			(*sc_data_ready)(struct sock *sk, int bytes);
+
+	u32			sc_msg_key;
+	u16			sc_msg_type;
+
+#ifdef CONFIG_DEBUG_FS
+	struct list_head        sc_net_debug_item;
+	ktime_t			sc_tv_timer;
+	ktime_t			sc_tv_data_ready;
+	ktime_t			sc_tv_advance_start;
+	ktime_t			sc_tv_advance_stop;
+	ktime_t			sc_tv_func_start;
+	ktime_t			sc_tv_func_stop;
+#endif
+#ifdef CONFIG_RAMSTER_FS_STATS
+	ktime_t			sc_tv_acquiry_total;
+	ktime_t			sc_tv_send_total;
+	ktime_t			sc_tv_status_total;
+	u32			sc_send_count;
+	u32			sc_recv_count;
+	ktime_t			sc_tv_process_total;
+#endif
+	struct mutex		sc_send_lock;
+};
+
+struct r2net_msg_handler {
+	struct rb_node		nh_node;
+	u32			nh_max_len;
+	u32			nh_msg_type;
+	u32			nh_key;
+	r2net_msg_handler_func	*nh_func;
+	r2net_msg_handler_func	*nh_func_data;
+	r2net_post_msg_handler_func
+				*nh_post_func;
+	struct kref		nh_kref;
+	struct list_head	nh_unregister_item;
+};
+
+enum r2net_system_error {
+	R2NET_ERR_NONE = 0,
+	R2NET_ERR_NO_HNDLR,
+	R2NET_ERR_OVERFLOW,
+	R2NET_ERR_DIED,
+	R2NET_ERR_MAX
+};
+
+struct r2net_status_wait {
+	enum r2net_system_error	ns_sys_status;
+	s32			ns_status;
+	int			ns_id;
+	wait_queue_head_t	ns_wq;
+	struct list_head	ns_node_item;
+};
+
+#ifdef CONFIG_DEBUG_FS
+/* just for state dumps */
+struct r2net_send_tracking {
+	struct list_head		st_net_debug_item;
+	struct task_struct		*st_task;
+	struct r2net_sock_container	*st_sc;
+	u32				st_id;
+	u32				st_msg_type;
+	u32				st_msg_key;
+	u8				st_node;
+	ktime_t				st_sock_time;
+	ktime_t				st_send_time;
+	ktime_t				st_status_time;
+};
+#else
+struct r2net_send_tracking {
+	u32	dummy;
+};
+#endif	/* CONFIG_DEBUG_FS */
+
+#endif /* R2CLUSTER_TCP_INTERNAL_H */
diff --git a/drivers/staging/ramster/r2net.c b/drivers/staging/ramster/r2net.c
new file mode 100644
index 0000000..2ee0220
--- /dev/null
+++ b/drivers/staging/ramster/r2net.c
@@ -0,0 +1,401 @@
+/*
+ * r2net.c
+ *
+ * Copyright (c) 2011, Dan Magenheimer, Oracle Corp.
+ *
+ * Ramster_r2net provides an interface between zcache and r2net.
+ *
+ * FIXME: support more than two nodes
+ */
+
+#include <linux/list.h>
+#include "cluster/tcp.h"
+#include "cluster/nodemanager.h"
+#include "tmem.h"
+#include "zcache.h"
+#include "ramster.h"
+
+#define RAMSTER_TESTING
+
+#define RMSTR_KEY	0x77347734
+
+enum {
+	RMSTR_TMEM_PUT_EPH = 100,
+	RMSTR_TMEM_PUT_PERS,
+	RMSTR_TMEM_ASYNC_GET_REQUEST,
+	RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST,
+	RMSTR_TMEM_ASYNC_GET_REPLY,
+	RMSTR_TMEM_FLUSH,
+	RMSTR_TMEM_FLOBJ,
+	RMSTR_TMEM_DESTROY_POOL,
+};
+
+#define RMSTR_R2NET_MAX_LEN \
+		(R2NET_MAX_PAYLOAD_BYTES - sizeof(struct tmem_xhandle))
+
+#include "cluster/tcp_internal.h"
+
+static struct r2nm_node *r2net_target_node;
+static int r2net_target_nodenum;
+
+int r2net_remote_target_node_set(int node_num)
+{
+	int ret = -1;
+
+	r2net_target_node = r2nm_get_node_by_num(node_num);
+	if (r2net_target_node != NULL) {
+		r2net_target_nodenum = node_num;
+		r2nm_node_put(r2net_target_node);
+		ret = 0;
+	}
+	return ret;
+}
+
+/* FIXME following buffer should be per-cpu, protected by preempt_disable */
+static char ramster_async_get_buf[R2NET_MAX_PAYLOAD_BYTES];
+
+static int ramster_remote_async_get_request_handler(struct r2net_msg *msg,
+				u32 len, void *data, void **ret_data)
+{
+	char *pdata;
+	struct tmem_xhandle xh;
+	int found;
+	size_t size = RMSTR_R2NET_MAX_LEN;
+	u16 msgtype = be16_to_cpu(msg->msg_type);
+	bool get_and_free = (msgtype == RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST);
+	unsigned long flags;
+
+	xh = *(struct tmem_xhandle *)msg->buf;
+	if (xh.xh_data_size > RMSTR_R2NET_MAX_LEN)
+		BUG();
+	pdata = ramster_async_get_buf;
+	*(struct tmem_xhandle *)pdata = xh;
+	pdata += sizeof(struct tmem_xhandle);
+	local_irq_save(flags);
+	found = zcache_get(xh.client_id, xh.pool_id, &xh.oid, xh.index,
+				pdata, &size, 1, get_and_free ? 1 : -1);
+	local_irq_restore(flags);
+	if (found < 0) {
+		/* a zero size indicates the get failed */
+		size = 0;
+	}
+	if (size > RMSTR_R2NET_MAX_LEN)
+		BUG();
+	*ret_data = pdata - sizeof(struct tmem_xhandle);
+	/* now make caller (r2net_process_message) handle specially */
+	r2net_force_data_magic(msg, RMSTR_TMEM_ASYNC_GET_REPLY, RMSTR_KEY);
+	return size + sizeof(struct tmem_xhandle);
+}
+
+static int ramster_remote_async_get_reply_handler(struct r2net_msg *msg,
+				u32 len, void *data, void **ret_data)
+{
+	char *in = (char *)msg->buf;
+	int datalen = len - sizeof(struct r2net_msg);
+	int ret = -1;
+	struct tmem_xhandle *xh = (struct tmem_xhandle *)in;
+
+	in += sizeof(struct tmem_xhandle);
+	datalen -= sizeof(struct tmem_xhandle);
+	BUG_ON(datalen < 0 || datalen > PAGE_SIZE);
+	ret = zcache_localify(xh->pool_id, &xh->oid, xh->index,
+				in, datalen, xh->extra);
+#ifdef RAMSTER_TESTING
+	if (ret == -EEXIST)
+		pr_err("TESTING ArrgREP, aborted overwrite on racy put\n");
+#endif
+	return ret;
+}
+
+int ramster_remote_put_handler(struct r2net_msg *msg,
+				u32 len, void *data, void **ret_data)
+{
+	struct tmem_xhandle *xh;
+	char *p = (char *)msg->buf;
+	int datalen = len - sizeof(struct r2net_msg) -
+				sizeof(struct tmem_xhandle);
+	u16 msgtype = be16_to_cpu(msg->msg_type);
+	bool ephemeral = (msgtype == RMSTR_TMEM_PUT_EPH);
+	unsigned long flags;
+	int ret;
+
+	xh = (struct tmem_xhandle *)p;
+	p += sizeof(struct tmem_xhandle);
+	zcache_autocreate_pool(xh->client_id, xh->pool_id, ephemeral);
+	local_irq_save(flags);
+	ret = zcache_put(xh->client_id, xh->pool_id, &xh->oid, xh->index,
+				p, datalen, 1, ephemeral ? 1 : -1);
+	local_irq_restore(flags);
+	return ret;
+}
+
+int ramster_remote_flush_handler(struct r2net_msg *msg,
+				u32 len, void *data, void **ret_data)
+{
+	struct tmem_xhandle *xh;
+	char *p = (char *)msg->buf;
+
+	xh = (struct tmem_xhandle *)p;
+	p += sizeof(struct tmem_xhandle);
+	(void)zcache_flush(xh->client_id, xh->pool_id, &xh->oid, xh->index);
+	return 0;
+}
+
+int ramster_remote_flobj_handler(struct r2net_msg *msg,
+				u32 len, void *data, void **ret_data)
+{
+	struct tmem_xhandle *xh;
+	char *p = (char *)msg->buf;
+
+	xh = (struct tmem_xhandle *)p;
+	p += sizeof(struct tmem_xhandle);
+	(void)zcache_flush_object(xh->client_id, xh->pool_id, &xh->oid);
+	return 0;
+}
+
+int ramster_remote_async_get(struct tmem_xhandle *xh, bool free, int remotenode,
+				size_t expect_size, uint8_t expect_cksum,
+				void *extra)
+{
+	int ret = -1, status;
+	struct r2nm_node *node = NULL;
+	struct kvec vec[1];
+	size_t veclen = 1;
+	u32 msg_type;
+
+	node = r2nm_get_node_by_num(remotenode);
+	if (node == NULL)
+		goto out;
+	xh->client_id = r2nm_this_node(); /* which node is getting */
+	xh->xh_data_cksum = expect_cksum;
+	xh->xh_data_size = expect_size;
+	xh->extra = extra;
+	vec[0].iov_len = sizeof(*xh);
+	vec[0].iov_base = xh;
+	if (free)
+		msg_type = RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST;
+	else
+		msg_type = RMSTR_TMEM_ASYNC_GET_REQUEST;
+	ret = r2net_send_message_vec(msg_type, RMSTR_KEY,
+					vec, veclen, remotenode, &status);
+	r2nm_node_put(node);
+	if (ret < 0) {
+		/* FIXME handle bad message possibilities here? */
+		pr_err("UNTESTED ret<0 in ramster_remote_async_get\n");
+	}
+	ret = status;
+out:
+	return ret;
+}
+
+#ifdef RAMSTER_TESTING
+/* leave me here to see if it catches a weird crash */
+static void ramster_check_irq_counts(void)
+{
+	static int last_hardirq_cnt, last_softirq_cnt, last_preempt_cnt;
+	int cur_hardirq_cnt, cur_softirq_cnt, cur_preempt_cnt;
+
+	cur_hardirq_cnt = hardirq_count() >> HARDIRQ_SHIFT;
+	if (cur_hardirq_cnt > last_hardirq_cnt) {
+		last_hardirq_cnt = cur_hardirq_cnt;
+		if (!(last_hardirq_cnt&(last_hardirq_cnt-1)))
+			pr_err("RAMSTER TESTING RRP hardirq_count=%d\n",
+				last_hardirq_cnt);
+	}
+	cur_softirq_cnt = softirq_count() >> SOFTIRQ_SHIFT;
+	if (cur_softirq_cnt > last_softirq_cnt) {
+		last_softirq_cnt = cur_softirq_cnt;
+		if (!(last_softirq_cnt&(last_softirq_cnt-1)))
+			pr_err("RAMSTER TESTING RRP softirq_count=%d\n",
+				last_softirq_cnt);
+	}
+	cur_preempt_cnt = preempt_count() & PREEMPT_MASK;
+	if (cur_preempt_cnt > last_preempt_cnt) {
+		last_preempt_cnt = cur_preempt_cnt;
+		if (!(last_preempt_cnt&(last_preempt_cnt-1)))
+			pr_err("RAMSTER TESTING RRP preempt_count=%d\n",
+				last_preempt_cnt);
+	}
+}
+#endif
+
+int ramster_remote_put(struct tmem_xhandle *xh, char *data, size_t size,
+				bool ephemeral, int *remotenode)
+{
+	int nodenum, ret = -1, status;
+	struct r2nm_node *node = NULL;
+	struct kvec vec[2];
+	size_t veclen = 2;
+	u32 msg_type;
+#ifdef RAMSTER_TESTING
+	struct r2net_node *nn;
+#endif
+
+	BUG_ON(size > RMSTR_R2NET_MAX_LEN);
+	xh->client_id = r2nm_this_node(); /* which node is putting */
+	vec[0].iov_len = sizeof(*xh);
+	vec[0].iov_base = xh;
+	vec[1].iov_len = size;
+	vec[1].iov_base = data;
+	node = r2net_target_node;
+	if (!node)
+		goto out;
+
+	nodenum = r2net_target_nodenum;
+
+	r2nm_node_get(node);
+
+#ifdef RAMSTER_TESTING
+	nn = r2net_nn_from_num(nodenum);
+	WARN_ON_ONCE(nn->nn_persistent_error || !nn->nn_sc_valid);
+#endif
+
+	if (ephemeral)
+		msg_type = RMSTR_TMEM_PUT_EPH;
+	else
+		msg_type = RMSTR_TMEM_PUT_PERS;
+#ifdef RAMSTER_TESTING
+	/* leave me here to see if it catches a weird crash */
+	ramster_check_irq_counts();
+#endif
+
+	ret = r2net_send_message_vec(msg_type, RMSTR_KEY, vec, veclen,
+						nodenum, &status);
+#ifdef RAMSTER_TESTING
+	if (ret != 0) {
+		static unsigned long cnt;
+		cnt++;
+		if (!(cnt&(cnt-1)))
+			pr_err("ramster_remote_put: message failed, "
+				"ret=%d, cnt=%lu\n", ret, cnt);
+		ret = -1;
+	}
+#endif
+	if (ret < 0)
+		ret = -1;
+	else {
+		ret = status;
+		*remotenode = nodenum;
+	}
+
+	r2nm_node_put(node);
+out:
+	return ret;
+}
+
+int ramster_remote_flush(struct tmem_xhandle *xh, int remotenode)
+{
+	int ret = -1, status;
+	struct r2nm_node *node = NULL;
+	struct kvec vec[1];
+	size_t veclen = 1;
+
+	node = r2nm_get_node_by_num(remotenode);
+	BUG_ON(node == NULL);
+	xh->client_id = r2nm_this_node(); /* which node is flushing */
+	vec[0].iov_len = sizeof(*xh);
+	vec[0].iov_base = xh;
+	BUG_ON(irqs_disabled());
+	BUG_ON(in_softirq());
+	ret = r2net_send_message_vec(RMSTR_TMEM_FLUSH, RMSTR_KEY,
+					vec, veclen, remotenode, &status);
+	r2nm_node_put(node);
+	return ret;
+}
+
+int ramster_remote_flush_object(struct tmem_xhandle *xh, int remotenode)
+{
+	int ret = -1, status;
+	struct r2nm_node *node = NULL;
+	struct kvec vec[1];
+	size_t veclen = 1;
+
+	node = r2nm_get_node_by_num(remotenode);
+	BUG_ON(node == NULL);
+	xh->client_id = r2nm_this_node(); /* which node is flobjing */
+	vec[0].iov_len = sizeof(*xh);
+	vec[0].iov_base = xh;
+	ret = r2net_send_message_vec(RMSTR_TMEM_FLOBJ, RMSTR_KEY,
+					vec, veclen, remotenode, &status);
+	r2nm_node_put(node);
+	return ret;
+}
+
+/*
+ * Handler registration
+ */
+
+static LIST_HEAD(r2net_unreg_list);
+
+static void r2net_unregister_handlers(void)
+{
+	r2net_unregister_handler_list(&r2net_unreg_list);
+}
+
+int r2net_register_handlers(void)
+{
+	int status;
+
+	status = r2net_register_handler(RMSTR_TMEM_PUT_EPH, RMSTR_KEY,
+				RMSTR_R2NET_MAX_LEN,
+				ramster_remote_put_handler,
+				NULL, NULL, &r2net_unreg_list);
+	if (status)
+		goto bail;
+
+	status = r2net_register_handler(RMSTR_TMEM_PUT_PERS, RMSTR_KEY,
+				RMSTR_R2NET_MAX_LEN,
+				ramster_remote_put_handler,
+				NULL, NULL, &r2net_unreg_list);
+	if (status)
+		goto bail;
+
+	status = r2net_register_handler(RMSTR_TMEM_ASYNC_GET_REQUEST, RMSTR_KEY,
+				RMSTR_R2NET_MAX_LEN,
+				ramster_remote_async_get_request_handler,
+				NULL, NULL,
+				&r2net_unreg_list);
+	if (status)
+		goto bail;
+
+	status = r2net_register_handler(RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST,
+				RMSTR_KEY, RMSTR_R2NET_MAX_LEN,
+				ramster_remote_async_get_request_handler,
+				NULL, NULL,
+				&r2net_unreg_list);
+	if (status)
+		goto bail;
+
+	status = r2net_register_handler(RMSTR_TMEM_ASYNC_GET_REPLY, RMSTR_KEY,
+				RMSTR_R2NET_MAX_LEN,
+				ramster_remote_async_get_reply_handler,
+				NULL, NULL,
+				&r2net_unreg_list);
+	if (status)
+		goto bail;
+
+	status = r2net_register_handler(RMSTR_TMEM_FLUSH, RMSTR_KEY,
+				RMSTR_R2NET_MAX_LEN,
+				ramster_remote_flush_handler,
+				NULL, NULL,
+				&r2net_unreg_list);
+	if (status)
+		goto bail;
+
+	status = r2net_register_handler(RMSTR_TMEM_FLOBJ, RMSTR_KEY,
+				RMSTR_R2NET_MAX_LEN,
+				ramster_remote_flobj_handler,
+				NULL, NULL,
+				&r2net_unreg_list);
+	if (status)
+		goto bail;
+
+	pr_info("ramster: r2net handlers registered\n");
+
+bail:
+	if (status) {
+		r2net_unregister_handlers();
+		pr_err("ramster: couldn't register r2net handlers\n");
+	}
+	return status;
+}
diff --git a/drivers/staging/ramster/ramster.h b/drivers/staging/ramster/ramster.h
new file mode 100644
index 0000000..0c9455e
--- /dev/null
+++ b/drivers/staging/ramster/ramster.h
@@ -0,0 +1,118 @@
+/*
+ * ramster.h
+ *
+ * Peer-to-peer transcendent memory
+ *
+ * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp.
+ */
+
+#ifndef _RAMSTER_H_
+#define _RAMSTER_H_
+
+/*
+ * format of remote pampd:
+ *   bit 0 == intransit
+ *   bit 1 == is_remote... if this bit is set, then
+ *   bit 2-9 == remotenode
+ *   bit 10-22 == size
+ *   bit 23-30 == cksum
+ */
+#define FAKE_PAMPD_INTRANSIT_BITS	1
+#define FAKE_PAMPD_ISREMOTE_BITS	1
+#define FAKE_PAMPD_REMOTENODE_BITS	8
+#define FAKE_PAMPD_REMOTESIZE_BITS	13
+#define FAKE_PAMPD_CHECKSUM_BITS	8
+
+#define FAKE_PAMPD_INTRANSIT_SHIFT	0
+#define FAKE_PAMPD_ISREMOTE_SHIFT	(FAKE_PAMPD_INTRANSIT_SHIFT + \
+					 FAKE_PAMPD_INTRANSIT_BITS)
+#define FAKE_PAMPD_REMOTENODE_SHIFT	(FAKE_PAMPD_ISREMOTE_SHIFT + \
+					 FAKE_PAMPD_ISREMOTE_BITS)
+#define FAKE_PAMPD_REMOTESIZE_SHIFT	(FAKE_PAMPD_REMOTENODE_SHIFT + \
+					 FAKE_PAMPD_REMOTENODE_BITS)
+#define FAKE_PAMPD_CHECKSUM_SHIFT	(FAKE_PAMPD_REMOTESIZE_SHIFT + \
+					 FAKE_PAMPD_REMOTESIZE_BITS)
+
+#define FAKE_PAMPD_MASK(x)		((1UL << (x)) - 1)
+
+static inline void *pampd_make_remote(int remotenode, size_t size,
+					unsigned char cksum)
+{
+	unsigned long fake_pampd = 0;
+	fake_pampd |= 1UL << FAKE_PAMPD_ISREMOTE_SHIFT;
+	fake_pampd |= ((unsigned long)remotenode &
+			FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTENODE_BITS)) <<
+				FAKE_PAMPD_REMOTENODE_SHIFT;
+	fake_pampd |= ((unsigned long)size &
+			FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTESIZE_BITS)) <<
+				FAKE_PAMPD_REMOTESIZE_SHIFT;
+	fake_pampd |= ((unsigned long)cksum &
+			FAKE_PAMPD_MASK(FAKE_PAMPD_CHECKSUM_BITS)) <<
+				FAKE_PAMPD_CHECKSUM_SHIFT;
+	return (void *)fake_pampd;
+}
+
+static inline unsigned int pampd_remote_node(void *pampd)
+{
+	unsigned long fake_pampd = (unsigned long)pampd;
+	return (fake_pampd >> FAKE_PAMPD_REMOTENODE_SHIFT) &
+		FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTENODE_BITS);
+}
+
+static inline unsigned int pampd_remote_size(void *pampd)
+{
+	unsigned long fake_pampd = (unsigned long)pampd;
+	return (fake_pampd >> FAKE_PAMPD_REMOTESIZE_SHIFT) &
+		FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTESIZE_BITS);
+}
+
+static inline unsigned char pampd_remote_cksum(void *pampd)
+{
+	unsigned long fake_pampd = (unsigned long)pampd;
+	return (fake_pampd >> FAKE_PAMPD_CHECKSUM_SHIFT) &
+		FAKE_PAMPD_MASK(FAKE_PAMPD_CHECKSUM_BITS);
+}
+
+static inline bool pampd_is_remote(void *pampd)
+{
+	unsigned long fake_pampd = (unsigned long)pampd;
+	return (fake_pampd >> FAKE_PAMPD_ISREMOTE_SHIFT) &
+		FAKE_PAMPD_MASK(FAKE_PAMPD_ISREMOTE_BITS);
+}
+
+static inline bool pampd_is_intransit(void *pampd)
+{
+	unsigned long fake_pampd = (unsigned long)pampd;
+	return (fake_pampd >> FAKE_PAMPD_INTRANSIT_SHIFT) &
+		FAKE_PAMPD_MASK(FAKE_PAMPD_INTRANSIT_BITS);
+}
+
+/* note that it is a BUG for intransit to be set without isremote also set */
+static inline void *pampd_mark_intransit(void *pampd)
+{
+	unsigned long fake_pampd = (unsigned long)pampd;
+
+	fake_pampd |= 1UL << FAKE_PAMPD_ISREMOTE_SHIFT;
+	fake_pampd |= 1UL << FAKE_PAMPD_INTRANSIT_SHIFT;
+	return (void *)fake_pampd;
+}
+
+static inline void *pampd_mask_intransit_and_remote(void *marked_pampd)
+{
+	unsigned long pampd = (unsigned long)marked_pampd;
+
+	pampd &= ~(1UL << FAKE_PAMPD_INTRANSIT_SHIFT);
+	pampd &= ~(1UL << FAKE_PAMPD_ISREMOTE_SHIFT);
+	return (void *)pampd;
+}
+
+extern int ramster_remote_async_get(struct tmem_xhandle *,
+				bool, int, size_t, uint8_t, void *extra);
+extern int ramster_remote_put(struct tmem_xhandle *, char *, size_t,
+				bool, int *);
+extern int ramster_remote_flush(struct tmem_xhandle *, int);
+extern int ramster_remote_flush_object(struct tmem_xhandle *, int);
+extern int r2net_register_handlers(void);
+extern int r2net_remote_target_node_set(int);
+
+#endif /* _TMEM_H */
diff --git a/drivers/staging/ramster/tmem.c b/drivers/staging/ramster/tmem.c
new file mode 100644
index 0000000..8f2f689
--- /dev/null
+++ b/drivers/staging/ramster/tmem.c
@@ -0,0 +1,851 @@
+/*
+ * In-kernel transcendent memory (generic implementation)
+ *
+ * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp.
+ *
+ * The primary purpose of Transcedent Memory ("tmem") is to map object-oriented
+ * "handles" (triples containing a pool id, and object id, and an index), to
+ * pages in a page-accessible memory (PAM).  Tmem references the PAM pages via
+ * an abstract "pampd" (PAM page-descriptor), which can be operated on by a
+ * set of functions (pamops).  Each pampd contains some representation of
+ * PAGE_SIZE bytes worth of data. Tmem must support potentially millions of
+ * pages and must be able to insert, find, and delete these pages at a
+ * potential frequency of thousands per second concurrently across many CPUs,
+ * (and, if used with KVM, across many vcpus across many guests).
+ * Tmem is tracked with a hierarchy of data structures, organized by
+ * the elements in a handle-tuple: pool_id, object_id, and page index.
+ * One or more "clients" (e.g. guests) each provide one or more tmem_pools.
+ * Each pool, contains a hash table of rb_trees of tmem_objs.  Each
+ * tmem_obj contains a radix-tree-like tree of pointers, with intermediate
+ * nodes called tmem_objnodes.  Each leaf pointer in this tree points to
+ * a pampd, which is accessible only through a small set of callbacks
+ * registered by the PAM implementation (see tmem_register_pamops). Tmem
+ * does all memory allocation via a set of callbacks registered by the tmem
+ * host implementation (e.g. see tmem_register_hostops).
+ */
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/atomic.h>
+#include <linux/delay.h>
+
+#include "tmem.h"
+
+/* data structure sentinels used for debugging... see tmem.h */
+#define POOL_SENTINEL 0x87658765
+#define OBJ_SENTINEL 0x12345678
+#define OBJNODE_SENTINEL 0xfedcba09
+
+/*
+ * A tmem host implementation must use this function to register callbacks
+ * for memory allocation.
+ */
+static struct tmem_hostops tmem_hostops;
+
+static void tmem_objnode_tree_init(void);
+
+void tmem_register_hostops(struct tmem_hostops *m)
+{
+	tmem_objnode_tree_init();
+	tmem_hostops = *m;
+}
+
+/*
+ * A tmem host implementation must use this function to register
+ * callbacks for a page-accessible memory (PAM) implementation
+ */
+static struct tmem_pamops tmem_pamops;
+
+void tmem_register_pamops(struct tmem_pamops *m)
+{
+	tmem_pamops = *m;
+}
+
+/*
+ * Oid's are potentially very sparse and tmem_objs may have an indeterminately
+ * short life, being added and deleted at a relatively high frequency.
+ * So an rb_tree is an ideal data structure to manage tmem_objs.  But because
+ * of the potentially huge number of tmem_objs, each pool manages a hashtable
+ * of rb_trees to reduce search, insert, delete, and rebalancing time.
+ * Each hashbucket also has a lock to manage concurrent access.
+ *
+ * The following routines manage tmem_objs.  When any tmem_obj is accessed,
+ * the hashbucket lock must be held.
+ */
+
+/* searches for object==oid in pool, returns locked object if found */
+static struct tmem_obj *tmem_obj_find(struct tmem_hashbucket *hb,
+					struct tmem_oid *oidp)
+{
+	struct rb_node *rbnode;
+	struct tmem_obj *obj;
+
+	rbnode = hb->obj_rb_root.rb_node;
+	while (rbnode) {
+		BUG_ON(RB_EMPTY_NODE(rbnode));
+		obj = rb_entry(rbnode, struct tmem_obj, rb_tree_node);
+		switch (tmem_oid_compare(oidp, &obj->oid)) {
+		case 0: /* equal */
+			goto out;
+		case -1:
+			rbnode = rbnode->rb_left;
+			break;
+		case 1:
+			rbnode = rbnode->rb_right;
+			break;
+		}
+	}
+	obj = NULL;
+out:
+	return obj;
+}
+
+static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *);
+
+/* free an object that has no more pampds in it */
+static void tmem_obj_free(struct tmem_obj *obj, struct tmem_hashbucket *hb)
+{
+	struct tmem_pool *pool;
+
+	BUG_ON(obj == NULL);
+	ASSERT_SENTINEL(obj, OBJ);
+	BUG_ON(obj->pampd_count > 0);
+	pool = obj->pool;
+	BUG_ON(pool == NULL);
+	if (obj->objnode_tree_root != NULL) /* may be "stump" with no leaves */
+		tmem_pampd_destroy_all_in_obj(obj);
+	BUG_ON(obj->objnode_tree_root != NULL);
+	BUG_ON((long)obj->objnode_count != 0);
+	atomic_dec(&pool->obj_count);
+	BUG_ON(atomic_read(&pool->obj_count) < 0);
+	INVERT_SENTINEL(obj, OBJ);
+	obj->pool = NULL;
+	tmem_oid_set_invalid(&obj->oid);
+	rb_erase(&obj->rb_tree_node, &hb->obj_rb_root);
+}
+
+/*
+ * initialize, and insert an tmem_object_root (called only if find failed)
+ */
+static void tmem_obj_init(struct tmem_obj *obj, struct tmem_hashbucket *hb,
+					struct tmem_pool *pool,
+					struct tmem_oid *oidp)
+{
+	struct rb_root *root = &hb->obj_rb_root;
+	struct rb_node **new = &(root->rb_node), *parent = NULL;
+	struct tmem_obj *this;
+
+	BUG_ON(pool == NULL);
+	atomic_inc(&pool->obj_count);
+	obj->objnode_tree_height = 0;
+	obj->objnode_tree_root = NULL;
+	obj->pool = pool;
+	obj->oid = *oidp;
+	obj->objnode_count = 0;
+	obj->pampd_count = 0;
+	(*tmem_pamops.new_obj)(obj);
+	SET_SENTINEL(obj, OBJ);
+	while (*new) {
+		BUG_ON(RB_EMPTY_NODE(*new));
+		this = rb_entry(*new, struct tmem_obj, rb_tree_node);
+		parent = *new;
+		switch (tmem_oid_compare(oidp, &this->oid)) {
+		case 0:
+			BUG(); /* already present; should never happen! */
+			break;
+		case -1:
+			new = &(*new)->rb_left;
+			break;
+		case 1:
+			new = &(*new)->rb_right;
+			break;
+		}
+	}
+	rb_link_node(&obj->rb_tree_node, parent, new);
+	rb_insert_color(&obj->rb_tree_node, root);
+}
+
+/*
+ * Tmem is managed as a set of tmem_pools with certain attributes, such as
+ * "ephemeral" vs "persistent".  These attributes apply to all tmem_objs
+ * and all pampds that belong to a tmem_pool.  A tmem_pool is created
+ * or deleted relatively rarely (for example, when a filesystem is
+ * mounted or unmounted.
+ */
+
+/* flush all data from a pool and, optionally, free it */
+static void tmem_pool_flush(struct tmem_pool *pool, bool destroy)
+{
+	struct rb_node *rbnode;
+	struct tmem_obj *obj;
+	struct tmem_hashbucket *hb = &pool->hashbucket[0];
+	int i;
+
+	BUG_ON(pool == NULL);
+	for (i = 0; i < TMEM_HASH_BUCKETS; i++, hb++) {
+		spin_lock(&hb->lock);
+		rbnode = rb_first(&hb->obj_rb_root);
+		while (rbnode != NULL) {
+			obj = rb_entry(rbnode, struct tmem_obj, rb_tree_node);
+			rbnode = rb_next(rbnode);
+			tmem_pampd_destroy_all_in_obj(obj);
+			tmem_obj_free(obj, hb);
+			(*tmem_hostops.obj_free)(obj, pool);
+		}
+		spin_unlock(&hb->lock);
+	}
+	if (destroy)
+		list_del(&pool->pool_list);
+}
+
+/*
+ * A tmem_obj contains a radix-tree-like tree in which the intermediate
+ * nodes are called tmem_objnodes.  (The kernel lib/radix-tree.c implementation
+ * is very specialized and tuned for specific uses and is not particularly
+ * suited for use from this code, though some code from the core algorithms has
+ * been reused, thus the copyright notices below).  Each tmem_objnode contains
+ * a set of pointers which point to either a set of intermediate tmem_objnodes
+ * or a set of of pampds.
+ *
+ * Portions Copyright (C) 2001 Momchil Velikov
+ * Portions Copyright (C) 2001 Christoph Hellwig
+ * Portions Copyright (C) 2005 SGI, Christoph Lameter <clameter@sgi.com>
+ */
+
+struct tmem_objnode_tree_path {
+	struct tmem_objnode *objnode;
+	int offset;
+};
+
+/* objnode height_to_maxindex translation */
+static unsigned long tmem_objnode_tree_h2max[OBJNODE_TREE_MAX_PATH + 1];
+
+static void tmem_objnode_tree_init(void)
+{
+	unsigned int ht, tmp;
+
+	for (ht = 0; ht < ARRAY_SIZE(tmem_objnode_tree_h2max); ht++) {
+		tmp = ht * OBJNODE_TREE_MAP_SHIFT;
+		if (tmp >= OBJNODE_TREE_INDEX_BITS)
+			tmem_objnode_tree_h2max[ht] = ~0UL;
+		else
+			tmem_objnode_tree_h2max[ht] =
+			    (~0UL >> (OBJNODE_TREE_INDEX_BITS - tmp - 1)) >> 1;
+	}
+}
+
+static struct tmem_objnode *tmem_objnode_alloc(struct tmem_obj *obj)
+{
+	struct tmem_objnode *objnode;
+
+	ASSERT_SENTINEL(obj, OBJ);
+	BUG_ON(obj->pool == NULL);
+	ASSERT_SENTINEL(obj->pool, POOL);
+	objnode = (*tmem_hostops.objnode_alloc)(obj->pool);
+	if (unlikely(objnode == NULL))
+		goto out;
+	objnode->obj = obj;
+	SET_SENTINEL(objnode, OBJNODE);
+	memset(&objnode->slots, 0, sizeof(objnode->slots));
+	objnode->slots_in_use = 0;
+	obj->objnode_count++;
+out:
+	return objnode;
+}
+
+static void tmem_objnode_free(struct tmem_objnode *objnode)
+{
+	struct tmem_pool *pool;
+	int i;
+
+	BUG_ON(objnode == NULL);
+	for (i = 0; i < OBJNODE_TREE_MAP_SIZE; i++)
+		BUG_ON(objnode->slots[i] != NULL);
+	ASSERT_SENTINEL(objnode, OBJNODE);
+	INVERT_SENTINEL(objnode, OBJNODE);
+	BUG_ON(objnode->obj == NULL);
+	ASSERT_SENTINEL(objnode->obj, OBJ);
+	pool = objnode->obj->pool;
+	BUG_ON(pool == NULL);
+	ASSERT_SENTINEL(pool, POOL);
+	objnode->obj->objnode_count--;
+	objnode->obj = NULL;
+	(*tmem_hostops.objnode_free)(objnode, pool);
+}
+
+/*
+ * lookup index in object and return associated pampd (or NULL if not found)
+ */
+static void **__tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index)
+{
+	unsigned int height, shift;
+	struct tmem_objnode **slot = NULL;
+
+	BUG_ON(obj == NULL);
+	ASSERT_SENTINEL(obj, OBJ);
+	BUG_ON(obj->pool == NULL);
+	ASSERT_SENTINEL(obj->pool, POOL);
+
+	height = obj->objnode_tree_height;
+	if (index > tmem_objnode_tree_h2max[obj->objnode_tree_height])
+		goto out;
+	if (height == 0 && obj->objnode_tree_root) {
+		slot = &obj->objnode_tree_root;
+		goto out;
+	}
+	shift = (height-1) * OBJNODE_TREE_MAP_SHIFT;
+	slot = &obj->objnode_tree_root;
+	while (height > 0) {
+		if (*slot == NULL)
+			goto out;
+		slot = (struct tmem_objnode **)
+			((*slot)->slots +
+			 ((index >> shift) & OBJNODE_TREE_MAP_MASK));
+		shift -= OBJNODE_TREE_MAP_SHIFT;
+		height--;
+	}
+out:
+	return slot != NULL ? (void **)slot : NULL;
+}
+
+static void *tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index)
+{
+	struct tmem_objnode **slot;
+
+	slot = (struct tmem_objnode **)__tmem_pampd_lookup_in_obj(obj, index);
+	return slot != NULL ? *slot : NULL;
+}
+
+static void *tmem_pampd_replace_in_obj(struct tmem_obj *obj, uint32_t index,
+					void *new_pampd, bool no_free)
+{
+	struct tmem_objnode **slot;
+	void *ret = NULL;
+
+	slot = (struct tmem_objnode **)__tmem_pampd_lookup_in_obj(obj, index);
+	if ((slot != NULL) && (*slot != NULL)) {
+		void *old_pampd = *(void **)slot;
+		*(void **)slot = new_pampd;
+		if (!no_free)
+			(*tmem_pamops.free)(old_pampd, obj->pool,
+						NULL, 0, false);
+		ret = new_pampd;
+	}
+	return ret;
+}
+
+static int tmem_pampd_add_to_obj(struct tmem_obj *obj, uint32_t index,
+					void *pampd)
+{
+	int ret = 0;
+	struct tmem_objnode *objnode = NULL, *newnode, *slot;
+	unsigned int height, shift;
+	int offset = 0;
+
+	/* if necessary, extend the tree to be higher  */
+	if (index > tmem_objnode_tree_h2max[obj->objnode_tree_height]) {
+		height = obj->objnode_tree_height + 1;
+		if (index > tmem_objnode_tree_h2max[height])
+			while (index > tmem_objnode_tree_h2max[height])
+				height++;
+		if (obj->objnode_tree_root == NULL) {
+			obj->objnode_tree_height = height;
+			goto insert;
+		}
+		do {
+			newnode = tmem_objnode_alloc(obj);
+			if (!newnode) {
+				ret = -ENOMEM;
+				goto out;
+			}
+			newnode->slots[0] = obj->objnode_tree_root;
+			newnode->slots_in_use = 1;
+			obj->objnode_tree_root = newnode;
+			obj->objnode_tree_height++;
+		} while (height > obj->objnode_tree_height);
+	}
+insert:
+	slot = obj->objnode_tree_root;
+	height = obj->objnode_tree_height;
+	shift = (height-1) * OBJNODE_TREE_MAP_SHIFT;
+	while (height > 0) {
+		if (slot == NULL) {
+			/* add a child objnode.  */
+			slot = tmem_objnode_alloc(obj);
+			if (!slot) {
+				ret = -ENOMEM;
+				goto out;
+			}
+			if (objnode) {
+
+				objnode->slots[offset] = slot;
+				objnode->slots_in_use++;
+			} else
+				obj->objnode_tree_root = slot;
+		}
+		/* go down a level */
+		offset = (index >> shift) & OBJNODE_TREE_MAP_MASK;
+		objnode = slot;
+		slot = objnode->slots[offset];
+		shift -= OBJNODE_TREE_MAP_SHIFT;
+		height--;
+	}
+	BUG_ON(slot != NULL);
+	if (objnode) {
+		objnode->slots_in_use++;
+		objnode->slots[offset] = pampd;
+	} else
+		obj->objnode_tree_root = pampd;
+	obj->pampd_count++;
+out:
+	return ret;
+}
+
+static void *tmem_pampd_delete_from_obj(struct tmem_obj *obj, uint32_t index)
+{
+	struct tmem_objnode_tree_path path[OBJNODE_TREE_MAX_PATH + 1];
+	struct tmem_objnode_tree_path *pathp = path;
+	struct tmem_objnode *slot = NULL;
+	unsigned int height, shift;
+	int offset;
+
+	BUG_ON(obj == NULL);
+	ASSERT_SENTINEL(obj, OBJ);
+	BUG_ON(obj->pool == NULL);
+	ASSERT_SENTINEL(obj->pool, POOL);
+	height = obj->objnode_tree_height;
+	if (index > tmem_objnode_tree_h2max[height])
+		goto out;
+	slot = obj->objnode_tree_root;
+	if (height == 0 && obj->objnode_tree_root) {
+		obj->objnode_tree_root = NULL;
+		goto out;
+	}
+	shift = (height - 1) * OBJNODE_TREE_MAP_SHIFT;
+	pathp->objnode = NULL;
+	do {
+		if (slot == NULL)
+			goto out;
+		pathp++;
+		offset = (index >> shift) & OBJNODE_TREE_MAP_MASK;
+		pathp->offset = offset;
+		pathp->objnode = slot;
+		slot = slot->slots[offset];
+		shift -= OBJNODE_TREE_MAP_SHIFT;
+		height--;
+	} while (height > 0);
+	if (slot == NULL)
+		goto out;
+	while (pathp->objnode) {
+		pathp->objnode->slots[pathp->offset] = NULL;
+		pathp->objnode->slots_in_use--;
+		if (pathp->objnode->slots_in_use) {
+			if (pathp->objnode == obj->objnode_tree_root) {
+				while (obj->objnode_tree_height > 0 &&
+				  obj->objnode_tree_root->slots_in_use == 1 &&
+				  obj->objnode_tree_root->slots[0]) {
+					struct tmem_objnode *to_free =
+						obj->objnode_tree_root;
+
+					obj->objnode_tree_root =
+							to_free->slots[0];
+					obj->objnode_tree_height--;
+					to_free->slots[0] = NULL;
+					to_free->slots_in_use = 0;
+					tmem_objnode_free(to_free);
+				}
+			}
+			goto out;
+		}
+		tmem_objnode_free(pathp->objnode); /* 0 slots used, free it */
+		pathp--;
+	}
+	obj->objnode_tree_height = 0;
+	obj->objnode_tree_root = NULL;
+
+out:
+	if (slot != NULL)
+		obj->pampd_count--;
+	BUG_ON(obj->pampd_count < 0);
+	return slot;
+}
+
+/* recursively walk the objnode_tree destroying pampds and objnodes */
+static void tmem_objnode_node_destroy(struct tmem_obj *obj,
+					struct tmem_objnode *objnode,
+					unsigned int ht)
+{
+	int i;
+
+	if (ht == 0)
+		return;
+	for (i = 0; i < OBJNODE_TREE_MAP_SIZE; i++) {
+		if (objnode->slots[i]) {
+			if (ht == 1) {
+				obj->pampd_count--;
+				(*tmem_pamops.free)(objnode->slots[i],
+						obj->pool, NULL, 0, true);
+				objnode->slots[i] = NULL;
+				continue;
+			}
+			tmem_objnode_node_destroy(obj, objnode->slots[i], ht-1);
+			tmem_objnode_free(objnode->slots[i]);
+			objnode->slots[i] = NULL;
+		}
+	}
+}
+
+static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *obj)
+{
+	if (obj->objnode_tree_root == NULL)
+		return;
+	if (obj->objnode_tree_height == 0) {
+		obj->pampd_count--;
+		(*tmem_pamops.free)(obj->objnode_tree_root,
+					obj->pool, NULL, 0, true);
+	} else {
+		tmem_objnode_node_destroy(obj, obj->objnode_tree_root,
+					obj->objnode_tree_height);
+		tmem_objnode_free(obj->objnode_tree_root);
+		obj->objnode_tree_height = 0;
+	}
+	obj->objnode_tree_root = NULL;
+	(*tmem_pamops.free_obj)(obj->pool, obj);
+}
+
+/*
+ * Tmem is operated on by a set of well-defined actions:
+ * "put", "get", "flush", "flush_object", "new pool" and "destroy pool".
+ * (The tmem ABI allows for subpages and exchanges but these operations
+ * are not included in this implementation.)
+ *
+ * These "tmem core" operations are implemented in the following functions.
+ */
+
+/*
+ * "Put" a page, e.g. copy a page from the kernel into newly allocated
+ * PAM space (if such space is available).  Tmem_put is complicated by
+ * a corner case: What if a page with matching handle already exists in
+ * tmem?  To guarantee coherency, one of two actions is necessary: Either
+ * the data for the page must be overwritten, or the page must be
+ * "flushed" so that the data is not accessible to a subsequent "get".
+ * Since these "duplicate puts" are relatively rare, this implementation
+ * always flushes for simplicity.
+ */
+int tmem_put(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index,
+		char *data, size_t size, bool raw, int ephemeral)
+{
+	struct tmem_obj *obj = NULL, *objfound = NULL, *objnew = NULL;
+	void *pampd = NULL, *pampd_del = NULL;
+	int ret = -ENOMEM;
+	struct tmem_hashbucket *hb;
+
+	hb = &pool->hashbucket[tmem_oid_hash(oidp)];
+	spin_lock(&hb->lock);
+	obj = objfound = tmem_obj_find(hb, oidp);
+	if (obj != NULL) {
+		pampd = tmem_pampd_lookup_in_obj(objfound, index);
+		if (pampd != NULL) {
+			/* if found, is a dup put, flush the old one */
+			pampd_del = tmem_pampd_delete_from_obj(obj, index);
+			BUG_ON(pampd_del != pampd);
+			(*tmem_pamops.free)(pampd, pool, oidp, index, true);
+			if (obj->pampd_count == 0) {
+				objnew = obj;
+				objfound = NULL;
+			}
+			pampd = NULL;
+		}
+	} else {
+		obj = objnew = (*tmem_hostops.obj_alloc)(pool);
+		if (unlikely(obj == NULL)) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		tmem_obj_init(obj, hb, pool, oidp);
+	}
+	BUG_ON(obj == NULL);
+	BUG_ON(((objnew != obj) && (objfound != obj)) || (objnew == objfound));
+	pampd = (*tmem_pamops.create)(data, size, raw, ephemeral,
+					obj->pool, &obj->oid, index);
+	if (unlikely(pampd == NULL))
+		goto free;
+	ret = tmem_pampd_add_to_obj(obj, index, pampd);
+	if (unlikely(ret == -ENOMEM))
+		/* may have partially built objnode tree ("stump") */
+		goto delete_and_free;
+	goto out;
+
+delete_and_free:
+	(void)tmem_pampd_delete_from_obj(obj, index);
+free:
+	if (pampd)
+		(*tmem_pamops.free)(pampd, pool, NULL, 0, true);
+	if (objnew) {
+		tmem_obj_free(objnew, hb);
+		(*tmem_hostops.obj_free)(objnew, pool);
+	}
+out:
+	spin_unlock(&hb->lock);
+	return ret;
+}
+
+void *tmem_localify_get_pampd(struct tmem_pool *pool, struct tmem_oid *oidp,
+				uint32_t index, struct tmem_obj **ret_obj,
+				void **saved_hb)
+{
+	struct tmem_hashbucket *hb;
+	struct tmem_obj *obj = NULL;
+	void *pampd = NULL;
+
+	hb = &pool->hashbucket[tmem_oid_hash(oidp)];
+	spin_lock(&hb->lock);
+	obj = tmem_obj_find(hb, oidp);
+	if (likely(obj != NULL))
+		pampd = tmem_pampd_lookup_in_obj(obj, index);
+	*ret_obj = obj;
+	*saved_hb = (void *)hb;
+	/* note, hashbucket remains locked */
+	return pampd;
+}
+
+void tmem_localify_finish(struct tmem_obj *obj, uint32_t index,
+			  void *pampd, void *saved_hb, bool delete)
+{
+	struct tmem_hashbucket *hb = (struct tmem_hashbucket *)saved_hb;
+
+	BUG_ON(!spin_is_locked(&hb->lock));
+	if (pampd != NULL) {
+		BUG_ON(obj == NULL);
+		(void)tmem_pampd_replace_in_obj(obj, index, pampd, 1);
+	} else if (delete) {
+		BUG_ON(obj == NULL);
+		(void)tmem_pampd_delete_from_obj(obj, index);
+	}
+	spin_unlock(&hb->lock);
+}
+
+static int tmem_repatriate(void **ppampd, struct tmem_hashbucket *hb,
+				struct tmem_pool *pool, struct tmem_oid *oidp,
+				uint32_t index, bool free, char *data)
+{
+	void *old_pampd = *ppampd, *new_pampd = NULL;
+	bool intransit = false;
+	int ret = 0;
+
+
+	if (!is_ephemeral(pool))
+		new_pampd = (*tmem_pamops.repatriate_preload)(
+				old_pampd, pool, oidp, index, &intransit);
+	if (intransit)
+		ret = -EAGAIN;
+	else if (new_pampd != NULL)
+		*ppampd = new_pampd;
+	/* must release the hb->lock else repatriate can't sleep */
+	spin_unlock(&hb->lock);
+	if (!intransit)
+		ret = (*tmem_pamops.repatriate)(old_pampd, new_pampd, pool,
+						oidp, index, free, data);
+	return ret;
+}
+
+/*
+ * "Get" a page, e.g. if one can be found, copy the tmem page with the
+ * matching handle from PAM space to the kernel.  By tmem definition,
+ * when a "get" is successful on an ephemeral page, the page is "flushed",
+ * and when a "get" is successful on a persistent page, the page is retained
+ * in tmem.  Note that to preserve
+ * coherency, "get" can never be skipped if tmem contains the data.
+ * That is, if a get is done with a certain handle and fails, any
+ * subsequent "get" must also fail (unless of course there is a
+ * "put" done with the same handle).
+
+ */
+int tmem_get(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index,
+		char *data, size_t *size, bool raw, int get_and_free)
+{
+	struct tmem_obj *obj;
+	void *pampd;
+	bool ephemeral = is_ephemeral(pool);
+	int ret = -1;
+	struct tmem_hashbucket *hb;
+	bool free = (get_and_free == 1) || ((get_and_free == 0) && ephemeral);
+	bool lock_held = 0;
+	void **ppampd;
+
+again:
+	hb = &pool->hashbucket[tmem_oid_hash(oidp)];
+	spin_lock(&hb->lock);
+	lock_held = 1;
+	obj = tmem_obj_find(hb, oidp);
+	if (obj == NULL)
+		goto out;
+	ppampd = __tmem_pampd_lookup_in_obj(obj, index);
+	if (ppampd == NULL)
+		goto out;
+	if (tmem_pamops.is_remote(*ppampd)) {
+		ret = tmem_repatriate(ppampd, hb, pool, oidp,
+					index, free, data);
+		lock_held = 0; /* note hb->lock has been unlocked */
+		if (ret == -EAGAIN) {
+			/* rare I think, but should cond_resched()??? */
+			usleep_range(10, 1000);
+			goto again;
+		} else if (ret != 0) {
+			if (ret != -ENOENT)
+				pr_err("UNTESTED case in tmem_get, ret=%d\n",
+						ret);
+			ret = -1;
+			goto out;
+		}
+		goto out;
+	}
+	if (free)
+		pampd = tmem_pampd_delete_from_obj(obj, index);
+	else
+		pampd = tmem_pampd_lookup_in_obj(obj, index);
+	if (pampd == NULL)
+		goto out;
+	if (free) {
+		if (obj->pampd_count == 0) {
+			tmem_obj_free(obj, hb);
+			(*tmem_hostops.obj_free)(obj, pool);
+			obj = NULL;
+		}
+	}
+	if (free)
+		ret = (*tmem_pamops.get_data_and_free)(
+				data, size, raw, pampd, pool, oidp, index);
+	else
+		ret = (*tmem_pamops.get_data)(
+				data, size, raw, pampd, pool, oidp, index);
+	if (ret < 0)
+		goto out;
+	ret = 0;
+out:
+	if (lock_held)
+		spin_unlock(&hb->lock);
+	return ret;
+}
+
+/*
+ * If a page in tmem matches the handle, "flush" this page from tmem such
+ * that any subsequent "get" does not succeed (unless, of course, there
+ * was another "put" with the same handle).
+ */
+int tmem_flush_page(struct tmem_pool *pool,
+				struct tmem_oid *oidp, uint32_t index)
+{
+	struct tmem_obj *obj;
+	void *pampd;
+	int ret = -1;
+	struct tmem_hashbucket *hb;
+
+	hb = &pool->hashbucket[tmem_oid_hash(oidp)];
+	spin_lock(&hb->lock);
+	obj = tmem_obj_find(hb, oidp);
+	if (obj == NULL)
+		goto out;
+	pampd = tmem_pampd_delete_from_obj(obj, index);
+	if (pampd == NULL)
+		goto out;
+	(*tmem_pamops.free)(pampd, pool, oidp, index, true);
+	if (obj->pampd_count == 0) {
+		tmem_obj_free(obj, hb);
+		(*tmem_hostops.obj_free)(obj, pool);
+	}
+	ret = 0;
+
+out:
+	spin_unlock(&hb->lock);
+	return ret;
+}
+
+/*
+ * If a page in tmem matches the handle, replace the page so that any
+ * subsequent "get" gets the new page.  Returns the new page if
+ * there was a page to replace, else returns NULL.
+ */
+int tmem_replace(struct tmem_pool *pool, struct tmem_oid *oidp,
+			uint32_t index, void *new_pampd)
+{
+	struct tmem_obj *obj;
+	int ret = -1;
+	struct tmem_hashbucket *hb;
+
+	hb = &pool->hashbucket[tmem_oid_hash(oidp)];
+	spin_lock(&hb->lock);
+	obj = tmem_obj_find(hb, oidp);
+	if (obj == NULL)
+		goto out;
+	new_pampd = tmem_pampd_replace_in_obj(obj, index, new_pampd, 0);
+	ret = (*tmem_pamops.replace_in_obj)(new_pampd, obj);
+out:
+	spin_unlock(&hb->lock);
+	return ret;
+}
+
+/*
+ * "Flush" all pages in tmem matching this oid.
+ */
+int tmem_flush_object(struct tmem_pool *pool, struct tmem_oid *oidp)
+{
+	struct tmem_obj *obj;
+	struct tmem_hashbucket *hb;
+	int ret = -1;
+
+	hb = &pool->hashbucket[tmem_oid_hash(oidp)];
+	spin_lock(&hb->lock);
+	obj = tmem_obj_find(hb, oidp);
+	if (obj == NULL)
+		goto out;
+	tmem_pampd_destroy_all_in_obj(obj);
+	tmem_obj_free(obj, hb);
+	(*tmem_hostops.obj_free)(obj, pool);
+	ret = 0;
+
+out:
+	spin_unlock(&hb->lock);
+	return ret;
+}
+
+/*
+ * "Flush" all pages (and tmem_objs) from this tmem_pool and disable
+ * all subsequent access to this tmem_pool.
+ */
+int tmem_destroy_pool(struct tmem_pool *pool)
+{
+	int ret = -1;
+
+	if (pool == NULL)
+		goto out;
+	tmem_pool_flush(pool, 1);
+	ret = 0;
+out:
+	return ret;
+}
+
+static LIST_HEAD(tmem_global_pool_list);
+
+/*
+ * Create a new tmem_pool with the provided flag and return
+ * a pool id provided by the tmem host implementation.
+ */
+void tmem_new_pool(struct tmem_pool *pool, uint32_t flags)
+{
+	int persistent = flags & TMEM_POOL_PERSIST;
+	int shared = flags & TMEM_POOL_SHARED;
+	struct tmem_hashbucket *hb = &pool->hashbucket[0];
+	int i;
+
+	for (i = 0; i < TMEM_HASH_BUCKETS; i++, hb++) {
+		hb->obj_rb_root = RB_ROOT;
+		spin_lock_init(&hb->lock);
+	}
+	INIT_LIST_HEAD(&pool->pool_list);
+	atomic_set(&pool->obj_count, 0);
+	SET_SENTINEL(pool, POOL);
+	list_add_tail(&pool->pool_list, &tmem_global_pool_list);
+	pool->persistent = persistent;
+	pool->shared = shared;
+}
diff --git a/drivers/staging/ramster/tmem.h b/drivers/staging/ramster/tmem.h
new file mode 100644
index 0000000..47f1918
--- /dev/null
+++ b/drivers/staging/ramster/tmem.h
@@ -0,0 +1,244 @@
+/*
+ * tmem.h
+ *
+ * Transcendent memory
+ *
+ * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp.
+ */
+
+#ifndef _TMEM_H_
+#define _TMEM_H_
+
+#include <linux/highmem.h>
+#include <linux/hash.h>
+#include <linux/atomic.h>
+
+/*
+ * These are pre-defined by the Xen<->Linux ABI
+ */
+#define TMEM_PUT_PAGE			4
+#define TMEM_GET_PAGE			5
+#define TMEM_FLUSH_PAGE			6
+#define TMEM_FLUSH_OBJECT		7
+#define TMEM_POOL_PERSIST		1
+#define TMEM_POOL_SHARED		2
+#define TMEM_POOL_PRECOMPRESSED		4
+#define TMEM_POOL_PAGESIZE_SHIFT	4
+#define TMEM_POOL_PAGESIZE_MASK		0xf
+#define TMEM_POOL_RESERVED_BITS		0x00ffff00
+
+/*
+ * sentinels have proven very useful for debugging but can be removed
+ * or disabled before final merge.
+ */
+#define SENTINELS
+#ifdef SENTINELS
+#define DECL_SENTINEL uint32_t sentinel;
+#define SET_SENTINEL(_x, _y) (_x->sentinel = _y##_SENTINEL)
+#define INVERT_SENTINEL(_x, _y) (_x->sentinel = ~_y##_SENTINEL)
+#define ASSERT_SENTINEL(_x, _y) WARN_ON(_x->sentinel != _y##_SENTINEL)
+#define ASSERT_INVERTED_SENTINEL(_x, _y) WARN_ON(_x->sentinel != ~_y##_SENTINEL)
+#else
+#define DECL_SENTINEL
+#define SET_SENTINEL(_x, _y) do { } while (0)
+#define INVERT_SENTINEL(_x, _y) do { } while (0)
+#define ASSERT_SENTINEL(_x, _y) do { } while (0)
+#define ASSERT_INVERTED_SENTINEL(_x, _y) do { } while (0)
+#endif
+
+#define ASSERT_SPINLOCK(_l)	WARN_ON(!spin_is_locked(_l))
+
+/*
+ * A pool is the highest-level data structure managed by tmem and
+ * usually corresponds to a large independent set of pages such as
+ * a filesystem.  Each pool has an id, and certain attributes and counters.
+ * It also contains a set of hash buckets, each of which contains an rbtree
+ * of objects and a lock to manage concurrency within the pool.
+ */
+
+#define TMEM_HASH_BUCKET_BITS	8
+#define TMEM_HASH_BUCKETS	(1<<TMEM_HASH_BUCKET_BITS)
+
+struct tmem_hashbucket {
+	struct rb_root obj_rb_root;
+	spinlock_t lock;
+};
+
+struct tmem_pool {
+	void *client; /* "up" for some clients, avoids table lookup */
+	struct list_head pool_list;
+	uint32_t pool_id;
+	bool persistent;
+	bool shared;
+	atomic_t obj_count;
+	atomic_t refcount;
+	struct tmem_hashbucket hashbucket[TMEM_HASH_BUCKETS];
+	DECL_SENTINEL
+};
+
+#define is_persistent(_p)  (_p->persistent)
+#define is_ephemeral(_p)   (!(_p->persistent))
+
+/*
+ * An object id ("oid") is large: 192-bits (to ensure, for example, files
+ * in a modern filesystem can be uniquely identified).
+ */
+
+struct tmem_oid {
+	uint64_t oid[3];
+};
+
+struct tmem_xhandle {
+	uint8_t client_id;
+	uint8_t xh_data_cksum;
+	uint16_t xh_data_size;
+	uint16_t pool_id;
+	struct tmem_oid oid;
+	uint32_t index;
+	void *extra;
+};
+
+static inline struct tmem_xhandle tmem_xhandle_fill(uint16_t client_id,
+					struct tmem_pool *pool,
+					struct tmem_oid *oidp,
+					uint32_t index)
+{
+	struct tmem_xhandle xh;
+	xh.client_id = client_id;
+	xh.xh_data_cksum = (uint8_t)-1;
+	xh.xh_data_size = (uint16_t)-1;
+	xh.pool_id = pool->pool_id;
+	xh.oid = *oidp;
+	xh.index = index;
+	return xh;
+}
+
+static inline void tmem_oid_set_invalid(struct tmem_oid *oidp)
+{
+	oidp->oid[0] = oidp->oid[1] = oidp->oid[2] = -1UL;
+}
+
+static inline bool tmem_oid_valid(struct tmem_oid *oidp)
+{
+	return oidp->oid[0] != -1UL || oidp->oid[1] != -1UL ||
+		oidp->oid[2] != -1UL;
+}
+
+static inline int tmem_oid_compare(struct tmem_oid *left,
+					struct tmem_oid *right)
+{
+	int ret;
+
+	if (left->oid[2] == right->oid[2]) {
+		if (left->oid[1] == right->oid[1]) {
+			if (left->oid[0] == right->oid[0])
+				ret = 0;
+			else if (left->oid[0] < right->oid[0])
+				ret = -1;
+			else
+				return 1;
+		} else if (left->oid[1] < right->oid[1])
+			ret = -1;
+		else
+			ret = 1;
+	} else if (left->oid[2] < right->oid[2])
+		ret = -1;
+	else
+		ret = 1;
+	return ret;
+}
+
+static inline unsigned tmem_oid_hash(struct tmem_oid *oidp)
+{
+	return hash_long(oidp->oid[0] ^ oidp->oid[1] ^ oidp->oid[2],
+				TMEM_HASH_BUCKET_BITS);
+}
+
+/*
+ * A tmem_obj contains an identifier (oid), pointers to the parent
+ * pool and the rb_tree to which it belongs, counters, and an ordered
+ * set of pampds, structured in a radix-tree-like tree.  The intermediate
+ * nodes of the tree are called tmem_objnodes.
+ */
+
+struct tmem_objnode;
+
+struct tmem_obj {
+	struct tmem_oid oid;
+	struct tmem_pool *pool;
+	struct rb_node rb_tree_node;
+	struct tmem_objnode *objnode_tree_root;
+	unsigned int objnode_tree_height;
+	unsigned long objnode_count;
+	long pampd_count;
+	/* for current design of ramster, all pages belonging to
+	 * an object reside on the same remotenode and extra is
+	 * used to record the number of the remotenode so a
+	 * flush-object operation can specify it */
+	void *extra; /* for use by pampd implementation */
+	DECL_SENTINEL
+};
+
+#define OBJNODE_TREE_MAP_SHIFT 6
+#define OBJNODE_TREE_MAP_SIZE (1UL << OBJNODE_TREE_MAP_SHIFT)
+#define OBJNODE_TREE_MAP_MASK (OBJNODE_TREE_MAP_SIZE-1)
+#define OBJNODE_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long))
+#define OBJNODE_TREE_MAX_PATH \
+		(OBJNODE_TREE_INDEX_BITS/OBJNODE_TREE_MAP_SHIFT + 2)
+
+struct tmem_objnode {
+	struct tmem_obj *obj;
+	DECL_SENTINEL
+	void *slots[OBJNODE_TREE_MAP_SIZE];
+	unsigned int slots_in_use;
+};
+
+/* pampd abstract datatype methods provided by the PAM implementation */
+struct tmem_pamops {
+	void *(*create)(char *, size_t, bool, int,
+			struct tmem_pool *, struct tmem_oid *, uint32_t);
+	int (*get_data)(char *, size_t *, bool, void *, struct tmem_pool *,
+				struct tmem_oid *, uint32_t);
+	int (*get_data_and_free)(char *, size_t *, bool, void *,
+				struct tmem_pool *, struct tmem_oid *,
+				uint32_t);
+	void (*free)(void *, struct tmem_pool *,
+				struct tmem_oid *, uint32_t, bool);
+	void (*free_obj)(struct tmem_pool *, struct tmem_obj *);
+	bool (*is_remote)(void *);
+	void *(*repatriate_preload)(void *, struct tmem_pool *,
+					struct tmem_oid *, uint32_t, bool *);
+	int (*repatriate)(void *, void *, struct tmem_pool *,
+				struct tmem_oid *, uint32_t, bool, void *);
+	void (*new_obj)(struct tmem_obj *);
+	int (*replace_in_obj)(void *, struct tmem_obj *);
+};
+extern void tmem_register_pamops(struct tmem_pamops *m);
+
+/* memory allocation methods provided by the host implementation */
+struct tmem_hostops {
+	struct tmem_obj *(*obj_alloc)(struct tmem_pool *);
+	void (*obj_free)(struct tmem_obj *, struct tmem_pool *);
+	struct tmem_objnode *(*objnode_alloc)(struct tmem_pool *);
+	void (*objnode_free)(struct tmem_objnode *, struct tmem_pool *);
+};
+extern void tmem_register_hostops(struct tmem_hostops *m);
+
+/* core tmem accessor functions */
+extern int tmem_put(struct tmem_pool *, struct tmem_oid *, uint32_t index,
+			char *, size_t, bool, int);
+extern int tmem_get(struct tmem_pool *, struct tmem_oid *, uint32_t index,
+			char *, size_t *, bool, int);
+extern int tmem_replace(struct tmem_pool *, struct tmem_oid *, uint32_t index,
+			void *);
+extern void *tmem_localify_get_pampd(struct tmem_pool *, struct tmem_oid *,
+				   uint32_t index, struct tmem_obj **,
+				   void **);
+extern void tmem_localify_finish(struct tmem_obj *, uint32_t index,
+				 void *, void *, bool);
+extern int tmem_flush_page(struct tmem_pool *, struct tmem_oid *,
+			uint32_t index);
+extern int tmem_flush_object(struct tmem_pool *, struct tmem_oid *);
+extern int tmem_destroy_pool(struct tmem_pool *);
+extern void tmem_new_pool(struct tmem_pool *, uint32_t);
+#endif /* _TMEM_H */
diff --git a/drivers/staging/zram/xvmalloc.c b/drivers/staging/ramster/xvmalloc.c
similarity index 100%
rename from drivers/staging/zram/xvmalloc.c
rename to drivers/staging/ramster/xvmalloc.c
diff --git a/drivers/staging/zram/xvmalloc.h b/drivers/staging/ramster/xvmalloc.h
similarity index 100%
rename from drivers/staging/zram/xvmalloc.h
rename to drivers/staging/ramster/xvmalloc.h
diff --git a/drivers/staging/zram/xvmalloc_int.h b/drivers/staging/ramster/xvmalloc_int.h
similarity index 100%
rename from drivers/staging/zram/xvmalloc_int.h
rename to drivers/staging/ramster/xvmalloc_int.h
diff --git a/drivers/staging/ramster/zcache-main.c b/drivers/staging/ramster/zcache-main.c
new file mode 100644
index 0000000..36d53ed
--- /dev/null
+++ b/drivers/staging/ramster/zcache-main.c
@@ -0,0 +1,3320 @@
+/*
+ * zcache.c
+ *
+ * Copyright (c) 2010-2012, Dan Magenheimer, Oracle Corp.
+ * Copyright (c) 2010,2011, Nitin Gupta
+ *
+ * Zcache provides an in-kernel "host implementation" for transcendent memory
+ * and, thus indirectly, for cleancache and frontswap.  Zcache includes two
+ * page-accessible memory [1] interfaces, both utilizing lzo1x compression:
+ * 1) "compression buddies" ("zbud") is used for ephemeral pages
+ * 2) xvmalloc is used for persistent pages.
+ * Xvmalloc (based on the TLSF allocator) has very low fragmentation
+ * so maximizes space efficiency, while zbud allows pairs (and potentially,
+ * in the future, more than a pair of) compressed pages to be closely linked
+ * so that reclaiming can be done via the kernel's physical-page-oriented
+ * "shrinker" interface.
+ *
+ * [1] For a definition of page-accessible memory (aka PAM), see:
+ *   http://marc.info/?l=linux-mm&m=127811271605009
+ *  RAMSTER TODO:
+ *   - handle remotifying of buddied pages (see zbud_remotify_zbpg)
+ *   - kernel boot params: nocleancache/nofrontswap don't always work?!?
+ */
+
+#include <linux/module.h>
+#include <linux/cpu.h>
+#include <linux/highmem.h>
+#include <linux/list.h>
+#include <linux/lzo.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/atomic.h>
+#include <linux/math64.h>
+#include "tmem.h"
+#include "zcache.h"
+#include "ramster.h"
+#include "cluster/tcp.h"
+
+#include "xvmalloc.h"	/* temporary until change to zsmalloc */
+
+#define	RAMSTER_TESTING
+
+#if (!defined(CONFIG_CLEANCACHE) && !defined(CONFIG_FRONTSWAP))
+#error "ramster is useless without CONFIG_CLEANCACHE or CONFIG_FRONTSWAP"
+#endif
+#ifdef CONFIG_CLEANCACHE
+#include <linux/cleancache.h>
+#endif
+#ifdef CONFIG_FRONTSWAP
+#include <linux/frontswap.h>
+#endif
+
+enum ramster_remotify_op {
+	RAMSTER_REMOTIFY_EPH_PUT,
+	RAMSTER_REMOTIFY_PERS_PUT,
+	RAMSTER_REMOTIFY_FLUSH_PAGE,
+	RAMSTER_REMOTIFY_FLUSH_OBJ,
+	RAMSTER_INTRANSIT_PERS
+};
+
+struct ramster_remotify_hdr {
+	enum ramster_remotify_op op;
+	struct list_head list;
+};
+
+#define ZBH_SENTINEL  0x43214321
+#define ZBPG_SENTINEL  0xdeadbeef
+
+#define ZBUD_MAX_BUDS 2
+
+struct zbud_hdr {
+	struct ramster_remotify_hdr rem_op;
+	uint16_t client_id;
+	uint16_t pool_id;
+	struct tmem_oid oid;
+	uint32_t index;
+	uint16_t size; /* compressed size in bytes, zero means unused */
+	DECL_SENTINEL
+};
+
+#define ZVH_SENTINEL  0x43214321
+static const int zv_max_page_size = (PAGE_SIZE / 8) * 7;
+
+struct zv_hdr {
+	struct ramster_remotify_hdr rem_op;
+	uint16_t client_id;
+	uint16_t pool_id;
+	struct tmem_oid oid;
+	uint32_t index;
+	DECL_SENTINEL
+};
+
+struct flushlist_node {
+	struct ramster_remotify_hdr rem_op;
+	struct tmem_xhandle xh;
+};
+
+union {
+	struct ramster_remotify_hdr rem_op;
+	struct zv_hdr zv;
+	struct zbud_hdr zbud;
+	struct flushlist_node flist;
+} remotify_list_node;
+
+static LIST_HEAD(zcache_rem_op_list);
+static DEFINE_SPINLOCK(zcache_rem_op_list_lock);
+
+#if 0
+/* this is more aggressive but may cause other problems? */
+#define ZCACHE_GFP_MASK	(GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN)
+#else
+#define ZCACHE_GFP_MASK \
+	(__GFP_FS | __GFP_NORETRY | __GFP_NOWARN | __GFP_NOMEMALLOC)
+#endif
+
+#define MAX_POOLS_PER_CLIENT 16
+
+#define MAX_CLIENTS 16
+#define LOCAL_CLIENT ((uint16_t)-1)
+
+MODULE_LICENSE("GPL");
+
+struct zcache_client {
+	struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT];
+	struct xv_pool *xvpool;
+	bool allocated;
+	atomic_t refcount;
+};
+
+static struct zcache_client zcache_host;
+static struct zcache_client zcache_clients[MAX_CLIENTS];
+
+static inline uint16_t get_client_id_from_client(struct zcache_client *cli)
+{
+	BUG_ON(cli == NULL);
+	if (cli == &zcache_host)
+		return LOCAL_CLIENT;
+	return cli - &zcache_clients[0];
+}
+
+static inline bool is_local_client(struct zcache_client *cli)
+{
+	return cli == &zcache_host;
+}
+
+/**********
+ * Compression buddies ("zbud") provides for packing two (or, possibly
+ * in the future, more) compressed ephemeral pages into a single "raw"
+ * (physical) page and tracking them with data structures so that
+ * the raw pages can be easily reclaimed.
+ *
+ * A zbud page ("zbpg") is an aligned page containing a list_head,
+ * a lock, and two "zbud headers".  The remainder of the physical
+ * page is divided up into aligned 64-byte "chunks" which contain
+ * the compressed data for zero, one, or two zbuds.  Each zbpg
+ * resides on: (1) an "unused list" if it has no zbuds; (2) a
+ * "buddied" list if it is fully populated  with two zbuds; or
+ * (3) one of PAGE_SIZE/64 "unbuddied" lists indexed by how many chunks
+ * the one unbuddied zbud uses.  The data inside a zbpg cannot be
+ * read or written unless the zbpg's lock is held.
+ */
+
+struct zbud_page {
+	struct list_head bud_list;
+	spinlock_t lock;
+	struct zbud_hdr buddy[ZBUD_MAX_BUDS];
+	DECL_SENTINEL
+	/* followed by NUM_CHUNK aligned CHUNK_SIZE-byte chunks */
+};
+
+#define CHUNK_SHIFT	6
+#define CHUNK_SIZE	(1 << CHUNK_SHIFT)
+#define CHUNK_MASK	(~(CHUNK_SIZE-1))
+#define NCHUNKS		(((PAGE_SIZE - sizeof(struct zbud_page)) & \
+				CHUNK_MASK) >> CHUNK_SHIFT)
+#define MAX_CHUNK	(NCHUNKS-1)
+
+static struct {
+	struct list_head list;
+	unsigned count;
+} zbud_unbuddied[NCHUNKS];
+/* list N contains pages with N chunks USED and NCHUNKS-N unused */
+/* element 0 is never used but optimizing that isn't worth it */
+static unsigned long zbud_cumul_chunk_counts[NCHUNKS];
+
+struct list_head zbud_buddied_list;
+static unsigned long zcache_zbud_buddied_count;
+
+/* protects the buddied list and all unbuddied lists */
+static DEFINE_SPINLOCK(zbud_budlists_spinlock);
+
+static atomic_t zcache_zbud_curr_raw_pages;
+static atomic_t zcache_zbud_curr_zpages;
+static unsigned long zcache_zbud_curr_zbytes;
+static unsigned long zcache_zbud_cumul_zpages;
+static unsigned long zcache_zbud_cumul_zbytes;
+static unsigned long zcache_compress_poor;
+static unsigned long zcache_policy_percent_exceeded;
+static unsigned long zcache_mean_compress_poor;
+
+/*
+ * RAMster counters
+ * - Remote pages are pages with a local pampd but the data is remote
+ * - Foreign pages are pages stored locally but belonging to another node
+ */
+static atomic_t ramster_remote_pers_pages = ATOMIC_INIT(0);
+static unsigned long ramster_pers_remotify_enable;
+static unsigned long ramster_eph_remotify_enable;
+static unsigned long ramster_eph_pages_remoted;
+static unsigned long ramster_eph_pages_remote_failed;
+static unsigned long ramster_pers_pages_remoted;
+static unsigned long ramster_pers_pages_remote_failed;
+static unsigned long ramster_pers_pages_remote_nomem;
+static unsigned long ramster_remote_objects_flushed;
+static unsigned long ramster_remote_object_flushes_failed;
+static unsigned long ramster_remote_pages_flushed;
+static unsigned long ramster_remote_page_flushes_failed;
+static unsigned long ramster_remote_eph_pages_succ_get;
+static unsigned long ramster_remote_pers_pages_succ_get;
+static unsigned long ramster_remote_eph_pages_unsucc_get;
+static unsigned long ramster_remote_pers_pages_unsucc_get;
+static atomic_t ramster_curr_flnode_count = ATOMIC_INIT(0);
+static unsigned long ramster_curr_flnode_count_max;
+static atomic_t ramster_foreign_eph_pampd_count = ATOMIC_INIT(0);
+static unsigned long ramster_foreign_eph_pampd_count_max;
+static atomic_t ramster_foreign_pers_pampd_count = ATOMIC_INIT(0);
+static unsigned long ramster_foreign_pers_pampd_count_max;
+
+/* forward references */
+static void *zcache_get_free_page(void);
+static void zcache_free_page(void *p);
+
+/*
+ * zbud helper functions
+ */
+
+static inline unsigned zbud_max_buddy_size(void)
+{
+	return MAX_CHUNK << CHUNK_SHIFT;
+}
+
+static inline unsigned zbud_size_to_chunks(unsigned size)
+{
+	BUG_ON(size == 0 || size > zbud_max_buddy_size());
+	return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT;
+}
+
+static inline int zbud_budnum(struct zbud_hdr *zh)
+{
+	unsigned offset = (unsigned long)zh & (PAGE_SIZE - 1);
+	struct zbud_page *zbpg = NULL;
+	unsigned budnum = -1U;
+	int i;
+
+	for (i = 0; i < ZBUD_MAX_BUDS; i++)
+		if (offset == offsetof(typeof(*zbpg), buddy[i])) {
+			budnum = i;
+			break;
+		}
+	BUG_ON(budnum == -1U);
+	return budnum;
+}
+
+static char *zbud_data(struct zbud_hdr *zh, unsigned size)
+{
+	struct zbud_page *zbpg;
+	char *p;
+	unsigned budnum;
+
+	ASSERT_SENTINEL(zh, ZBH);
+	budnum = zbud_budnum(zh);
+	BUG_ON(size == 0 || size > zbud_max_buddy_size());
+	zbpg = container_of(zh, struct zbud_page, buddy[budnum]);
+	ASSERT_SPINLOCK(&zbpg->lock);
+	p = (char *)zbpg;
+	if (budnum == 0)
+		p += ((sizeof(struct zbud_page) + CHUNK_SIZE - 1) &
+							CHUNK_MASK);
+	else if (budnum == 1)
+		p += PAGE_SIZE - ((size + CHUNK_SIZE - 1) & CHUNK_MASK);
+	return p;
+}
+
+static void zbud_copy_from_pampd(char *data, size_t *size, struct zbud_hdr *zh)
+{
+	struct zbud_page *zbpg;
+	char *p;
+	unsigned budnum;
+
+	ASSERT_SENTINEL(zh, ZBH);
+	budnum = zbud_budnum(zh);
+	zbpg = container_of(zh, struct zbud_page, buddy[budnum]);
+	spin_lock(&zbpg->lock);
+	BUG_ON(zh->size > *size);
+	p = (char *)zbpg;
+	if (budnum == 0)
+		p += ((sizeof(struct zbud_page) + CHUNK_SIZE - 1) &
+							CHUNK_MASK);
+	else if (budnum == 1)
+		p += PAGE_SIZE - ((zh->size + CHUNK_SIZE - 1) & CHUNK_MASK);
+	/* client should be filled in by caller */
+	memcpy(data, p, zh->size);
+	*size = zh->size;
+	spin_unlock(&zbpg->lock);
+}
+
+/*
+ * zbud raw page management
+ */
+
+static struct zbud_page *zbud_alloc_raw_page(void)
+{
+	struct zbud_page *zbpg = NULL;
+	struct zbud_hdr *zh0, *zh1;
+		zbpg = zcache_get_free_page();
+	if (likely(zbpg != NULL)) {
+		INIT_LIST_HEAD(&zbpg->bud_list);
+		zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1];
+		spin_lock_init(&zbpg->lock);
+		atomic_inc(&zcache_zbud_curr_raw_pages);
+		INIT_LIST_HEAD(&zbpg->bud_list);
+		SET_SENTINEL(zbpg, ZBPG);
+		zh0->size = 0; zh1->size = 0;
+		tmem_oid_set_invalid(&zh0->oid);
+		tmem_oid_set_invalid(&zh1->oid);
+	}
+	return zbpg;
+}
+
+static void zbud_free_raw_page(struct zbud_page *zbpg)
+{
+	struct zbud_hdr *zh0 = &zbpg->buddy[0], *zh1 = &zbpg->buddy[1];
+
+	ASSERT_SENTINEL(zbpg, ZBPG);
+	BUG_ON(!list_empty(&zbpg->bud_list));
+	ASSERT_SPINLOCK(&zbpg->lock);
+	BUG_ON(zh0->size != 0 || tmem_oid_valid(&zh0->oid));
+	BUG_ON(zh1->size != 0 || tmem_oid_valid(&zh1->oid));
+	INVERT_SENTINEL(zbpg, ZBPG);
+	spin_unlock(&zbpg->lock);
+	atomic_dec(&zcache_zbud_curr_raw_pages);
+	zcache_free_page(zbpg);
+}
+
+/*
+ * core zbud handling routines
+ */
+
+static unsigned zbud_free(struct zbud_hdr *zh)
+{
+	unsigned size;
+
+	ASSERT_SENTINEL(zh, ZBH);
+	BUG_ON(!tmem_oid_valid(&zh->oid));
+	size = zh->size;
+	BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size());
+	zh->size = 0;
+	tmem_oid_set_invalid(&zh->oid);
+	INVERT_SENTINEL(zh, ZBH);
+	zcache_zbud_curr_zbytes -= size;
+	atomic_dec(&zcache_zbud_curr_zpages);
+	return size;
+}
+
+static void zbud_free_and_delist(struct zbud_hdr *zh)
+{
+	unsigned chunks;
+	struct zbud_hdr *zh_other;
+	unsigned budnum = zbud_budnum(zh), size;
+	struct zbud_page *zbpg =
+		container_of(zh, struct zbud_page, buddy[budnum]);
+
+	/* FIXME, should be BUG_ON, pool destruction path doesn't disable
+	 * interrupts tmem_destroy_pool()->tmem_pampd_destroy_all_in_obj()->
+	 * tmem_objnode_node_destroy()-> zcache_pampd_free() */
+	WARN_ON(!irqs_disabled());
+	spin_lock(&zbpg->lock);
+	if (list_empty(&zbpg->bud_list)) {
+		/* ignore zombie page... see zbud_evict_pages() */
+		spin_unlock(&zbpg->lock);
+		return;
+	}
+	size = zbud_free(zh);
+	ASSERT_SPINLOCK(&zbpg->lock);
+	zh_other = &zbpg->buddy[(budnum == 0) ? 1 : 0];
+	if (zh_other->size == 0) { /* was unbuddied: unlist and free */
+		chunks = zbud_size_to_chunks(size) ;
+		spin_lock(&zbud_budlists_spinlock);
+		BUG_ON(list_empty(&zbud_unbuddied[chunks].list));
+		list_del_init(&zbpg->bud_list);
+		zbud_unbuddied[chunks].count--;
+		spin_unlock(&zbud_budlists_spinlock);
+		zbud_free_raw_page(zbpg);
+	} else { /* was buddied: move remaining buddy to unbuddied list */
+		chunks = zbud_size_to_chunks(zh_other->size) ;
+		spin_lock(&zbud_budlists_spinlock);
+		list_del_init(&zbpg->bud_list);
+		zcache_zbud_buddied_count--;
+		list_add_tail(&zbpg->bud_list, &zbud_unbuddied[chunks].list);
+		zbud_unbuddied[chunks].count++;
+		spin_unlock(&zbud_budlists_spinlock);
+		spin_unlock(&zbpg->lock);
+	}
+}
+
+static struct zbud_hdr *zbud_create(uint16_t client_id, uint16_t pool_id,
+					struct tmem_oid *oid,
+					uint32_t index, struct page *page,
+					void *cdata, unsigned size)
+{
+	struct zbud_hdr *zh0, *zh1, *zh = NULL;
+	struct zbud_page *zbpg = NULL, *ztmp;
+	unsigned nchunks;
+	char *to;
+	int i, found_good_buddy = 0;
+
+	nchunks = zbud_size_to_chunks(size) ;
+	for (i = MAX_CHUNK - nchunks + 1; i > 0; i--) {
+		spin_lock(&zbud_budlists_spinlock);
+		if (!list_empty(&zbud_unbuddied[i].list)) {
+			list_for_each_entry_safe(zbpg, ztmp,
+				    &zbud_unbuddied[i].list, bud_list) {
+				if (spin_trylock(&zbpg->lock)) {
+					found_good_buddy = i;
+					goto found_unbuddied;
+				}
+			}
+		}
+		spin_unlock(&zbud_budlists_spinlock);
+	}
+	/* didn't find a good buddy, try allocating a new page */
+	zbpg = zbud_alloc_raw_page();
+	if (unlikely(zbpg == NULL))
+		goto out;
+	/* ok, have a page, now compress the data before taking locks */
+	spin_lock(&zbud_budlists_spinlock);
+	spin_lock(&zbpg->lock);
+	list_add_tail(&zbpg->bud_list, &zbud_unbuddied[nchunks].list);
+	zbud_unbuddied[nchunks].count++;
+	zh = &zbpg->buddy[0];
+	goto init_zh;
+
+found_unbuddied:
+	ASSERT_SPINLOCK(&zbpg->lock);
+	zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1];
+	BUG_ON(!((zh0->size == 0) ^ (zh1->size == 0)));
+	if (zh0->size != 0) { /* buddy0 in use, buddy1 is vacant */
+		ASSERT_SENTINEL(zh0, ZBH);
+		zh = zh1;
+	} else if (zh1->size != 0) { /* buddy1 in use, buddy0 is vacant */
+		ASSERT_SENTINEL(zh1, ZBH);
+		zh = zh0;
+	} else
+		BUG();
+	list_del_init(&zbpg->bud_list);
+	zbud_unbuddied[found_good_buddy].count--;
+	list_add_tail(&zbpg->bud_list, &zbud_buddied_list);
+	zcache_zbud_buddied_count++;
+
+init_zh:
+	SET_SENTINEL(zh, ZBH);
+	zh->size = size;
+	zh->index = index;
+	zh->oid = *oid;
+	zh->pool_id = pool_id;
+	zh->client_id = client_id;
+	to = zbud_data(zh, size);
+	memcpy(to, cdata, size);
+	spin_unlock(&zbpg->lock);
+	spin_unlock(&zbud_budlists_spinlock);
+	zbud_cumul_chunk_counts[nchunks]++;
+	atomic_inc(&zcache_zbud_curr_zpages);
+	zcache_zbud_cumul_zpages++;
+	zcache_zbud_curr_zbytes += size;
+	zcache_zbud_cumul_zbytes += size;
+out:
+	return zh;
+}
+
+static int zbud_decompress(struct page *page, struct zbud_hdr *zh)
+{
+	struct zbud_page *zbpg;
+	unsigned budnum = zbud_budnum(zh);
+	size_t out_len = PAGE_SIZE;
+	char *to_va, *from_va;
+	unsigned size;
+	int ret = 0;
+
+	zbpg = container_of(zh, struct zbud_page, buddy[budnum]);
+	spin_lock(&zbpg->lock);
+	if (list_empty(&zbpg->bud_list)) {
+		/* ignore zombie page... see zbud_evict_pages() */
+		ret = -EINVAL;
+		goto out;
+	}
+	ASSERT_SENTINEL(zh, ZBH);
+	BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size());
+	to_va = kmap_atomic(page, KM_USER0);
+	size = zh->size;
+	from_va = zbud_data(zh, size);
+	ret = lzo1x_decompress_safe(from_va, size, to_va, &out_len);
+	BUG_ON(ret != LZO_E_OK);
+	BUG_ON(out_len != PAGE_SIZE);
+	kunmap_atomic(to_va, KM_USER0);
+out:
+	spin_unlock(&zbpg->lock);
+	return ret;
+}
+
+/*
+ * The following routines handle shrinking of ephemeral pages by evicting
+ * pages "least valuable" first.
+ */
+
+static unsigned long zcache_evicted_raw_pages;
+static unsigned long zcache_evicted_buddied_pages;
+static unsigned long zcache_evicted_unbuddied_pages;
+
+static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id,
+						uint16_t poolid);
+static void zcache_put_pool(struct tmem_pool *pool);
+
+/*
+ * Flush and free all zbuds in a zbpg, then free the pageframe
+ */
+static void zbud_evict_zbpg(struct zbud_page *zbpg)
+{
+	struct zbud_hdr *zh;
+	int i, j;
+	uint32_t pool_id[ZBUD_MAX_BUDS], client_id[ZBUD_MAX_BUDS];
+	uint32_t index[ZBUD_MAX_BUDS];
+	struct tmem_oid oid[ZBUD_MAX_BUDS];
+	struct tmem_pool *pool;
+	unsigned long flags;
+
+	ASSERT_SPINLOCK(&zbpg->lock);
+	for (i = 0, j = 0; i < ZBUD_MAX_BUDS; i++) {
+		zh = &zbpg->buddy[i];
+		if (zh->size) {
+			client_id[j] = zh->client_id;
+			pool_id[j] = zh->pool_id;
+			oid[j] = zh->oid;
+			index[j] = zh->index;
+			j++;
+		}
+	}
+	spin_unlock(&zbpg->lock);
+	for (i = 0; i < j; i++) {
+		pool = zcache_get_pool_by_id(client_id[i], pool_id[i]);
+		BUG_ON(pool == NULL);
+		local_irq_save(flags);
+		/* these flushes should dispose of any local storage */
+		tmem_flush_page(pool, &oid[i], index[i]);
+		local_irq_restore(flags);
+		zcache_put_pool(pool);
+	}
+}
+
+/*
+ * Free nr pages.  This code is funky because we want to hold the locks
+ * protecting various lists for as short a time as possible, and in some
+ * circumstances the list may change asynchronously when the list lock is
+ * not held.  In some cases we also trylock not only to avoid waiting on a
+ * page in use by another cpu, but also to avoid potential deadlock due to
+ * lock inversion.
+ */
+static void zbud_evict_pages(int nr)
+{
+	struct zbud_page *zbpg;
+	int i, newly_unused_pages = 0;
+
+
+	/* now try freeing unbuddied pages, starting with least space avail */
+	for (i = 0; i < MAX_CHUNK; i++) {
+retry_unbud_list_i:
+		spin_lock_bh(&zbud_budlists_spinlock);
+		if (list_empty(&zbud_unbuddied[i].list)) {
+			spin_unlock_bh(&zbud_budlists_spinlock);
+			continue;
+		}
+		list_for_each_entry(zbpg, &zbud_unbuddied[i].list, bud_list) {
+			if (unlikely(!spin_trylock(&zbpg->lock)))
+				continue;
+			zbud_unbuddied[i].count--;
+			spin_unlock(&zbud_budlists_spinlock);
+			zcache_evicted_unbuddied_pages++;
+			/* want budlists unlocked when doing zbpg eviction */
+			zbud_evict_zbpg(zbpg);
+			newly_unused_pages++;
+			local_bh_enable();
+			if (--nr <= 0)
+				goto evict_unused;
+			goto retry_unbud_list_i;
+		}
+		spin_unlock_bh(&zbud_budlists_spinlock);
+	}
+
+	/* as a last resort, free buddied pages */
+retry_bud_list:
+	spin_lock_bh(&zbud_budlists_spinlock);
+	if (list_empty(&zbud_buddied_list)) {
+		spin_unlock_bh(&zbud_budlists_spinlock);
+		goto evict_unused;
+	}
+	list_for_each_entry(zbpg, &zbud_buddied_list, bud_list) {
+		if (unlikely(!spin_trylock(&zbpg->lock)))
+			continue;
+		zcache_zbud_buddied_count--;
+		spin_unlock(&zbud_budlists_spinlock);
+		zcache_evicted_buddied_pages++;
+		/* want budlists unlocked when doing zbpg eviction */
+		zbud_evict_zbpg(zbpg);
+		newly_unused_pages++;
+		local_bh_enable();
+		if (--nr <= 0)
+			goto evict_unused;
+		goto retry_bud_list;
+	}
+	spin_unlock_bh(&zbud_budlists_spinlock);
+
+evict_unused:
+	return;
+}
+
+static DEFINE_PER_CPU(unsigned char *, zcache_remoteputmem);
+
+static int zbud_remotify_zbud(struct tmem_xhandle *xh, char *data,
+				size_t size)
+{
+	struct tmem_pool *pool;
+	int i, remotenode, ret = -1;
+	unsigned char cksum, *p;
+	unsigned long flags;
+
+	for (p = data, cksum = 0, i = 0; i < size; i++)
+		cksum += *p;
+	ret = ramster_remote_put(xh, data, size, true, &remotenode);
+	if (ret == 0) {
+		/* data was successfully remoted so change the local version
+		 * to point to the remote node where it landed */
+		pool = zcache_get_pool_by_id(LOCAL_CLIENT, xh->pool_id);
+		BUG_ON(pool == NULL);
+		local_irq_save(flags);
+		/* tmem_replace will also free up any local space */
+		(void)tmem_replace(pool, &xh->oid, xh->index,
+			pampd_make_remote(remotenode, size, cksum));
+		local_irq_restore(flags);
+		zcache_put_pool(pool);
+		ramster_eph_pages_remoted++;
+		ret = 0;
+	} else
+		ramster_eph_pages_remote_failed++;
+	return ret;
+}
+
+static int zbud_remotify_zbpg(struct zbud_page *zbpg)
+{
+	struct zbud_hdr *zh1, *zh2 = NULL;
+	struct tmem_xhandle xh1, xh2 = { 0 };
+	char *data1 = NULL, *data2 = NULL;
+	size_t size1 = 0, size2 = 0;
+	int ret = 0;
+	unsigned char *tmpmem = __get_cpu_var(zcache_remoteputmem);
+
+	ASSERT_SPINLOCK(&zbpg->lock);
+	if (zbpg->buddy[0].size == 0)
+		zh1 = &zbpg->buddy[1];
+	else if (zbpg->buddy[1].size == 0)
+		zh1 = &zbpg->buddy[0];
+	else {
+		zh1 = &zbpg->buddy[0];
+		zh2 = &zbpg->buddy[1];
+	}
+	/* don't remotify pages that are already remotified */
+	if (zh1->client_id != LOCAL_CLIENT)
+		zh1 = NULL;
+	if ((zh2 != NULL) && (zh2->client_id != LOCAL_CLIENT))
+		zh2 = NULL;
+
+	/* copy the data and metadata so can release lock */
+	if (zh1 != NULL) {
+		xh1.client_id = zh1->client_id;
+		xh1.pool_id = zh1->pool_id;
+		xh1.oid = zh1->oid;
+		xh1.index = zh1->index;
+		size1 = zh1->size;
+		data1 = zbud_data(zh1, size1);
+		memcpy(tmpmem, zbud_data(zh1, size1), size1);
+		data1 = tmpmem;
+		tmpmem += size1;
+	}
+	if (zh2 != NULL) {
+		xh2.client_id = zh2->client_id;
+		xh2.pool_id = zh2->pool_id;
+		xh2.oid = zh2->oid;
+		xh2.index = zh2->index;
+		size2 = zh2->size;
+		memcpy(tmpmem, zbud_data(zh2, size2), size2);
+		data2 = tmpmem;
+	}
+	spin_unlock(&zbpg->lock);
+	preempt_enable();
+
+	/* OK, no locks held anymore, remotify one or both zbuds */
+	if (zh1 != NULL)
+		ret = zbud_remotify_zbud(&xh1, data1, size1);
+	if (zh2 != NULL)
+		ret |= zbud_remotify_zbud(&xh2, data2, size2);
+	return ret;
+}
+
+void zbud_remotify_pages(int nr)
+{
+	struct zbud_page *zbpg;
+	int i, ret;
+
+	/*
+	 * for now just try remotifying unbuddied pages, starting with
+	 * least space avail
+	 */
+	for (i = 0; i < MAX_CHUNK; i++) {
+retry_unbud_list_i:
+		preempt_disable();  /* enable in zbud_remotify_zbpg */
+		spin_lock_bh(&zbud_budlists_spinlock);
+		if (list_empty(&zbud_unbuddied[i].list)) {
+			spin_unlock_bh(&zbud_budlists_spinlock);
+			preempt_enable();
+			continue; /* next i in for loop */
+		}
+		list_for_each_entry(zbpg, &zbud_unbuddied[i].list, bud_list) {
+			if (unlikely(!spin_trylock(&zbpg->lock)))
+				continue; /* next list_for_each_entry */
+			zbud_unbuddied[i].count--;
+			/* want budlists unlocked when doing zbpg remotify */
+			spin_unlock_bh(&zbud_budlists_spinlock);
+			ret = zbud_remotify_zbpg(zbpg);
+			/* preemption is re-enabled in zbud_remotify_zbpg */
+			if (ret == 0) {
+				if (--nr <= 0)
+					goto out;
+				goto retry_unbud_list_i;
+			}
+			/* if fail to remotify any page, quit */
+			pr_err("TESTING zbud_remotify_pages failed on page,"
+				" trying to re-add\n");
+			spin_lock_bh(&zbud_budlists_spinlock);
+			spin_lock(&zbpg->lock);
+			list_add_tail(&zbpg->bud_list, &zbud_unbuddied[i].list);
+			zbud_unbuddied[i].count++;
+			spin_unlock(&zbpg->lock);
+			spin_unlock_bh(&zbud_budlists_spinlock);
+			pr_err("TESTING zbud_remotify_pages failed on page,"
+				" finished re-add\n");
+			goto out;
+		}
+		spin_unlock_bh(&zbud_budlists_spinlock);
+		preempt_enable();
+	}
+
+next_buddied_zbpg:
+	preempt_disable();  /* enable in zbud_remotify_zbpg */
+	spin_lock_bh(&zbud_budlists_spinlock);
+	if (list_empty(&zbud_buddied_list))
+		goto unlock_out;
+	list_for_each_entry(zbpg, &zbud_buddied_list, bud_list) {
+		if (unlikely(!spin_trylock(&zbpg->lock)))
+			continue; /* next list_for_each_entry */
+		zcache_zbud_buddied_count--;
+		/* want budlists unlocked when doing zbpg remotify */
+		spin_unlock_bh(&zbud_budlists_spinlock);
+		ret = zbud_remotify_zbpg(zbpg);
+		/* preemption is re-enabled in zbud_remotify_zbpg */
+		if (ret == 0) {
+			if (--nr <= 0)
+				goto out;
+			goto next_buddied_zbpg;
+		}
+		/* if fail to remotify any page, quit */
+		pr_err("TESTING zbud_remotify_pages failed on BUDDIED page,"
+			" trying to re-add\n");
+		spin_lock_bh(&zbud_budlists_spinlock);
+		spin_lock(&zbpg->lock);
+		list_add_tail(&zbpg->bud_list, &zbud_buddied_list);
+		zcache_zbud_buddied_count++;
+		spin_unlock(&zbpg->lock);
+		spin_unlock_bh(&zbud_budlists_spinlock);
+		pr_err("TESTING zbud_remotify_pages failed on BUDDIED page,"
+			" finished re-add\n");
+		goto out;
+	}
+unlock_out:
+	spin_unlock_bh(&zbud_budlists_spinlock);
+	preempt_enable();
+out:
+	return;
+}
+
+/* the "flush list" asynchronously collects pages to remotely flush */
+#define FLUSH_ENTIRE_OBJECT ((uint32_t)-1)
+static void ramster_flnode_free(struct flushlist_node *,
+				struct tmem_pool *);
+
+static void zcache_remote_flush_page(struct flushlist_node *flnode)
+{
+	struct tmem_xhandle *xh;
+	int remotenode, ret;
+
+	preempt_disable();
+	xh = &flnode->xh;
+	remotenode = flnode->xh.client_id;
+	ret = ramster_remote_flush(xh, remotenode);
+	if (ret >= 0)
+		ramster_remote_pages_flushed++;
+	else
+		ramster_remote_page_flushes_failed++;
+	preempt_enable_no_resched();
+	ramster_flnode_free(flnode, NULL);
+}
+
+static void zcache_remote_flush_object(struct flushlist_node *flnode)
+{
+	struct tmem_xhandle *xh;
+	int remotenode, ret;
+
+	preempt_disable();
+	xh = &flnode->xh;
+	remotenode = flnode->xh.client_id;
+	ret = ramster_remote_flush_object(xh, remotenode);
+	if (ret >= 0)
+		ramster_remote_objects_flushed++;
+	else
+		ramster_remote_object_flushes_failed++;
+	preempt_enable_no_resched();
+	ramster_flnode_free(flnode, NULL);
+}
+
+static void zcache_remote_eph_put(struct zbud_hdr *zbud)
+{
+	/* FIXME */
+}
+
+static void zcache_remote_pers_put(struct zv_hdr *zv)
+{
+	struct tmem_xhandle xh;
+	uint16_t size;
+	bool ephemeral;
+	int remotenode, ret = -1;
+	char *data;
+	struct tmem_pool *pool;
+	unsigned long flags;
+	unsigned char cksum;
+	char *p;
+	int i;
+	unsigned char *tmpmem = __get_cpu_var(zcache_remoteputmem);
+
+	ASSERT_SENTINEL(zv, ZVH);
+	BUG_ON(zv->client_id != LOCAL_CLIENT);
+	local_bh_disable();
+	xh.client_id = zv->client_id;
+	xh.pool_id = zv->pool_id;
+	xh.oid = zv->oid;
+	xh.index = zv->index;
+	size = xv_get_object_size(zv) - sizeof(*zv);
+	BUG_ON(size == 0 || size > zv_max_page_size);
+	data = (char *)zv + sizeof(*zv);
+	for (p = data, cksum = 0, i = 0; i < size; i++)
+		cksum += *p;
+	memcpy(tmpmem, data, size);
+	data = tmpmem;
+	pool = zcache_get_pool_by_id(zv->client_id, zv->pool_id);
+	ephemeral = is_ephemeral(pool);
+	zcache_put_pool(pool);
+	/* now OK to release lock set in caller */
+	spin_unlock(&zcache_rem_op_list_lock);
+	local_bh_enable();
+	preempt_disable();
+	ret = ramster_remote_put(&xh, data, size, ephemeral, &remotenode);
+	preempt_enable_no_resched();
+	if (ret != 0) {
+		/*
+		 * This is some form of a memory leak... if the remote put
+		 * fails, there will never be another attempt to remotify
+		 * this page.  But since we've dropped the zv pointer,
+		 * the page may have been freed or the data replaced
+		 * so we can't just "put it back" in the remote op list.
+		 * Even if we could, not sure where to put it in the list
+		 * because there may be flushes that must be strictly
+		 * ordered vs the put.  So leave this as a FIXME for now.
+		 * But count them so we know if it becomes a problem.
+		 */
+		ramster_pers_pages_remote_failed++;
+		goto out;
+	} else
+		atomic_inc(&ramster_remote_pers_pages);
+	ramster_pers_pages_remoted++;
+	/*
+	 * data was successfully remoted so change the local version to
+	 * point to the remote node where it landed
+	 */
+	local_bh_disable();
+	pool = zcache_get_pool_by_id(LOCAL_CLIENT, xh.pool_id);
+	local_irq_save(flags);
+	(void)tmem_replace(pool, &xh.oid, xh.index,
+			pampd_make_remote(remotenode, size, cksum));
+	local_irq_restore(flags);
+	zcache_put_pool(pool);
+	local_bh_enable();
+out:
+	return;
+}
+
+static void zcache_do_remotify_ops(int nr)
+{
+	struct ramster_remotify_hdr *rem_op;
+	union remotify_list_node *u;
+
+	while (1) {
+		if (!nr)
+			goto out;
+		spin_lock(&zcache_rem_op_list_lock);
+		if (list_empty(&zcache_rem_op_list)) {
+			spin_unlock(&zcache_rem_op_list_lock);
+			goto out;
+		}
+		rem_op = list_first_entry(&zcache_rem_op_list,
+				struct ramster_remotify_hdr, list);
+		list_del_init(&rem_op->list);
+		if (rem_op->op != RAMSTER_REMOTIFY_PERS_PUT)
+			spin_unlock(&zcache_rem_op_list_lock);
+		u = (union remotify_list_node *)rem_op;
+		switch (rem_op->op) {
+		case RAMSTER_REMOTIFY_EPH_PUT:
+BUG();
+			zcache_remote_eph_put((struct zbud_hdr *)rem_op);
+			break;
+		case RAMSTER_REMOTIFY_PERS_PUT:
+			zcache_remote_pers_put((struct zv_hdr *)rem_op);
+			break;
+		case RAMSTER_REMOTIFY_FLUSH_PAGE:
+			zcache_remote_flush_page((struct flushlist_node *)u);
+			break;
+		case RAMSTER_REMOTIFY_FLUSH_OBJ:
+			zcache_remote_flush_object((struct flushlist_node *)u);
+			break;
+		default:
+			BUG();
+		}
+	}
+out:
+	return;
+}
+
+/*
+ * Communicate interface revision with userspace
+ */
+#include "cluster/ramster_nodemanager.h"
+static unsigned long ramster_interface_revision  = R2NM_API_VERSION;
+
+/*
+ * For now, just push over a few pages every few seconds to
+ * ensure that it basically works
+ */
+static struct workqueue_struct *ramster_remotify_workqueue;
+static void ramster_remotify_process(struct work_struct *work);
+static DECLARE_DELAYED_WORK(ramster_remotify_worker,
+		ramster_remotify_process);
+
+static void ramster_remotify_queue_delayed_work(unsigned long delay)
+{
+	if (!queue_delayed_work(ramster_remotify_workqueue,
+				&ramster_remotify_worker, delay))
+		pr_err("ramster_remotify: bad workqueue\n");
+}
+
+
+static int use_frontswap;
+static int use_cleancache;
+static int ramster_remote_target_nodenum = -1;
+static void ramster_remotify_process(struct work_struct *work)
+{
+	static bool remotify_in_progress;
+
+	BUG_ON(irqs_disabled());
+	if (remotify_in_progress)
+		ramster_remotify_queue_delayed_work(HZ);
+	else if (ramster_remote_target_nodenum != -1) {
+		remotify_in_progress = true;
+#ifdef CONFIG_CLEANCACHE
+	if (use_cleancache && ramster_eph_remotify_enable)
+		zbud_remotify_pages(5000); /* FIXME is this a good number? */
+#endif
+#ifdef CONFIG_FRONTSWAP
+	if (use_frontswap && ramster_pers_remotify_enable)
+		zcache_do_remotify_ops(500); /* FIXME is this a good number? */
+#endif
+		remotify_in_progress = false;
+		ramster_remotify_queue_delayed_work(HZ);
+	}
+}
+
+static void ramster_remotify_init(void)
+{
+	unsigned long n = 60UL;
+	ramster_remotify_workqueue =
+		create_singlethread_workqueue("ramster_remotify");
+	ramster_remotify_queue_delayed_work(n * HZ);
+}
+
+
+static void zbud_init(void)
+{
+	int i;
+
+	INIT_LIST_HEAD(&zbud_buddied_list);
+	zcache_zbud_buddied_count = 0;
+	for (i = 0; i < NCHUNKS; i++) {
+		INIT_LIST_HEAD(&zbud_unbuddied[i].list);
+		zbud_unbuddied[i].count = 0;
+	}
+}
+
+#ifdef CONFIG_SYSFS
+/*
+ * These sysfs routines show a nice distribution of how many zbpg's are
+ * currently (and have ever been placed) in each unbuddied list.  It's fun
+ * to watch but can probably go away before final merge.
+ */
+static int zbud_show_unbuddied_list_counts(char *buf)
+{
+	int i;
+	char *p = buf;
+
+	for (i = 0; i < NCHUNKS; i++)
+		p += sprintf(p, "%u ", zbud_unbuddied[i].count);
+	return p - buf;
+}
+
+static int zbud_show_cumul_chunk_counts(char *buf)
+{
+	unsigned long i, chunks = 0, total_chunks = 0, sum_total_chunks = 0;
+	unsigned long total_chunks_lte_21 = 0, total_chunks_lte_32 = 0;
+	unsigned long total_chunks_lte_42 = 0;
+	char *p = buf;
+
+	for (i = 0; i < NCHUNKS; i++) {
+		p += sprintf(p, "%lu ", zbud_cumul_chunk_counts[i]);
+		chunks += zbud_cumul_chunk_counts[i];
+		total_chunks += zbud_cumul_chunk_counts[i];
+		sum_total_chunks += i * zbud_cumul_chunk_counts[i];
+		if (i == 21)
+			total_chunks_lte_21 = total_chunks;
+		if (i == 32)
+			total_chunks_lte_32 = total_chunks;
+		if (i == 42)
+			total_chunks_lte_42 = total_chunks;
+	}
+	p += sprintf(p, "<=21:%lu <=32:%lu <=42:%lu, mean:%lu\n",
+		total_chunks_lte_21, total_chunks_lte_32, total_chunks_lte_42,
+		chunks == 0 ? 0 : sum_total_chunks / chunks);
+	return p - buf;
+}
+#endif
+
+/**********
+ * This "zv" PAM implementation combines the TLSF-based xvMalloc
+ * with lzo1x compression to maximize the amount of data that can
+ * be packed into a physical page.
+ *
+ * Zv represents a PAM page with the index and object (plus a "size" value
+ * necessary for decompression) immediately preceding the compressed data.
+ */
+
+/* rudimentary policy limits */
+/* total number of persistent pages may not exceed this percentage */
+static unsigned int zv_page_count_policy_percent = 75;
+/*
+ * byte count defining poor compression; pages with greater zsize will be
+ * rejected
+ */
+static unsigned int zv_max_zsize = (PAGE_SIZE / 8) * 7;
+/*
+ * byte count defining poor *mean* compression; pages with greater zsize
+ * will be rejected until sufficient better-compressed pages are accepted
+ * driving the mean below this threshold
+ */
+static unsigned int zv_max_mean_zsize = (PAGE_SIZE / 8) * 5;
+
+static atomic_t zv_curr_dist_counts[NCHUNKS];
+static atomic_t zv_cumul_dist_counts[NCHUNKS];
+
+
+static struct zv_hdr *zv_create(struct zcache_client *cli, uint32_t pool_id,
+				struct tmem_oid *oid, uint32_t index,
+				void *cdata, unsigned clen)
+{
+	struct page *page;
+	struct zv_hdr *zv = NULL;
+	uint32_t offset;
+	int alloc_size = clen + sizeof(struct zv_hdr);
+	int chunks = (alloc_size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT;
+	int ret;
+
+	BUG_ON(!irqs_disabled());
+	BUG_ON(chunks >= NCHUNKS);
+	ret = xv_malloc(cli->xvpool, clen + sizeof(struct zv_hdr),
+			&page, &offset, ZCACHE_GFP_MASK);
+	if (unlikely(ret))
+		goto out;
+	atomic_inc(&zv_curr_dist_counts[chunks]);
+	atomic_inc(&zv_cumul_dist_counts[chunks]);
+	zv = kmap_atomic(page, KM_USER0) + offset;
+	zv->index = index;
+	zv->oid = *oid;
+	zv->pool_id = pool_id;
+	SET_SENTINEL(zv, ZVH);
+	INIT_LIST_HEAD(&zv->rem_op.list);
+	zv->client_id = get_client_id_from_client(cli);
+	zv->rem_op.op = RAMSTER_REMOTIFY_PERS_PUT;
+	if (zv->client_id == LOCAL_CLIENT) {
+		spin_lock(&zcache_rem_op_list_lock);
+		list_add_tail(&zv->rem_op.list, &zcache_rem_op_list);
+		spin_unlock(&zcache_rem_op_list_lock);
+	}
+	memcpy((char *)zv + sizeof(struct zv_hdr), cdata, clen);
+	kunmap_atomic(zv, KM_USER0);
+out:
+	return zv;
+}
+
+/* similar to zv_create, but just reserve space, no data yet */
+static struct zv_hdr *zv_alloc(struct tmem_pool *pool,
+				struct tmem_oid *oid, uint32_t index,
+				unsigned clen)
+{
+	struct zcache_client *cli = pool->client;
+	struct page *page;
+	struct zv_hdr *zv = NULL;
+	uint32_t offset;
+	int ret;
+
+	BUG_ON(!irqs_disabled());
+	BUG_ON(!is_local_client(pool->client));
+	ret = xv_malloc(cli->xvpool, clen + sizeof(struct zv_hdr),
+			&page, &offset, ZCACHE_GFP_MASK);
+	if (unlikely(ret))
+		goto out;
+	zv = kmap_atomic(page, KM_USER0) + offset;
+	SET_SENTINEL(zv, ZVH);
+	INIT_LIST_HEAD(&zv->rem_op.list);
+	zv->client_id = LOCAL_CLIENT;
+	zv->rem_op.op = RAMSTER_INTRANSIT_PERS;
+	zv->index = index;
+	zv->oid = *oid;
+	zv->pool_id = pool->pool_id;
+	kunmap_atomic(zv, KM_USER0);
+out:
+	return zv;
+}
+
+static void zv_free(struct xv_pool *xvpool, struct zv_hdr *zv)
+{
+	unsigned long flags;
+	struct page *page;
+	uint32_t offset;
+	uint16_t size = xv_get_object_size(zv);
+	int chunks = (size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT;
+
+	ASSERT_SENTINEL(zv, ZVH);
+	BUG_ON(chunks >= NCHUNKS);
+	atomic_dec(&zv_curr_dist_counts[chunks]);
+	size -= sizeof(*zv);
+	spin_lock(&zcache_rem_op_list_lock);
+	size = xv_get_object_size(zv) - sizeof(*zv);
+	BUG_ON(size == 0);
+	INVERT_SENTINEL(zv, ZVH);
+	if (!list_empty(&zv->rem_op.list))
+		list_del_init(&zv->rem_op.list);
+	spin_unlock(&zcache_rem_op_list_lock);
+	page = virt_to_page(zv);
+	offset = (unsigned long)zv & ~PAGE_MASK;
+	local_irq_save(flags);
+	xv_free(xvpool, page, offset);
+	local_irq_restore(flags);
+}
+
+static void zv_decompress(struct page *page, struct zv_hdr *zv)
+{
+	size_t clen = PAGE_SIZE;
+	char *to_va;
+	unsigned size;
+	int ret;
+
+	ASSERT_SENTINEL(zv, ZVH);
+	size = xv_get_object_size(zv) - sizeof(*zv);
+	BUG_ON(size == 0);
+	to_va = kmap_atomic(page, KM_USER0);
+	ret = lzo1x_decompress_safe((char *)zv + sizeof(*zv),
+					size, to_va, &clen);
+	kunmap_atomic(to_va, KM_USER0);
+	BUG_ON(ret != LZO_E_OK);
+	BUG_ON(clen != PAGE_SIZE);
+}
+
+static void zv_copy_from_pampd(char *data, size_t *bufsize, struct zv_hdr *zv)
+{
+	unsigned size;
+
+	ASSERT_SENTINEL(zv, ZVH);
+	size = xv_get_object_size(zv) - sizeof(*zv);
+	BUG_ON(size == 0 || size > zv_max_page_size);
+	BUG_ON(size > *bufsize);
+	memcpy(data, (char *)zv + sizeof(*zv), size);
+	*bufsize = size;
+}
+
+static void zv_copy_to_pampd(struct zv_hdr *zv, char *data, size_t size)
+{
+	unsigned zv_size;
+
+	ASSERT_SENTINEL(zv, ZVH);
+	zv_size = xv_get_object_size(zv) - sizeof(*zv);
+	BUG_ON(zv_size != size);
+	BUG_ON(zv_size == 0 || zv_size > zv_max_page_size);
+	memcpy((char *)zv + sizeof(*zv), data, size);
+}
+
+#ifdef CONFIG_SYSFS
+/*
+ * show a distribution of compression stats for zv pages.
+ */
+
+static int zv_curr_dist_counts_show(char *buf)
+{
+	unsigned long i, n, chunks = 0, sum_total_chunks = 0;
+	char *p = buf;
+
+	for (i = 0; i < NCHUNKS; i++) {
+		n = atomic_read(&zv_curr_dist_counts[i]);
+		p += sprintf(p, "%lu ", n);
+		chunks += n;
+		sum_total_chunks += i * n;
+	}
+	p += sprintf(p, "mean:%lu\n",
+		chunks == 0 ? 0 : sum_total_chunks / chunks);
+	return p - buf;
+}
+
+static int zv_cumul_dist_counts_show(char *buf)
+{
+	unsigned long i, n, chunks = 0, sum_total_chunks = 0;
+	char *p = buf;
+
+	for (i = 0; i < NCHUNKS; i++) {
+		n = atomic_read(&zv_cumul_dist_counts[i]);
+		p += sprintf(p, "%lu ", n);
+		chunks += n;
+		sum_total_chunks += i * n;
+	}
+	p += sprintf(p, "mean:%lu\n",
+		chunks == 0 ? 0 : sum_total_chunks / chunks);
+	return p - buf;
+}
+
+/*
+ * setting zv_max_zsize via sysfs causes all persistent (e.g. swap)
+ * pages that don't compress to less than this value (including metadata
+ * overhead) to be rejected.  We don't allow the value to get too close
+ * to PAGE_SIZE.
+ */
+static ssize_t zv_max_zsize_show(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    char *buf)
+{
+	return sprintf(buf, "%u\n", zv_max_zsize);
+}
+
+static ssize_t zv_max_zsize_store(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    const char *buf, size_t count)
+{
+	unsigned long val;
+	int err;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err || (val == 0) || (val > (PAGE_SIZE / 8) * 7))
+		return -EINVAL;
+	zv_max_zsize = val;
+	return count;
+}
+
+/*
+ * setting zv_max_mean_zsize via sysfs causes all persistent (e.g. swap)
+ * pages that don't compress to less than this value (including metadata
+ * overhead) to be rejected UNLESS the mean compression is also smaller
+ * than this value.  In other words, we are load-balancing-by-zsize the
+ * accepted pages.  Again, we don't allow the value to get too close
+ * to PAGE_SIZE.
+ */
+static ssize_t zv_max_mean_zsize_show(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    char *buf)
+{
+	return sprintf(buf, "%u\n", zv_max_mean_zsize);
+}
+
+static ssize_t zv_max_mean_zsize_store(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    const char *buf, size_t count)
+{
+	unsigned long val;
+	int err;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err || (val == 0) || (val > (PAGE_SIZE / 8) * 7))
+		return -EINVAL;
+	zv_max_mean_zsize = val;
+	return count;
+}
+
+/*
+ * setting zv_page_count_policy_percent via sysfs sets an upper bound of
+ * persistent (e.g. swap) pages that will be retained according to:
+ *     (zv_page_count_policy_percent * totalram_pages) / 100)
+ * when that limit is reached, further puts will be rejected (until
+ * some pages have been flushed).  Note that, due to compression,
+ * this number may exceed 100; it defaults to 75 and we set an
+ * arbitary limit of 150.  A poor choice will almost certainly result
+ * in OOM's, so this value should only be changed prudently.
+ */
+static ssize_t zv_page_count_policy_percent_show(struct kobject *kobj,
+						 struct kobj_attribute *attr,
+						 char *buf)
+{
+	return sprintf(buf, "%u\n", zv_page_count_policy_percent);
+}
+
+static ssize_t zv_page_count_policy_percent_store(struct kobject *kobj,
+						  struct kobj_attribute *attr,
+						  const char *buf, size_t count)
+{
+	unsigned long val;
+	int err;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err || (val == 0) || (val > 150))
+		return -EINVAL;
+	zv_page_count_policy_percent = val;
+	return count;
+}
+
+static struct kobj_attribute zcache_zv_max_zsize_attr = {
+		.attr = { .name = "zv_max_zsize", .mode = 0644 },
+		.show = zv_max_zsize_show,
+		.store = zv_max_zsize_store,
+};
+
+static struct kobj_attribute zcache_zv_max_mean_zsize_attr = {
+		.attr = { .name = "zv_max_mean_zsize", .mode = 0644 },
+		.show = zv_max_mean_zsize_show,
+		.store = zv_max_mean_zsize_store,
+};
+
+static struct kobj_attribute zcache_zv_page_count_policy_percent_attr = {
+		.attr = { .name = "zv_page_count_policy_percent",
+			  .mode = 0644 },
+		.show = zv_page_count_policy_percent_show,
+		.store = zv_page_count_policy_percent_store,
+};
+#endif
+
+/*
+ * zcache core code starts here
+ */
+
+/* useful stats not collected by cleancache or frontswap */
+static unsigned long zcache_flush_total;
+static unsigned long zcache_flush_found;
+static unsigned long zcache_flobj_total;
+static unsigned long zcache_flobj_found;
+static unsigned long zcache_failed_eph_puts;
+static unsigned long zcache_nonactive_puts;
+static unsigned long zcache_failed_pers_puts;
+
+/*
+ * Tmem operations assume the poolid implies the invoking client.
+ * Zcache only has one client (the kernel itself): LOCAL_CLIENT.
+ * RAMster has each client numbered by cluster node, and a KVM version
+ * of zcache would have one client per guest and each client might
+ * have a poolid==N.
+ */
+static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, uint16_t poolid)
+{
+	struct tmem_pool *pool = NULL;
+	struct zcache_client *cli = NULL;
+
+	if (cli_id == LOCAL_CLIENT)
+		cli = &zcache_host;
+	else {
+		if (cli_id >= MAX_CLIENTS)
+			goto out;
+		cli = &zcache_clients[cli_id];
+		if (cli == NULL)
+			goto out;
+		atomic_inc(&cli->refcount);
+	}
+	if (poolid < MAX_POOLS_PER_CLIENT) {
+		pool = cli->tmem_pools[poolid];
+		if (pool != NULL)
+			atomic_inc(&pool->refcount);
+	}
+out:
+	return pool;
+}
+
+static void zcache_put_pool(struct tmem_pool *pool)
+{
+	struct zcache_client *cli = NULL;
+
+	if (pool == NULL)
+		BUG();
+	cli = pool->client;
+	atomic_dec(&pool->refcount);
+	atomic_dec(&cli->refcount);
+}
+
+int zcache_new_client(uint16_t cli_id)
+{
+	struct zcache_client *cli = NULL;
+	int ret = -1;
+
+	if (cli_id == LOCAL_CLIENT)
+		cli = &zcache_host;
+	else if ((unsigned int)cli_id < MAX_CLIENTS)
+		cli = &zcache_clients[cli_id];
+	if (cli == NULL)
+		goto out;
+	if (cli->allocated)
+		goto out;
+	cli->allocated = 1;
+#ifdef CONFIG_FRONTSWAP
+	cli->xvpool = xv_create_pool();
+	if (cli->xvpool == NULL)
+		goto out;
+#endif
+	ret = 0;
+out:
+	return ret;
+}
+
+/* counters for debugging */
+static unsigned long zcache_failed_get_free_pages;
+static unsigned long zcache_failed_alloc;
+static unsigned long zcache_put_to_flush;
+
+/*
+ * for now, used named slabs so can easily track usage; later can
+ * either just use kmalloc, or perhaps add a slab-like allocator
+ * to more carefully manage total memory utilization
+ */
+static struct kmem_cache *zcache_objnode_cache;
+static struct kmem_cache *zcache_obj_cache;
+static struct kmem_cache *ramster_flnode_cache;
+static atomic_t zcache_curr_obj_count = ATOMIC_INIT(0);
+static unsigned long zcache_curr_obj_count_max;
+static atomic_t zcache_curr_objnode_count = ATOMIC_INIT(0);
+static unsigned long zcache_curr_objnode_count_max;
+
+/*
+ * to avoid memory allocation recursion (e.g. due to direct reclaim), we
+ * preload all necessary data structures so the hostops callbacks never
+ * actually do a malloc
+ */
+struct zcache_preload {
+	void *page;
+	struct tmem_obj *obj;
+	int nr;
+	struct tmem_objnode *objnodes[OBJNODE_TREE_MAX_PATH];
+	struct flushlist_node *flnode;
+};
+static DEFINE_PER_CPU(struct zcache_preload, zcache_preloads) = { 0, };
+
+static int zcache_do_preload(struct tmem_pool *pool)
+{
+	struct zcache_preload *kp;
+	struct tmem_objnode *objnode;
+	struct tmem_obj *obj;
+	struct flushlist_node *flnode;
+	void *page;
+	int ret = -ENOMEM;
+
+	if (unlikely(zcache_objnode_cache == NULL))
+		goto out;
+	if (unlikely(zcache_obj_cache == NULL))
+		goto out;
+	preempt_disable();
+	kp = &__get_cpu_var(zcache_preloads);
+	while (kp->nr < ARRAY_SIZE(kp->objnodes)) {
+		preempt_enable_no_resched();
+		objnode = kmem_cache_alloc(zcache_objnode_cache,
+				ZCACHE_GFP_MASK);
+		if (unlikely(objnode == NULL)) {
+			zcache_failed_alloc++;
+			goto out;
+		}
+		preempt_disable();
+		kp = &__get_cpu_var(zcache_preloads);
+		if (kp->nr < ARRAY_SIZE(kp->objnodes))
+			kp->objnodes[kp->nr++] = objnode;
+		else
+			kmem_cache_free(zcache_objnode_cache, objnode);
+	}
+	preempt_enable_no_resched();
+	obj = kmem_cache_alloc(zcache_obj_cache, ZCACHE_GFP_MASK);
+	if (unlikely(obj == NULL)) {
+		zcache_failed_alloc++;
+		goto out;
+	}
+	flnode = kmem_cache_alloc(ramster_flnode_cache, ZCACHE_GFP_MASK);
+	if (unlikely(flnode == NULL)) {
+		zcache_failed_alloc++;
+		goto out;
+	}
+	if (is_ephemeral(pool)) {
+		page = (void *)__get_free_page(ZCACHE_GFP_MASK);
+		if (unlikely(page == NULL)) {
+			zcache_failed_get_free_pages++;
+			kmem_cache_free(zcache_obj_cache, obj);
+			kmem_cache_free(ramster_flnode_cache, flnode);
+			goto out;
+		}
+	}
+	preempt_disable();
+	kp = &__get_cpu_var(zcache_preloads);
+	if (kp->obj == NULL)
+		kp->obj = obj;
+	else
+		kmem_cache_free(zcache_obj_cache, obj);
+	if (kp->flnode == NULL)
+		kp->flnode = flnode;
+	else
+		kmem_cache_free(ramster_flnode_cache, flnode);
+	if (is_ephemeral(pool)) {
+		if (kp->page == NULL)
+			kp->page = page;
+		else
+			free_page((unsigned long)page);
+	}
+	ret = 0;
+out:
+	return ret;
+}
+
+static int ramster_do_preload_flnode_only(struct tmem_pool *pool)
+{
+	struct zcache_preload *kp;
+	struct flushlist_node *flnode;
+	int ret = -ENOMEM;
+
+	BUG_ON(!irqs_disabled());
+	if (unlikely(ramster_flnode_cache == NULL))
+		BUG();
+	kp = &__get_cpu_var(zcache_preloads);
+	flnode = kmem_cache_alloc(ramster_flnode_cache, GFP_ATOMIC);
+	if (unlikely(flnode == NULL) && kp->flnode == NULL)
+		BUG();  /* FIXME handle more gracefully, but how??? */
+	else if (kp->flnode == NULL)
+		kp->flnode = flnode;
+	else
+		kmem_cache_free(ramster_flnode_cache, flnode);
+	return ret;
+}
+
+static void *zcache_get_free_page(void)
+{
+	struct zcache_preload *kp;
+	void *page;
+
+	kp = &__get_cpu_var(zcache_preloads);
+	page = kp->page;
+	BUG_ON(page == NULL);
+	kp->page = NULL;
+	return page;
+}
+
+static void zcache_free_page(void *p)
+{
+	free_page((unsigned long)p);
+}
+
+/*
+ * zcache implementation for tmem host ops
+ */
+
+static struct tmem_objnode *zcache_objnode_alloc(struct tmem_pool *pool)
+{
+	struct tmem_objnode *objnode = NULL;
+	unsigned long count;
+	struct zcache_preload *kp;
+
+	kp = &__get_cpu_var(zcache_preloads);
+	if (kp->nr <= 0)
+		goto out;
+	objnode = kp->objnodes[kp->nr - 1];
+	BUG_ON(objnode == NULL);
+	kp->objnodes[kp->nr - 1] = NULL;
+	kp->nr--;
+	count = atomic_inc_return(&zcache_curr_objnode_count);
+	if (count > zcache_curr_objnode_count_max)
+		zcache_curr_objnode_count_max = count;
+out:
+	return objnode;
+}
+
+static void zcache_objnode_free(struct tmem_objnode *objnode,
+					struct tmem_pool *pool)
+{
+	atomic_dec(&zcache_curr_objnode_count);
+	BUG_ON(atomic_read(&zcache_curr_objnode_count) < 0);
+	kmem_cache_free(zcache_objnode_cache, objnode);
+}
+
+static struct tmem_obj *zcache_obj_alloc(struct tmem_pool *pool)
+{
+	struct tmem_obj *obj = NULL;
+	unsigned long count;
+	struct zcache_preload *kp;
+
+	kp = &__get_cpu_var(zcache_preloads);
+	obj = kp->obj;
+	BUG_ON(obj == NULL);
+	kp->obj = NULL;
+	count = atomic_inc_return(&zcache_curr_obj_count);
+	if (count > zcache_curr_obj_count_max)
+		zcache_curr_obj_count_max = count;
+	return obj;
+}
+
+static void zcache_obj_free(struct tmem_obj *obj, struct tmem_pool *pool)
+{
+	atomic_dec(&zcache_curr_obj_count);
+	BUG_ON(atomic_read(&zcache_curr_obj_count) < 0);
+	kmem_cache_free(zcache_obj_cache, obj);
+}
+
+static struct flushlist_node *ramster_flnode_alloc(struct tmem_pool *pool)
+{
+	struct flushlist_node *flnode = NULL;
+	struct zcache_preload *kp;
+	int count;
+
+	kp = &__get_cpu_var(zcache_preloads);
+	flnode = kp->flnode;
+	BUG_ON(flnode == NULL);
+	kp->flnode = NULL;
+	count = atomic_inc_return(&ramster_curr_flnode_count);
+	if (count > ramster_curr_flnode_count_max)
+		ramster_curr_flnode_count_max = count;
+	return flnode;
+}
+
+static void ramster_flnode_free(struct flushlist_node *flnode,
+				struct tmem_pool *pool)
+{
+	atomic_dec(&ramster_curr_flnode_count);
+	BUG_ON(atomic_read(&ramster_curr_flnode_count) < 0);
+	kmem_cache_free(ramster_flnode_cache, flnode);
+}
+
+static struct tmem_hostops zcache_hostops = {
+	.obj_alloc = zcache_obj_alloc,
+	.obj_free = zcache_obj_free,
+	.objnode_alloc = zcache_objnode_alloc,
+	.objnode_free = zcache_objnode_free,
+};
+
+/*
+ * zcache implementations for PAM page descriptor ops
+ */
+
+
+static inline void dec_and_check(atomic_t *pvar)
+{
+	atomic_dec(pvar);
+	/* later when all accounting is fixed, make this a BUG */
+	WARN_ON_ONCE(atomic_read(pvar) < 0);
+}
+
+static atomic_t zcache_curr_eph_pampd_count = ATOMIC_INIT(0);
+static unsigned long zcache_curr_eph_pampd_count_max;
+static atomic_t zcache_curr_pers_pampd_count = ATOMIC_INIT(0);
+static unsigned long zcache_curr_pers_pampd_count_max;
+
+/* forward reference */
+static int zcache_compress(struct page *from, void **out_va, size_t *out_len);
+
+static int zcache_pampd_eph_create(char *data, size_t size, bool raw,
+				struct tmem_pool *pool, struct tmem_oid *oid,
+				uint32_t index, void **pampd)
+{
+	int ret = -1;
+	void *cdata = data;
+	size_t clen = size;
+	struct zcache_client *cli = pool->client;
+	uint16_t client_id = get_client_id_from_client(cli);
+	struct page *page = NULL;
+	unsigned long count;
+
+	if (!raw) {
+		page = virt_to_page(data);
+		ret = zcache_compress(page, &cdata, &clen);
+		if (ret == 0)
+			goto out;
+		if (clen == 0 || clen > zbud_max_buddy_size()) {
+			zcache_compress_poor++;
+			goto out;
+		}
+	}
+	*pampd = (void *)zbud_create(client_id, pool->pool_id, oid,
+					index, page, cdata, clen);
+	if (*pampd == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	ret = 0;
+	count = atomic_inc_return(&zcache_curr_eph_pampd_count);
+	if (count > zcache_curr_eph_pampd_count_max)
+		zcache_curr_eph_pampd_count_max = count;
+	if (client_id != LOCAL_CLIENT) {
+		count = atomic_inc_return(&ramster_foreign_eph_pampd_count);
+		if (count > ramster_foreign_eph_pampd_count_max)
+			ramster_foreign_eph_pampd_count_max = count;
+	}
+out:
+	return ret;
+}
+
+static int zcache_pampd_pers_create(char *data, size_t size, bool raw,
+				struct tmem_pool *pool, struct tmem_oid *oid,
+				uint32_t index, void **pampd)
+{
+	int ret = -1;
+	void *cdata = data;
+	size_t clen = size;
+	struct zcache_client *cli = pool->client;
+	struct page *page;
+	unsigned long count;
+	unsigned long zv_mean_zsize;
+	struct zv_hdr *zv;
+	long curr_pers_pampd_count;
+	u64 total_zsize;
+#ifdef RAMSTER_TESTING
+	static bool pampd_neg_warned;
+#endif
+
+	curr_pers_pampd_count = atomic_read(&zcache_curr_pers_pampd_count) -
+			atomic_read(&ramster_remote_pers_pages);
+#ifdef RAMSTER_TESTING
+	/* should always be positive, but warn if accounting is off */
+	if (!pampd_neg_warned) {
+		pr_warn("ramster: bad accounting for curr_pers_pampd_count\n");
+		pampd_neg_warned = true;
+	}
+#endif
+	if (curr_pers_pampd_count >
+		    (zv_page_count_policy_percent * totalram_pages) / 100) {
+		zcache_policy_percent_exceeded++;
+		goto out;
+	}
+	if (raw)
+		goto ok_to_create;
+	page = virt_to_page(data);
+	if (zcache_compress(page, &cdata, &clen) == 0)
+		goto out;
+	/* reject if compression is too poor */
+	if (clen > zv_max_zsize) {
+		zcache_compress_poor++;
+		goto out;
+	}
+	/* reject if mean compression is too poor */
+	if ((clen > zv_max_mean_zsize) && (curr_pers_pampd_count > 0)) {
+		total_zsize = xv_get_total_size_bytes(cli->xvpool);
+		zv_mean_zsize = div_u64(total_zsize, curr_pers_pampd_count);
+		if (zv_mean_zsize > zv_max_mean_zsize) {
+			zcache_mean_compress_poor++;
+			goto out;
+		}
+	}
+ok_to_create:
+	*pampd = (void *)zv_create(cli, pool->pool_id, oid, index, cdata, clen);
+	if (*pampd == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	ret = 0;
+	count = atomic_inc_return(&zcache_curr_pers_pampd_count);
+	if (count > zcache_curr_pers_pampd_count_max)
+		zcache_curr_pers_pampd_count_max = count;
+	if (is_local_client(cli))
+		goto out;
+	zv = *(struct zv_hdr **)pampd;
+	count = atomic_inc_return(&ramster_foreign_pers_pampd_count);
+	if (count > ramster_foreign_pers_pampd_count_max)
+		ramster_foreign_pers_pampd_count_max = count;
+out:
+	return ret;
+}
+
+static void *zcache_pampd_create(char *data, size_t size, bool raw, int eph,
+				struct tmem_pool *pool, struct tmem_oid *oid,
+				uint32_t index)
+{
+	void *pampd = NULL;
+	int ret;
+	bool ephemeral;
+
+	BUG_ON(preemptible());
+	ephemeral = (eph == 1) || ((eph == 0) && is_ephemeral(pool));
+	if (ephemeral)
+		ret = zcache_pampd_eph_create(data, size, raw, pool,
+						oid, index, &pampd);
+	else
+		ret = zcache_pampd_pers_create(data, size, raw, pool,
+						oid, index, &pampd);
+	/* FIXME add some counters here for failed creates? */
+	return pampd;
+}
+
+/*
+ * fill the pageframe corresponding to the struct page with the data
+ * from the passed pampd
+ */
+static int zcache_pampd_get_data(char *data, size_t *bufsize, bool raw,
+					void *pampd, struct tmem_pool *pool,
+					struct tmem_oid *oid, uint32_t index)
+{
+	int ret = 0;
+
+	BUG_ON(preemptible());
+	BUG_ON(is_ephemeral(pool)); /* Fix later for shared pools? */
+	BUG_ON(pampd_is_remote(pampd));
+	if (raw)
+		zv_copy_from_pampd(data, bufsize, pampd);
+	else
+		zv_decompress(virt_to_page(data), pampd);
+	return ret;
+}
+
+static int zcache_pampd_get_data_and_free(char *data, size_t *bufsize, bool raw,
+					void *pampd, struct tmem_pool *pool,
+					struct tmem_oid *oid, uint32_t index)
+{
+	int ret = 0;
+	unsigned long flags;
+	struct zcache_client *cli = pool->client;
+
+	BUG_ON(preemptible());
+	BUG_ON(pampd_is_remote(pampd));
+	if (is_ephemeral(pool)) {
+		local_irq_save(flags);
+		if (raw)
+			zbud_copy_from_pampd(data, bufsize, pampd);
+		else
+			ret = zbud_decompress(virt_to_page(data), pampd);
+		zbud_free_and_delist((struct zbud_hdr *)pampd);
+		local_irq_restore(flags);
+		if (!is_local_client(cli))
+			dec_and_check(&ramster_foreign_eph_pampd_count);
+		dec_and_check(&zcache_curr_eph_pampd_count);
+	} else {
+		if (is_local_client(cli))
+			BUG();
+		if (raw)
+			zv_copy_from_pampd(data, bufsize, pampd);
+		else
+			zv_decompress(virt_to_page(data), pampd);
+		zv_free(cli->xvpool, pampd);
+		if (!is_local_client(cli))
+			dec_and_check(&ramster_foreign_pers_pampd_count);
+		dec_and_check(&zcache_curr_pers_pampd_count);
+		ret = 0;
+	}
+	return ret;
+}
+
+static bool zcache_pampd_is_remote(void *pampd)
+{
+	return pampd_is_remote(pampd);
+}
+
+/*
+ * free the pampd and remove it from any zcache lists
+ * pampd must no longer be pointed to from any tmem data structures!
+ */
+static void zcache_pampd_free(void *pampd, struct tmem_pool *pool,
+			      struct tmem_oid *oid, uint32_t index, bool acct)
+{
+	struct zcache_client *cli = pool->client;
+	bool eph = is_ephemeral(pool);
+	struct zv_hdr *zv;
+
+	BUG_ON(preemptible());
+	if (pampd_is_remote(pampd)) {
+		WARN_ON(acct == false);
+		if (oid == NULL) {
+			/*
+			 * a NULL oid means to ignore this pampd free
+			 * as the remote freeing will be handled elsewhere
+			 */
+		} else if (eph) {
+			/* FIXME remote flush optional but probably good idea */
+			/* FIXME get these working properly again */
+			dec_and_check(&zcache_curr_eph_pampd_count);
+		} else if (pampd_is_intransit(pampd)) {
+			/* did a pers remote get_and_free, so just free local */
+			pampd = pampd_mask_intransit_and_remote(pampd);
+			goto local_pers;
+		} else {
+			struct flushlist_node *flnode =
+				ramster_flnode_alloc(pool);
+
+			flnode->xh.client_id = pampd_remote_node(pampd);
+			flnode->xh.pool_id = pool->pool_id;
+			flnode->xh.oid = *oid;
+			flnode->xh.index = index;
+			flnode->rem_op.op = RAMSTER_REMOTIFY_FLUSH_PAGE;
+			spin_lock(&zcache_rem_op_list_lock);
+			list_add(&flnode->rem_op.list, &zcache_rem_op_list);
+			spin_unlock(&zcache_rem_op_list_lock);
+			dec_and_check(&zcache_curr_pers_pampd_count);
+			dec_and_check(&ramster_remote_pers_pages);
+		}
+	} else if (eph) {
+		zbud_free_and_delist((struct zbud_hdr *)pampd);
+		if (!is_local_client(pool->client))
+			dec_and_check(&ramster_foreign_eph_pampd_count);
+		if (acct)
+			/* FIXME get these working properly again */
+			dec_and_check(&zcache_curr_eph_pampd_count);
+	} else {
+local_pers:
+		zv = (struct zv_hdr *)pampd;
+		if (!is_local_client(pool->client))
+			dec_and_check(&ramster_foreign_pers_pampd_count);
+		zv_free(cli->xvpool, zv);
+		if (acct)
+			/* FIXME get these working properly again */
+			dec_and_check(&zcache_curr_pers_pampd_count);
+	}
+}
+
+static void zcache_pampd_free_obj(struct tmem_pool *pool,
+					struct tmem_obj *obj)
+{
+	struct flushlist_node *flnode;
+
+	BUG_ON(preemptible());
+	if (obj->extra == NULL)
+		return;
+	BUG_ON(!pampd_is_remote(obj->extra));
+	flnode = ramster_flnode_alloc(pool);
+	flnode->xh.client_id = pampd_remote_node(obj->extra);
+	flnode->xh.pool_id = pool->pool_id;
+	flnode->xh.oid = obj->oid;
+	flnode->xh.index = FLUSH_ENTIRE_OBJECT;
+	flnode->rem_op.op = RAMSTER_REMOTIFY_FLUSH_OBJ;
+	spin_lock(&zcache_rem_op_list_lock);
+	list_add(&flnode->rem_op.list, &zcache_rem_op_list);
+	spin_unlock(&zcache_rem_op_list_lock);
+}
+
+void zcache_pampd_new_obj(struct tmem_obj *obj)
+{
+	obj->extra = NULL;
+}
+
+int zcache_pampd_replace_in_obj(void *new_pampd, struct tmem_obj *obj)
+{
+	int ret = -1;
+
+	if (new_pampd != NULL) {
+		if (obj->extra == NULL)
+			obj->extra = new_pampd;
+		/* enforce that all remote pages in an object reside
+		 * in the same node! */
+		else if (pampd_remote_node(new_pampd) !=
+				pampd_remote_node((void *)(obj->extra)))
+			BUG();
+		ret = 0;
+	}
+	return ret;
+}
+
+/*
+ * Called by the message handler after a (still compressed) page has been
+ * fetched from the remote machine in response to an "is_remote" tmem_get
+ * or persistent tmem_localify.  For a tmem_get, "extra" is the address of
+ * the page that is to be filled to succesfully resolve the tmem_get; for
+ * a (persistent) tmem_localify, "extra" is NULL (as the data is placed only
+ * in the local zcache).  "data" points to "size" bytes of (compressed) data
+ * passed in the message.  In the case of a persistent remote get, if
+ * pre-allocation was successful (see zcache_repatriate_preload), the page
+ * is placed into both local zcache and at "extra".
+ */
+int zcache_localify(int pool_id, struct tmem_oid *oidp,
+			uint32_t index, char *data, size_t size,
+			void *extra)
+{
+	int ret = -ENOENT;
+	unsigned long flags;
+	struct tmem_pool *pool;
+	bool ephemeral, delete = false;
+	size_t clen = PAGE_SIZE;
+	void *pampd, *saved_hb;
+	struct tmem_obj *obj;
+
+	pool = zcache_get_pool_by_id(LOCAL_CLIENT, pool_id);
+	if (unlikely(pool == NULL))
+		/* pool doesn't exist anymore */
+		goto out;
+	ephemeral = is_ephemeral(pool);
+	local_irq_save(flags);  /* FIXME: maybe only disable softirqs? */
+	pampd = tmem_localify_get_pampd(pool, oidp, index, &obj, &saved_hb);
+	if (pampd == NULL) {
+		/* hmmm... must have been a flush while waiting */
+#ifdef RAMSTER_TESTING
+		pr_err("UNTESTED pampd==NULL in zcache_localify\n");
+#endif
+		if (ephemeral)
+			ramster_remote_eph_pages_unsucc_get++;
+		else
+			ramster_remote_pers_pages_unsucc_get++;
+		obj = NULL;
+		goto finish;
+	} else if (unlikely(!pampd_is_remote(pampd))) {
+		/* hmmm... must have been a dup put while waiting */
+#ifdef RAMSTER_TESTING
+		pr_err("UNTESTED dup while waiting in zcache_localify\n");
+#endif
+		if (ephemeral)
+			ramster_remote_eph_pages_unsucc_get++;
+		else
+			ramster_remote_pers_pages_unsucc_get++;
+		obj = NULL;
+		pampd = NULL;
+		ret = -EEXIST;
+		goto finish;
+	} else if (size == 0) {
+		/* no remote data, delete the local is_remote pampd */
+		pampd = NULL;
+		if (ephemeral)
+			ramster_remote_eph_pages_unsucc_get++;
+		else
+			BUG();
+		delete = true;
+		goto finish;
+	}
+	if (!ephemeral && pampd_is_intransit(pampd)) {
+		/* localify to zcache */
+		pampd = pampd_mask_intransit_and_remote(pampd);
+		zv_copy_to_pampd(pampd, data, size);
+	} else {
+		pampd = NULL;
+		obj = NULL;
+	}
+	if (extra != NULL) {
+		/* decompress direct-to-memory to complete remotify */
+		ret = lzo1x_decompress_safe((char *)data, size,
+						(char *)extra, &clen);
+		BUG_ON(ret != LZO_E_OK);
+		BUG_ON(clen != PAGE_SIZE);
+	}
+	if (ephemeral)
+		ramster_remote_eph_pages_succ_get++;
+	else
+		ramster_remote_pers_pages_succ_get++;
+	ret = 0;
+finish:
+	tmem_localify_finish(obj, index, pampd, saved_hb, delete);
+	zcache_put_pool(pool);
+	local_irq_restore(flags);
+out:
+	return ret;
+}
+
+/*
+ * Called on a remote persistent tmem_get to attempt to preallocate
+ * local storage for the data contained in the remote persistent page.
+ * If succesfully preallocated, returns the pampd, marked as remote and
+ * in_transit.  Else returns NULL.  Note that the appropriate tmem data
+ * structure must be locked.
+ */
+static void *zcache_pampd_repatriate_preload(void *pampd,
+						struct tmem_pool *pool,
+						struct tmem_oid *oid,
+						uint32_t index,
+						bool *intransit)
+{
+	int clen = pampd_remote_size(pampd);
+	void *ret_pampd = NULL;
+	unsigned long flags;
+
+	if (!pampd_is_remote(pampd))
+		BUG();
+	if (is_ephemeral(pool))
+		BUG();
+	if (pampd_is_intransit(pampd)) {
+		/*
+		 * to avoid multiple allocations (and maybe a memory leak)
+		 * don't preallocate if already in the process of being
+		 * repatriated
+		 */
+		*intransit = true;
+		goto out;
+	}
+	*intransit = false;
+	local_irq_save(flags);
+	ret_pampd = (void *)zv_alloc(pool, oid, index, clen);
+	if (ret_pampd != NULL) {
+		/*
+		 *  a pampd is marked intransit if it is remote and space has
+		 *  been allocated for it locally (note, only happens for
+		 *  persistent pages, in which case the remote copy is freed)
+		 */
+		ret_pampd = pampd_mark_intransit(ret_pampd);
+		dec_and_check(&ramster_remote_pers_pages);
+	} else
+		ramster_pers_pages_remote_nomem++;
+	local_irq_restore(flags);
+out:
+	return ret_pampd;
+}
+
+/*
+ * Called on a remote tmem_get to invoke a message to fetch the page.
+ * Might sleep so no tmem locks can be held.  "extra" is passed
+ * all the way through the round-trip messaging to zcache_localify.
+ */
+static int zcache_pampd_repatriate(void *fake_pampd, void *real_pampd,
+				   struct tmem_pool *pool,
+				   struct tmem_oid *oid, uint32_t index,
+				   bool free, void *extra)
+{
+	struct tmem_xhandle xh;
+	int ret;
+
+	if (pampd_is_intransit(real_pampd))
+		/* have local space pre-reserved, so free remote copy */
+		free = true;
+	xh = tmem_xhandle_fill(LOCAL_CLIENT, pool, oid, index);
+	/* unreliable request/response for now */
+	ret = ramster_remote_async_get(&xh, free,
+					pampd_remote_node(fake_pampd),
+					pampd_remote_size(fake_pampd),
+					pampd_remote_cksum(fake_pampd),
+					extra);
+#ifdef RAMSTER_TESTING
+	if (ret != 0 && ret != -ENOENT)
+		pr_err("TESTING zcache_pampd_repatriate returns, ret=%d\n",
+			ret);
+#endif
+	return ret;
+}
+
+static struct tmem_pamops zcache_pamops = {
+	.create = zcache_pampd_create,
+	.get_data = zcache_pampd_get_data,
+	.free = zcache_pampd_free,
+	.get_data_and_free = zcache_pampd_get_data_and_free,
+	.free_obj = zcache_pampd_free_obj,
+	.is_remote = zcache_pampd_is_remote,
+	.repatriate_preload = zcache_pampd_repatriate_preload,
+	.repatriate = zcache_pampd_repatriate,
+	.new_obj = zcache_pampd_new_obj,
+	.replace_in_obj = zcache_pampd_replace_in_obj,
+};
+
+/*
+ * zcache compression/decompression and related per-cpu stuff
+ */
+
+#define LZO_WORKMEM_BYTES LZO1X_1_MEM_COMPRESS
+#define LZO_DSTMEM_PAGE_ORDER 1
+static DEFINE_PER_CPU(unsigned char *, zcache_workmem);
+static DEFINE_PER_CPU(unsigned char *, zcache_dstmem);
+
+static int zcache_compress(struct page *from, void **out_va, size_t *out_len)
+{
+	int ret = 0;
+	unsigned char *dmem = __get_cpu_var(zcache_dstmem);
+	unsigned char *wmem = __get_cpu_var(zcache_workmem);
+	char *from_va;
+
+	BUG_ON(!irqs_disabled());
+	if (unlikely(dmem == NULL || wmem == NULL))
+		goto out;  /* no buffer, so can't compress */
+	from_va = kmap_atomic(from, KM_USER0);
+	mb();
+	ret = lzo1x_1_compress(from_va, PAGE_SIZE, dmem, out_len, wmem);
+	BUG_ON(ret != LZO_E_OK);
+	*out_va = dmem;
+	kunmap_atomic(from_va, KM_USER0);
+	ret = 1;
+out:
+	return ret;
+}
+
+
+static int zcache_cpu_notifier(struct notifier_block *nb,
+				unsigned long action, void *pcpu)
+{
+	int cpu = (long)pcpu;
+	struct zcache_preload *kp;
+
+	switch (action) {
+	case CPU_UP_PREPARE:
+		per_cpu(zcache_dstmem, cpu) = (void *)__get_free_pages(
+			GFP_KERNEL | __GFP_REPEAT,
+			LZO_DSTMEM_PAGE_ORDER),
+		per_cpu(zcache_workmem, cpu) =
+			kzalloc(LZO1X_MEM_COMPRESS,
+				GFP_KERNEL | __GFP_REPEAT);
+		per_cpu(zcache_remoteputmem, cpu) =
+			kzalloc(PAGE_SIZE, GFP_KERNEL | __GFP_REPEAT);
+		break;
+	case CPU_DEAD:
+	case CPU_UP_CANCELED:
+		kfree(per_cpu(zcache_remoteputmem, cpu));
+		per_cpu(zcache_remoteputmem, cpu) = NULL;
+		free_pages((unsigned long)per_cpu(zcache_dstmem, cpu),
+				LZO_DSTMEM_PAGE_ORDER);
+		per_cpu(zcache_dstmem, cpu) = NULL;
+		kfree(per_cpu(zcache_workmem, cpu));
+		per_cpu(zcache_workmem, cpu) = NULL;
+		kp = &per_cpu(zcache_preloads, cpu);
+		while (kp->nr) {
+			kmem_cache_free(zcache_objnode_cache,
+					kp->objnodes[kp->nr - 1]);
+			kp->objnodes[kp->nr - 1] = NULL;
+			kp->nr--;
+		}
+		if (kp->obj) {
+			kmem_cache_free(zcache_obj_cache, kp->obj);
+			kp->obj = NULL;
+		}
+		if (kp->flnode) {
+			kmem_cache_free(ramster_flnode_cache, kp->flnode);
+			kp->flnode = NULL;
+		}
+		if (kp->page) {
+			free_page((unsigned long)kp->page);
+			kp->page = NULL;
+		}
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block zcache_cpu_notifier_block = {
+	.notifier_call = zcache_cpu_notifier
+};
+
+#ifdef CONFIG_SYSFS
+#define ZCACHE_SYSFS_RO(_name) \
+	static ssize_t zcache_##_name##_show(struct kobject *kobj, \
+				struct kobj_attribute *attr, char *buf) \
+	{ \
+		return sprintf(buf, "%lu\n", zcache_##_name); \
+	} \
+	static struct kobj_attribute zcache_##_name##_attr = { \
+		.attr = { .name = __stringify(_name), .mode = 0444 }, \
+		.show = zcache_##_name##_show, \
+	}
+
+#define ZCACHE_SYSFS_RO_ATOMIC(_name) \
+	static ssize_t zcache_##_name##_show(struct kobject *kobj, \
+				struct kobj_attribute *attr, char *buf) \
+	{ \
+	    return sprintf(buf, "%d\n", atomic_read(&zcache_##_name)); \
+	} \
+	static struct kobj_attribute zcache_##_name##_attr = { \
+		.attr = { .name = __stringify(_name), .mode = 0444 }, \
+		.show = zcache_##_name##_show, \
+	}
+
+#define ZCACHE_SYSFS_RO_CUSTOM(_name, _func) \
+	static ssize_t zcache_##_name##_show(struct kobject *kobj, \
+				struct kobj_attribute *attr, char *buf) \
+	{ \
+	    return _func(buf); \
+	} \
+	static struct kobj_attribute zcache_##_name##_attr = { \
+		.attr = { .name = __stringify(_name), .mode = 0444 }, \
+		.show = zcache_##_name##_show, \
+	}
+
+ZCACHE_SYSFS_RO(curr_obj_count_max);
+ZCACHE_SYSFS_RO(curr_objnode_count_max);
+ZCACHE_SYSFS_RO(flush_total);
+ZCACHE_SYSFS_RO(flush_found);
+ZCACHE_SYSFS_RO(flobj_total);
+ZCACHE_SYSFS_RO(flobj_found);
+ZCACHE_SYSFS_RO(failed_eph_puts);
+ZCACHE_SYSFS_RO(nonactive_puts);
+ZCACHE_SYSFS_RO(failed_pers_puts);
+ZCACHE_SYSFS_RO(zbud_curr_zbytes);
+ZCACHE_SYSFS_RO(zbud_cumul_zpages);
+ZCACHE_SYSFS_RO(zbud_cumul_zbytes);
+ZCACHE_SYSFS_RO(zbud_buddied_count);
+ZCACHE_SYSFS_RO(evicted_raw_pages);
+ZCACHE_SYSFS_RO(evicted_unbuddied_pages);
+ZCACHE_SYSFS_RO(evicted_buddied_pages);
+ZCACHE_SYSFS_RO(failed_get_free_pages);
+ZCACHE_SYSFS_RO(failed_alloc);
+ZCACHE_SYSFS_RO(put_to_flush);
+ZCACHE_SYSFS_RO(compress_poor);
+ZCACHE_SYSFS_RO(mean_compress_poor);
+ZCACHE_SYSFS_RO(policy_percent_exceeded);
+ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_raw_pages);
+ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_zpages);
+ZCACHE_SYSFS_RO_ATOMIC(curr_obj_count);
+ZCACHE_SYSFS_RO_ATOMIC(curr_objnode_count);
+ZCACHE_SYSFS_RO_CUSTOM(zbud_unbuddied_list_counts,
+			zbud_show_unbuddied_list_counts);
+ZCACHE_SYSFS_RO_CUSTOM(zbud_cumul_chunk_counts,
+			zbud_show_cumul_chunk_counts);
+ZCACHE_SYSFS_RO_CUSTOM(zv_curr_dist_counts,
+			zv_curr_dist_counts_show);
+ZCACHE_SYSFS_RO_CUSTOM(zv_cumul_dist_counts,
+			zv_cumul_dist_counts_show);
+
+static struct attribute *zcache_attrs[] = {
+	&zcache_curr_obj_count_attr.attr,
+	&zcache_curr_obj_count_max_attr.attr,
+	&zcache_curr_objnode_count_attr.attr,
+	&zcache_curr_objnode_count_max_attr.attr,
+	&zcache_flush_total_attr.attr,
+	&zcache_flobj_total_attr.attr,
+	&zcache_flush_found_attr.attr,
+	&zcache_flobj_found_attr.attr,
+	&zcache_failed_eph_puts_attr.attr,
+	&zcache_nonactive_puts_attr.attr,
+	&zcache_failed_pers_puts_attr.attr,
+	&zcache_policy_percent_exceeded_attr.attr,
+	&zcache_compress_poor_attr.attr,
+	&zcache_mean_compress_poor_attr.attr,
+	&zcache_zbud_curr_raw_pages_attr.attr,
+	&zcache_zbud_curr_zpages_attr.attr,
+	&zcache_zbud_curr_zbytes_attr.attr,
+	&zcache_zbud_cumul_zpages_attr.attr,
+	&zcache_zbud_cumul_zbytes_attr.attr,
+	&zcache_zbud_buddied_count_attr.attr,
+	&zcache_evicted_raw_pages_attr.attr,
+	&zcache_evicted_unbuddied_pages_attr.attr,
+	&zcache_evicted_buddied_pages_attr.attr,
+	&zcache_failed_get_free_pages_attr.attr,
+	&zcache_failed_alloc_attr.attr,
+	&zcache_put_to_flush_attr.attr,
+	&zcache_zbud_unbuddied_list_counts_attr.attr,
+	&zcache_zbud_cumul_chunk_counts_attr.attr,
+	&zcache_zv_curr_dist_counts_attr.attr,
+	&zcache_zv_cumul_dist_counts_attr.attr,
+	&zcache_zv_max_zsize_attr.attr,
+	&zcache_zv_max_mean_zsize_attr.attr,
+	&zcache_zv_page_count_policy_percent_attr.attr,
+	NULL,
+};
+
+static struct attribute_group zcache_attr_group = {
+	.attrs = zcache_attrs,
+	.name = "zcache",
+};
+
+#define RAMSTER_SYSFS_RO(_name) \
+	static ssize_t ramster_##_name##_show(struct kobject *kobj, \
+				struct kobj_attribute *attr, char *buf) \
+	{ \
+		return sprintf(buf, "%lu\n", ramster_##_name); \
+	} \
+	static struct kobj_attribute ramster_##_name##_attr = { \
+		.attr = { .name = __stringify(_name), .mode = 0444 }, \
+		.show = ramster_##_name##_show, \
+	}
+
+#define RAMSTER_SYSFS_RW(_name) \
+	static ssize_t ramster_##_name##_show(struct kobject *kobj, \
+				struct kobj_attribute *attr, char *buf) \
+	{ \
+		return sprintf(buf, "%lu\n", ramster_##_name); \
+	} \
+	static ssize_t ramster_##_name##_store(struct kobject *kobj, \
+		struct kobj_attribute *attr, const char *buf, size_t count) \
+	{ \
+		int err; \
+		unsigned long enable; \
+		err = kstrtoul(buf, 10, &enable); \
+		if (err) \
+			return -EINVAL; \
+		ramster_##_name = enable; \
+		return count; \
+	} \
+	static struct kobj_attribute ramster_##_name##_attr = { \
+		.attr = { .name = __stringify(_name), .mode = 0644 }, \
+		.show = ramster_##_name##_show, \
+		.store = ramster_##_name##_store, \
+	}
+
+#define RAMSTER_SYSFS_RO_ATOMIC(_name) \
+	static ssize_t ramster_##_name##_show(struct kobject *kobj, \
+				struct kobj_attribute *attr, char *buf) \
+	{ \
+	    return sprintf(buf, "%d\n", atomic_read(&ramster_##_name)); \
+	} \
+	static struct kobj_attribute ramster_##_name##_attr = { \
+		.attr = { .name = __stringify(_name), .mode = 0444 }, \
+		.show = ramster_##_name##_show, \
+	}
+
+RAMSTER_SYSFS_RO(interface_revision);
+RAMSTER_SYSFS_RO_ATOMIC(remote_pers_pages);
+RAMSTER_SYSFS_RW(pers_remotify_enable);
+RAMSTER_SYSFS_RW(eph_remotify_enable);
+RAMSTER_SYSFS_RO(eph_pages_remoted);
+RAMSTER_SYSFS_RO(eph_pages_remote_failed);
+RAMSTER_SYSFS_RO(pers_pages_remoted);
+RAMSTER_SYSFS_RO(pers_pages_remote_failed);
+RAMSTER_SYSFS_RO(pers_pages_remote_nomem);
+RAMSTER_SYSFS_RO(remote_pages_flushed);
+RAMSTER_SYSFS_RO(remote_page_flushes_failed);
+RAMSTER_SYSFS_RO(remote_objects_flushed);
+RAMSTER_SYSFS_RO(remote_object_flushes_failed);
+RAMSTER_SYSFS_RO(remote_eph_pages_succ_get);
+RAMSTER_SYSFS_RO(remote_eph_pages_unsucc_get);
+RAMSTER_SYSFS_RO(remote_pers_pages_succ_get);
+RAMSTER_SYSFS_RO(remote_pers_pages_unsucc_get);
+RAMSTER_SYSFS_RO_ATOMIC(foreign_eph_pampd_count);
+RAMSTER_SYSFS_RO(foreign_eph_pampd_count_max);
+RAMSTER_SYSFS_RO_ATOMIC(foreign_pers_pampd_count);
+RAMSTER_SYSFS_RO(foreign_pers_pampd_count_max);
+RAMSTER_SYSFS_RO_ATOMIC(curr_flnode_count);
+RAMSTER_SYSFS_RO(curr_flnode_count_max);
+
+#define MANUAL_NODES 8
+static bool ramster_nodes_manual_up[MANUAL_NODES];
+static ssize_t ramster_manual_node_up_show(struct kobject *kobj,
+				struct kobj_attribute *attr, char *buf)
+{
+	int i;
+	char *p = buf;
+	for (i = 0; i < MANUAL_NODES; i++)
+		if (ramster_nodes_manual_up[i])
+			p += sprintf(p, "%d ", i);
+	p += sprintf(p, "\n");
+	return p - buf;
+}
+
+static ssize_t ramster_manual_node_up_store(struct kobject *kobj,
+		struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int err;
+	unsigned long node_num;
+
+	err = kstrtoul(buf, 10, &node_num);
+	if (err) {
+		pr_err("ramster: bad strtoul?\n");
+		return -EINVAL;
+	}
+	if (node_num >= MANUAL_NODES) {
+		pr_err("ramster: bad node_num=%lu?\n", node_num);
+		return -EINVAL;
+	}
+	if (ramster_nodes_manual_up[node_num]) {
+		pr_err("ramster: node %d already up, ignoring\n",
+							(int)node_num);
+	} else {
+		ramster_nodes_manual_up[node_num] = true;
+		r2net_hb_node_up_manual((int)node_num);
+	}
+	return count;
+}
+
+static struct kobj_attribute ramster_manual_node_up_attr = {
+	.attr = { .name = "manual_node_up", .mode = 0644 },
+	.show = ramster_manual_node_up_show,
+	.store = ramster_manual_node_up_store,
+};
+
+static ssize_t ramster_remote_target_nodenum_show(struct kobject *kobj,
+				struct kobj_attribute *attr, char *buf)
+{
+	if (ramster_remote_target_nodenum == -1UL)
+		return sprintf(buf, "unset\n");
+	else
+		return sprintf(buf, "%d\n", ramster_remote_target_nodenum);
+}
+
+static ssize_t ramster_remote_target_nodenum_store(struct kobject *kobj,
+		struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int err;
+	unsigned long node_num;
+
+	err = kstrtoul(buf, 10, &node_num);
+	if (err) {
+		pr_err("ramster: bad strtoul?\n");
+		return -EINVAL;
+	} else if (node_num == -1UL) {
+		pr_err("ramster: disabling all remotification, "
+			"data may still reside on remote nodes however\n");
+		return -EINVAL;
+	} else if (node_num >= MANUAL_NODES) {
+		pr_err("ramster: bad node_num=%lu?\n", node_num);
+		return -EINVAL;
+	} else if (!ramster_nodes_manual_up[node_num]) {
+		pr_err("ramster: node %d not up, ignoring setting "
+			"of remotification target\n", (int)node_num);
+	} else if (r2net_remote_target_node_set((int)node_num) >= 0) {
+		pr_info("ramster: node %d set as remotification target\n",
+				(int)node_num);
+		ramster_remote_target_nodenum = (int)node_num;
+	} else {
+		pr_err("ramster: bad num to node node_num=%d?\n",
+				(int)node_num);
+		return -EINVAL;
+	}
+	return count;
+}
+
+static struct kobj_attribute ramster_remote_target_nodenum_attr = {
+	.attr = { .name = "remote_target_nodenum", .mode = 0644 },
+	.show = ramster_remote_target_nodenum_show,
+	.store = ramster_remote_target_nodenum_store,
+};
+
+
+static struct attribute *ramster_attrs[] = {
+	&ramster_interface_revision_attr.attr,
+	&ramster_pers_remotify_enable_attr.attr,
+	&ramster_eph_remotify_enable_attr.attr,
+	&ramster_remote_pers_pages_attr.attr,
+	&ramster_eph_pages_remoted_attr.attr,
+	&ramster_eph_pages_remote_failed_attr.attr,
+	&ramster_pers_pages_remoted_attr.attr,
+	&ramster_pers_pages_remote_failed_attr.attr,
+	&ramster_pers_pages_remote_nomem_attr.attr,
+	&ramster_remote_pages_flushed_attr.attr,
+	&ramster_remote_page_flushes_failed_attr.attr,
+	&ramster_remote_objects_flushed_attr.attr,
+	&ramster_remote_object_flushes_failed_attr.attr,
+	&ramster_remote_eph_pages_succ_get_attr.attr,
+	&ramster_remote_eph_pages_unsucc_get_attr.attr,
+	&ramster_remote_pers_pages_succ_get_attr.attr,
+	&ramster_remote_pers_pages_unsucc_get_attr.attr,
+	&ramster_foreign_eph_pampd_count_attr.attr,
+	&ramster_foreign_eph_pampd_count_max_attr.attr,
+	&ramster_foreign_pers_pampd_count_attr.attr,
+	&ramster_foreign_pers_pampd_count_max_attr.attr,
+	&ramster_curr_flnode_count_attr.attr,
+	&ramster_curr_flnode_count_max_attr.attr,
+	&ramster_manual_node_up_attr.attr,
+	&ramster_remote_target_nodenum_attr.attr,
+	NULL,
+};
+
+static struct attribute_group ramster_attr_group = {
+	.attrs = ramster_attrs,
+	.name = "ramster",
+};
+
+#endif /* CONFIG_SYSFS */
+/*
+ * When zcache is disabled ("frozen"), pools can be created and destroyed,
+ * but all puts (and thus all other operations that require memory allocation)
+ * must fail.  If zcache is unfrozen, accepts puts, then frozen again,
+ * data consistency requires all puts while frozen to be converted into
+ * flushes.
+ */
+static bool zcache_freeze;
+
+/*
+ * zcache shrinker interface (only useful for ephemeral pages, so zbud only)
+ */
+static int shrink_zcache_memory(struct shrinker *shrink,
+				struct shrink_control *sc)
+{
+	int ret = -1;
+	int nr = sc->nr_to_scan;
+	gfp_t gfp_mask = sc->gfp_mask;
+
+	if (nr >= 0) {
+		if (!(gfp_mask & __GFP_FS))
+			/* does this case really need to be skipped? */
+			goto out;
+		zbud_evict_pages(nr);
+	}
+	ret = (int)atomic_read(&zcache_zbud_curr_raw_pages);
+out:
+	return ret;
+}
+
+static struct shrinker zcache_shrinker = {
+	.shrink = shrink_zcache_memory,
+	.seeks = DEFAULT_SEEKS,
+};
+
+/*
+ * zcache shims between cleancache/frontswap ops and tmem
+ */
+
+int zcache_put(int cli_id, int pool_id, struct tmem_oid *oidp,
+			uint32_t index, char *data, size_t size,
+			bool raw, int ephemeral)
+{
+	struct tmem_pool *pool;
+	int ret = -1;
+
+	BUG_ON(!irqs_disabled());
+	pool = zcache_get_pool_by_id(cli_id, pool_id);
+	if (unlikely(pool == NULL))
+		goto out;
+	if (!zcache_freeze && zcache_do_preload(pool) == 0) {
+		/* preload does preempt_disable on success */
+		ret = tmem_put(pool, oidp, index, data, size, raw, ephemeral);
+		if (ret < 0) {
+			if (is_ephemeral(pool))
+				zcache_failed_eph_puts++;
+			else
+				zcache_failed_pers_puts++;
+		}
+		zcache_put_pool(pool);
+		preempt_enable_no_resched();
+	} else {
+		zcache_put_to_flush++;
+		if (atomic_read(&pool->obj_count) > 0)
+			/* the put fails whether the flush succeeds or not */
+			(void)tmem_flush_page(pool, oidp, index);
+		zcache_put_pool(pool);
+	}
+out:
+	return ret;
+}
+
+int zcache_get(int cli_id, int pool_id, struct tmem_oid *oidp,
+			uint32_t index, char *data, size_t *sizep,
+			bool raw, int get_and_free)
+{
+	struct tmem_pool *pool;
+	int ret = -1;
+	bool eph;
+
+	if (!raw) {
+		BUG_ON(irqs_disabled());
+		BUG_ON(in_softirq());
+	}
+	pool = zcache_get_pool_by_id(cli_id, pool_id);
+	eph = is_ephemeral(pool);
+	if (likely(pool != NULL)) {
+		if (atomic_read(&pool->obj_count) > 0)
+			ret = tmem_get(pool, oidp, index, data, sizep,
+					raw, get_and_free);
+		zcache_put_pool(pool);
+	}
+	WARN_ONCE((!eph && (ret != 0)), "zcache_get fails on persistent pool, "
+			  "bad things are very likely to happen soon\n");
+#ifdef RAMSTER_TESTING
+	if (ret != 0 && ret != -1 && !(ret == -EINVAL && is_ephemeral(pool)))
+		pr_err("TESTING zcache_get tmem_get returns ret=%d\n", ret);
+#endif
+	if (ret == -EAGAIN)
+		BUG(); /* FIXME... don't need this anymore??? let's ensure */
+	return ret;
+}
+
+int zcache_flush(int cli_id, int pool_id,
+				struct tmem_oid *oidp, uint32_t index)
+{
+	struct tmem_pool *pool;
+	int ret = -1;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	zcache_flush_total++;
+	pool = zcache_get_pool_by_id(cli_id, pool_id);
+	ramster_do_preload_flnode_only(pool);
+	if (likely(pool != NULL)) {
+		if (atomic_read(&pool->obj_count) > 0)
+			ret = tmem_flush_page(pool, oidp, index);
+		zcache_put_pool(pool);
+	}
+	if (ret >= 0)
+		zcache_flush_found++;
+	local_irq_restore(flags);
+	return ret;
+}
+
+int zcache_flush_object(int cli_id, int pool_id, struct tmem_oid *oidp)
+{
+	struct tmem_pool *pool;
+	int ret = -1;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	zcache_flobj_total++;
+	pool = zcache_get_pool_by_id(cli_id, pool_id);
+	ramster_do_preload_flnode_only(pool);
+	if (likely(pool != NULL)) {
+		if (atomic_read(&pool->obj_count) > 0)
+			ret = tmem_flush_object(pool, oidp);
+		zcache_put_pool(pool);
+	}
+	if (ret >= 0)
+		zcache_flobj_found++;
+	local_irq_restore(flags);
+	return ret;
+}
+
+int zcache_client_destroy_pool(int cli_id, int pool_id)
+{
+	struct tmem_pool *pool = NULL;
+	struct zcache_client *cli = NULL;
+	int ret = -1;
+
+	if (pool_id < 0)
+		goto out;
+	if (cli_id == LOCAL_CLIENT)
+		cli = &zcache_host;
+	else if ((unsigned int)cli_id < MAX_CLIENTS)
+		cli = &zcache_clients[cli_id];
+	if (cli == NULL)
+		goto out;
+	atomic_inc(&cli->refcount);
+	pool = cli->tmem_pools[pool_id];
+	if (pool == NULL)
+		goto out;
+	cli->tmem_pools[pool_id] = NULL;
+	/* wait for pool activity on other cpus to quiesce */
+	while (atomic_read(&pool->refcount) != 0)
+		;
+	atomic_dec(&cli->refcount);
+	local_bh_disable();
+	ret = tmem_destroy_pool(pool);
+	local_bh_enable();
+	kfree(pool);
+	pr_info("ramster: destroyed pool id=%d cli_id=%d\n", pool_id, cli_id);
+out:
+	return ret;
+}
+
+static int zcache_destroy_pool(int pool_id)
+{
+	return zcache_client_destroy_pool(LOCAL_CLIENT, pool_id);
+}
+
+int zcache_new_pool(uint16_t cli_id, uint32_t flags)
+{
+	int poolid = -1;
+	struct tmem_pool *pool;
+	struct zcache_client *cli = NULL;
+
+	if (cli_id == LOCAL_CLIENT)
+		cli = &zcache_host;
+	else if ((unsigned int)cli_id < MAX_CLIENTS)
+		cli = &zcache_clients[cli_id];
+	if (cli == NULL)
+		goto out;
+	atomic_inc(&cli->refcount);
+	pool = kmalloc(sizeof(struct tmem_pool), GFP_ATOMIC);
+	if (pool == NULL) {
+		pr_info("ramster: pool creation failed: out of memory\n");
+		goto out;
+	}
+
+	for (poolid = 0; poolid < MAX_POOLS_PER_CLIENT; poolid++)
+		if (cli->tmem_pools[poolid] == NULL)
+			break;
+	if (poolid >= MAX_POOLS_PER_CLIENT) {
+		pr_info("ramster: pool creation failed: max exceeded\n");
+		kfree(pool);
+		poolid = -1;
+		goto out;
+	}
+	atomic_set(&pool->refcount, 0);
+	pool->client = cli;
+	pool->pool_id = poolid;
+	tmem_new_pool(pool, flags);
+	cli->tmem_pools[poolid] = pool;
+	if (cli_id == LOCAL_CLIENT)
+		pr_info("ramster: created %s tmem pool, id=%d, local client\n",
+			flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
+			poolid);
+	else
+		pr_info("ramster: created %s tmem pool, id=%d, client=%d\n",
+			flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
+			poolid, cli_id);
+out:
+	if (cli != NULL)
+		atomic_dec(&cli->refcount);
+	return poolid;
+}
+
+static int zcache_local_new_pool(uint32_t flags)
+{
+	return zcache_new_pool(LOCAL_CLIENT, flags);
+}
+
+int zcache_autocreate_pool(int cli_id, int pool_id, bool ephemeral)
+{
+	struct tmem_pool *pool;
+	struct zcache_client *cli = NULL;
+	uint32_t flags = ephemeral ? 0 : TMEM_POOL_PERSIST;
+	int ret = -1;
+
+	if (cli_id == LOCAL_CLIENT)
+		goto out;
+	if (pool_id >= MAX_POOLS_PER_CLIENT)
+		goto out;
+	else if ((unsigned int)cli_id < MAX_CLIENTS)
+		cli = &zcache_clients[cli_id];
+	if ((ephemeral && !use_cleancache) || (!ephemeral && !use_frontswap))
+		BUG(); /* FIXME, handle more gracefully later */
+	if (!cli->allocated) {
+		if (zcache_new_client(cli_id))
+			BUG(); /* FIXME, handle more gracefully later */
+		cli = &zcache_clients[cli_id];
+	}
+	atomic_inc(&cli->refcount);
+	pool = cli->tmem_pools[pool_id];
+	if (pool != NULL) {
+		if (pool->persistent && ephemeral) {
+			pr_err("zcache_autocreate_pool: type mismatch\n");
+			goto out;
+		}
+		ret = 0;
+		goto out;
+	}
+	pool = kmalloc(sizeof(struct tmem_pool), GFP_KERNEL);
+	if (pool == NULL) {
+		pr_info("ramster: pool creation failed: out of memory\n");
+		goto out;
+	}
+	atomic_set(&pool->refcount, 0);
+	pool->client = cli;
+	pool->pool_id = pool_id;
+	tmem_new_pool(pool, flags);
+	cli->tmem_pools[pool_id] = pool;
+	pr_info("ramster: AUTOcreated %s tmem poolid=%d, for remote client=%d\n",
+		flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
+		pool_id, cli_id);
+	ret = 0;
+out:
+	if (cli == NULL)
+		BUG(); /* FIXME, handle more gracefully later */
+		/* pr_err("zcache_autocreate_pool: failed\n"); */
+	if (cli != NULL)
+		atomic_dec(&cli->refcount);
+	return ret;
+}
+
+/**********
+ * Two kernel functionalities currently can be layered on top of tmem.
+ * These are "cleancache" which is used as a second-chance cache for clean
+ * page cache pages; and "frontswap" which is used for swap pages
+ * to avoid writes to disk.  A generic "shim" is provided here for each
+ * to translate in-kernel semantics to zcache semantics.
+ */
+
+#ifdef CONFIG_CLEANCACHE
+static void zcache_cleancache_put_page(int pool_id,
+					struct cleancache_filekey key,
+					pgoff_t index, struct page *page)
+{
+	u32 ind = (u32) index;
+	struct tmem_oid oid = *(struct tmem_oid *)&key;
+
+#ifdef __PG_WAS_ACTIVE
+	if (!PageWasActive(page)) {
+		zcache_nonactive_puts++;
+		return;
+	}
+#endif
+	if (likely(ind == index)) {
+		char *kva = page_address(page);
+
+		(void)zcache_put(LOCAL_CLIENT, pool_id, &oid, index,
+			kva, PAGE_SIZE, 0, 1);
+	}
+}
+
+static int zcache_cleancache_get_page(int pool_id,
+					struct cleancache_filekey key,
+					pgoff_t index, struct page *page)
+{
+	u32 ind = (u32) index;
+	struct tmem_oid oid = *(struct tmem_oid *)&key;
+	int ret = -1;
+
+	preempt_disable();
+	if (likely(ind == index)) {
+		char *kva = page_address(page);
+		size_t size = PAGE_SIZE;
+
+		ret = zcache_get(LOCAL_CLIENT, pool_id, &oid, index,
+			kva, &size, 0, 0);
+#ifdef __PG_WAS_ACTIVE
+		if (ret == 0)
+			SetPageWasActive(page);
+#endif
+	}
+	preempt_enable();
+	return ret;
+}
+
+static void zcache_cleancache_flush_page(int pool_id,
+					struct cleancache_filekey key,
+					pgoff_t index)
+{
+	u32 ind = (u32) index;
+	struct tmem_oid oid = *(struct tmem_oid *)&key;
+
+	if (likely(ind == index))
+		(void)zcache_flush(LOCAL_CLIENT, pool_id, &oid, ind);
+}
+
+static void zcache_cleancache_flush_inode(int pool_id,
+					struct cleancache_filekey key)
+{
+	struct tmem_oid oid = *(struct tmem_oid *)&key;
+
+	(void)zcache_flush_object(LOCAL_CLIENT, pool_id, &oid);
+}
+
+static void zcache_cleancache_flush_fs(int pool_id)
+{
+	if (pool_id >= 0)
+		(void)zcache_destroy_pool(pool_id);
+}
+
+static int zcache_cleancache_init_fs(size_t pagesize)
+{
+	BUG_ON(sizeof(struct cleancache_filekey) !=
+				sizeof(struct tmem_oid));
+	BUG_ON(pagesize != PAGE_SIZE);
+	return zcache_local_new_pool(0);
+}
+
+static int zcache_cleancache_init_shared_fs(char *uuid, size_t pagesize)
+{
+	/* shared pools are unsupported and map to private */
+	BUG_ON(sizeof(struct cleancache_filekey) !=
+				sizeof(struct tmem_oid));
+	BUG_ON(pagesize != PAGE_SIZE);
+	return zcache_local_new_pool(0);
+}
+
+static struct cleancache_ops zcache_cleancache_ops = {
+	.put_page = zcache_cleancache_put_page,
+	.get_page = zcache_cleancache_get_page,
+	.invalidate_page = zcache_cleancache_flush_page,
+	.invalidate_inode = zcache_cleancache_flush_inode,
+	.invalidate_fs = zcache_cleancache_flush_fs,
+	.init_shared_fs = zcache_cleancache_init_shared_fs,
+	.init_fs = zcache_cleancache_init_fs
+};
+
+struct cleancache_ops zcache_cleancache_register_ops(void)
+{
+	struct cleancache_ops old_ops =
+		cleancache_register_ops(&zcache_cleancache_ops);
+
+	return old_ops;
+}
+#endif
+
+#ifdef CONFIG_FRONTSWAP
+/* a single tmem poolid is used for all frontswap "types" (swapfiles) */
+static int zcache_frontswap_poolid = -1;
+
+/*
+ * Swizzling increases objects per swaptype, increasing tmem concurrency
+ * for heavy swaploads.  Later, larger nr_cpus -> larger SWIZ_BITS
+ */
+#define SWIZ_BITS		8
+#define SWIZ_MASK		((1 << SWIZ_BITS) - 1)
+#define _oswiz(_type, _ind)	((_type << SWIZ_BITS) | (_ind & SWIZ_MASK))
+#define iswiz(_ind)		(_ind >> SWIZ_BITS)
+
+static inline struct tmem_oid oswiz(unsigned type, u32 ind)
+{
+	struct tmem_oid oid = { .oid = { 0 } };
+	oid.oid[0] = _oswiz(type, ind);
+	return oid;
+}
+
+static int zcache_frontswap_put_page(unsigned type, pgoff_t offset,
+				   struct page *page)
+{
+	u64 ind64 = (u64)offset;
+	u32 ind = (u32)offset;
+	struct tmem_oid oid = oswiz(type, ind);
+	int ret = -1;
+	unsigned long flags;
+	char *kva;
+
+	BUG_ON(!PageLocked(page));
+	if (likely(ind64 == ind)) {
+		local_irq_save(flags);
+		kva = page_address(page);
+		ret = zcache_put(LOCAL_CLIENT, zcache_frontswap_poolid,
+				&oid, iswiz(ind), kva, PAGE_SIZE, 0, 0);
+		local_irq_restore(flags);
+	}
+	return ret;
+}
+
+/* returns 0 if the page was successfully gotten from frontswap, -1 if
+ * was not present (should never happen!) */
+static int zcache_frontswap_get_page(unsigned type, pgoff_t offset,
+				   struct page *page)
+{
+	u64 ind64 = (u64)offset;
+	u32 ind = (u32)offset;
+	struct tmem_oid oid = oswiz(type, ind);
+	int ret = -1;
+
+	preempt_disable(); /* FIXME, remove this? */
+	BUG_ON(!PageLocked(page));
+	if (likely(ind64 == ind)) {
+		char *kva = page_address(page);
+		size_t size = PAGE_SIZE;
+
+		ret = zcache_get(LOCAL_CLIENT, zcache_frontswap_poolid,
+					&oid, iswiz(ind), kva, &size, 0, -1);
+	}
+	preempt_enable(); /* FIXME, remove this? */
+	return ret;
+}
+
+/* flush a single page from frontswap */
+static void zcache_frontswap_flush_page(unsigned type, pgoff_t offset)
+{
+	u64 ind64 = (u64)offset;
+	u32 ind = (u32)offset;
+	struct tmem_oid oid = oswiz(type, ind);
+
+	if (likely(ind64 == ind))
+		(void)zcache_flush(LOCAL_CLIENT, zcache_frontswap_poolid,
+					&oid, iswiz(ind));
+}
+
+/* flush all pages from the passed swaptype */
+static void zcache_frontswap_flush_area(unsigned type)
+{
+	struct tmem_oid oid;
+	int ind;
+
+	for (ind = SWIZ_MASK; ind >= 0; ind--) {
+		oid = oswiz(type, ind);
+		(void)zcache_flush_object(LOCAL_CLIENT,
+						zcache_frontswap_poolid, &oid);
+	}
+}
+
+static void zcache_frontswap_init(unsigned ignored)
+{
+	/* a single tmem poolid is used for all frontswap "types" (swapfiles) */
+	if (zcache_frontswap_poolid < 0)
+		zcache_frontswap_poolid =
+				zcache_local_new_pool(TMEM_POOL_PERSIST);
+}
+
+static struct frontswap_ops zcache_frontswap_ops = {
+	.put_page = zcache_frontswap_put_page,
+	.get_page = zcache_frontswap_get_page,
+	.invalidate_page = zcache_frontswap_flush_page,
+	.invalidate_area = zcache_frontswap_flush_area,
+	.init = zcache_frontswap_init
+};
+
+struct frontswap_ops zcache_frontswap_register_ops(void)
+{
+	struct frontswap_ops old_ops =
+		frontswap_register_ops(&zcache_frontswap_ops);
+
+	return old_ops;
+}
+#endif
+
+/*
+ * frontswap selfshrinking
+ */
+
+#ifdef CONFIG_FRONTSWAP
+/* In HZ, controls frequency of worker invocation. */
+static unsigned int selfshrink_interval __read_mostly = 5;
+
+static void selfshrink_process(struct work_struct *work);
+static DECLARE_DELAYED_WORK(selfshrink_worker, selfshrink_process);
+
+/* Enable/disable with sysfs. */
+static bool frontswap_selfshrinking __read_mostly;
+
+/* Enable/disable with kernel boot option. */
+static bool use_frontswap_selfshrink __initdata = true;
+
+/*
+ * The default values for the following parameters were deemed reasonable
+ * by experimentation, may be workload-dependent, and can all be
+ * adjusted via sysfs.
+ */
+
+/* Control rate for frontswap shrinking. Higher hysteresis is slower. */
+static unsigned int frontswap_hysteresis __read_mostly = 20;
+
+/*
+ * Number of selfshrink worker invocations to wait before observing that
+ * frontswap selfshrinking should commence. Note that selfshrinking does
+ * not use a separate worker thread.
+ */
+static unsigned int frontswap_inertia __read_mostly = 3;
+
+/* Countdown to next invocation of frontswap_shrink() */
+static unsigned long frontswap_inertia_counter;
+
+/*
+ * Invoked by the selfshrink worker thread, uses current number of pages
+ * in frontswap (frontswap_curr_pages()), previous status, and control
+ * values (hysteresis and inertia) to determine if frontswap should be
+ * shrunk and what the new frontswap size should be.  Note that
+ * frontswap_shrink is essentially a partial swapoff that immediately
+ * transfers pages from the "swap device" (frontswap) back into kernel
+ * RAM; despite the name, frontswap "shrinking" is very different from
+ * the "shrinker" interface used by the kernel MM subsystem to reclaim
+ * memory.
+ */
+static void frontswap_selfshrink(void)
+{
+	static unsigned long cur_frontswap_pages;
+	static unsigned long last_frontswap_pages;
+	static unsigned long tgt_frontswap_pages;
+
+	last_frontswap_pages = cur_frontswap_pages;
+	cur_frontswap_pages = frontswap_curr_pages();
+	if (!cur_frontswap_pages ||
+			(cur_frontswap_pages > last_frontswap_pages)) {
+		frontswap_inertia_counter = frontswap_inertia;
+		return;
+	}
+	if (frontswap_inertia_counter && --frontswap_inertia_counter)
+		return;
+	if (cur_frontswap_pages <= frontswap_hysteresis)
+		tgt_frontswap_pages = 0;
+	else
+		tgt_frontswap_pages = cur_frontswap_pages -
+			(cur_frontswap_pages / frontswap_hysteresis);
+	frontswap_shrink(tgt_frontswap_pages);
+}
+
+static int __init ramster_nofrontswap_selfshrink_setup(char *s)
+{
+	use_frontswap_selfshrink = false;
+	return 1;
+}
+
+__setup("noselfshrink", ramster_nofrontswap_selfshrink_setup);
+
+static void selfshrink_process(struct work_struct *work)
+{
+	if (frontswap_selfshrinking && frontswap_enabled) {
+		frontswap_selfshrink();
+		schedule_delayed_work(&selfshrink_worker,
+			selfshrink_interval * HZ);
+	}
+}
+
+static int ramster_enabled;
+
+static int __init ramster_selfshrink_init(void)
+{
+	frontswap_selfshrinking = ramster_enabled && use_frontswap_selfshrink;
+	if (frontswap_selfshrinking)
+		pr_info("ramster: Initializing frontswap "
+					"selfshrinking driver.\n");
+	else
+		return -ENODEV;
+
+	schedule_delayed_work(&selfshrink_worker, selfshrink_interval * HZ);
+
+	return 0;
+}
+
+subsys_initcall(ramster_selfshrink_init);
+#endif
+
+/*
+ * zcache initialization
+ * NOTE FOR NOW ramster MUST BE PROVIDED AS A KERNEL BOOT PARAMETER OR
+ * NOTHING HAPPENS!
+ */
+
+static int ramster_enabled;
+
+static int __init enable_ramster(char *s)
+{
+	ramster_enabled = 1;
+	return 1;
+}
+__setup("ramster", enable_ramster);
+
+/* allow independent dynamic disabling of cleancache and frontswap */
+
+static int use_cleancache = 1;
+
+static int __init no_cleancache(char *s)
+{
+	pr_info("INIT no_cleancache called\n");
+	use_cleancache = 0;
+	return 1;
+}
+
+/*
+ * FIXME: need to guarantee this gets checked before zcache_init is called
+ * What is the correct way to achieve this?
+ */
+early_param("nocleancache", no_cleancache);
+
+static int use_frontswap = 1;
+
+static int __init no_frontswap(char *s)
+{
+	pr_info("INIT no_frontswap called\n");
+	use_frontswap = 0;
+	return 1;
+}
+
+__setup("nofrontswap", no_frontswap);
+
+static int __init zcache_init(void)
+{
+	int ret = 0;
+
+#ifdef CONFIG_SYSFS
+	ret = sysfs_create_group(mm_kobj, &zcache_attr_group);
+	ret = sysfs_create_group(mm_kobj, &ramster_attr_group);
+	if (ret) {
+		pr_err("ramster: can't create sysfs\n");
+		goto out;
+	}
+#endif /* CONFIG_SYSFS */
+#if defined(CONFIG_CLEANCACHE) || defined(CONFIG_FRONTSWAP)
+	if (ramster_enabled) {
+		unsigned int cpu;
+
+		(void)r2net_register_handlers();
+		tmem_register_hostops(&zcache_hostops);
+		tmem_register_pamops(&zcache_pamops);
+		ret = register_cpu_notifier(&zcache_cpu_notifier_block);
+		if (ret) {
+			pr_err("ramster: can't register cpu notifier\n");
+			goto out;
+		}
+		for_each_online_cpu(cpu) {
+			void *pcpu = (void *)(long)cpu;
+			zcache_cpu_notifier(&zcache_cpu_notifier_block,
+				CPU_UP_PREPARE, pcpu);
+		}
+	}
+	zcache_objnode_cache = kmem_cache_create("zcache_objnode",
+				sizeof(struct tmem_objnode), 0, 0, NULL);
+	zcache_obj_cache = kmem_cache_create("zcache_obj",
+				sizeof(struct tmem_obj), 0, 0, NULL);
+	ramster_flnode_cache = kmem_cache_create("ramster_flnode",
+				sizeof(struct flushlist_node), 0, 0, NULL);
+#endif
+#ifdef CONFIG_CLEANCACHE
+	pr_info("INIT ramster_enabled=%d use_cleancache=%d\n",
+					ramster_enabled, use_cleancache);
+	if (ramster_enabled && use_cleancache) {
+		struct cleancache_ops old_ops;
+
+		zbud_init();
+		register_shrinker(&zcache_shrinker);
+		old_ops = zcache_cleancache_register_ops();
+		pr_info("ramster: cleancache enabled using kernel "
+			"transcendent memory and compression buddies\n");
+		if (old_ops.init_fs != NULL)
+			pr_warning("ramster: cleancache_ops overridden");
+	}
+#endif
+#ifdef CONFIG_FRONTSWAP
+	pr_info("INIT ramster_enabled=%d use_frontswap=%d\n",
+					ramster_enabled, use_frontswap);
+	if (ramster_enabled && use_frontswap) {
+		struct frontswap_ops old_ops;
+
+		zcache_new_client(LOCAL_CLIENT);
+		old_ops = zcache_frontswap_register_ops();
+		pr_info("ramster: frontswap enabled using kernel "
+			"transcendent memory and xvmalloc\n");
+		if (old_ops.init != NULL)
+			pr_warning("ramster: frontswap_ops overridden");
+	}
+	if (ramster_enabled && (use_frontswap || use_cleancache))
+		ramster_remotify_init();
+#endif
+out:
+	return ret;
+}
+
+module_init(zcache_init)
diff --git a/drivers/staging/ramster/zcache.h b/drivers/staging/ramster/zcache.h
new file mode 100644
index 0000000..250b121
--- /dev/null
+++ b/drivers/staging/ramster/zcache.h
@@ -0,0 +1,22 @@
+/*
+ * zcache.h
+ *
+ * External zcache functions
+ *
+ * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp.
+ */
+
+#ifndef _ZCACHE_H_
+#define _ZCACHE_H_
+
+extern int zcache_put(int, int, struct tmem_oid *, uint32_t,
+			char *, size_t, bool, int);
+extern int zcache_autocreate_pool(int, int, bool);
+extern int zcache_get(int, int, struct tmem_oid *, uint32_t,
+			char *, size_t *, bool, int);
+extern int zcache_flush(int, int, struct tmem_oid *, uint32_t);
+extern int zcache_flush_object(int, int, struct tmem_oid *);
+extern int zcache_localify(int, struct tmem_oid *, uint32_t,
+			char *, size_t, void *);
+
+#endif /* _ZCACHE_H */
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index 04c2391..e4ade55 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -439,8 +439,7 @@
 		}
 		kfree(tmp);
 		tmp = next;
-	}
-	while (next != *buffer);
+	} while (next != *buffer);
 
 	*buffer = NULL;
 }
@@ -1392,11 +1391,13 @@
 	priv->bCurCCKPkt = bCckRate;
 
 	if (priv->UndecoratedSmoothedSS >= 0)
-		priv->UndecoratedSmoothedSS = ((priv->UndecoratedSmoothedSS * 5) + (priv->SignalStrength * 10)) / 6;
+		priv->UndecoratedSmoothedSS = ((priv->UndecoratedSmoothedSS * 5) +
+					       (priv->SignalStrength * 10)) / 6;
 	else
 		priv->UndecoratedSmoothedSS = priv->SignalStrength * 10;
 
-	priv->UndercorateSmoothedRxPower = ((priv->UndercorateSmoothedRxPower * 50) + (priv->RxPower * 11)) / 60;
+	priv->UndercorateSmoothedRxPower = ((priv->UndercorateSmoothedRxPower * 50) +
+					    (priv->RxPower * 11)) / 60;
 
 	if (bCckRate)
 		priv->CurCCKRSSI = priv->RSSI;
@@ -1607,43 +1608,50 @@
 		/* printk("==========================>rx : RXAGC is %d,signalstrength is %d\n",RXAGC,stats.signalstrength); */
 		stats.rssi = priv->wstats.qual.qual = priv->SignalQuality;
 		stats.noise = priv->wstats.qual.noise = 100 - priv->wstats.qual.qual;
-		bHwError = (((*(priv->rxringtail)) & (0x00000fff)) == 4080) | (((*(priv->rxringtail)) & (0x04000000)) != 0)
-			| (((*(priv->rxringtail)) & (0x08000000)) != 0) | (((~(*(priv->rxringtail))) & (0x10000000)) != 0) | (((~(*(priv->rxringtail))) & (0x20000000)) != 0);
+		bHwError = (((*(priv->rxringtail)) & (0x00000fff)) == 4080) |
+			   (((*(priv->rxringtail)) & (0x04000000)) != 0) |
+			   (((*(priv->rxringtail)) & (0x08000000)) != 0) |
+			   (((~(*(priv->rxringtail))) & (0x10000000)) != 0) |
+			   (((~(*(priv->rxringtail))) & (0x20000000)) != 0);
 		bCRC = ((*(priv->rxringtail)) & (0x00002000)) >> 13;
 		bICV = ((*(priv->rxringtail)) & (0x00001000)) >> 12;
 		hdr = (struct ieee80211_hdr_4addr *)priv->rxbuffer->buf;
 		    fc = le16_to_cpu(hdr->frame_ctl);
 		type = WLAN_FC_GET_TYPE(fc);
 
-			if ((IEEE80211_FTYPE_CTL != type) &&
-				(eqMacAddr(priv->ieee80211->current_network.bssid, (fc & IEEE80211_FCTL_TODS) ? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS) ? hdr->addr2 : hdr->addr3))
-				 && (!bHwError) && (!bCRC) && (!bICV)) {
-				/* Perform signal smoothing for dynamic
-				 * mechanism on demand. This is different
-				 * with PerformSignalSmoothing8185 in smoothing
-				 * fomula. No dramatic adjustion is apply
-				 * because dynamic mechanism need some degree
-				 * of correctness. */
-				PerformUndecoratedSignalSmoothing8185(priv, bCckRate);
+		if (IEEE80211_FTYPE_CTL != type &&
+		    !bHwError && !bCRC && !bICV &&
+		    eqMacAddr(priv->ieee80211->current_network.bssid,
+			fc & IEEE80211_FCTL_TODS ? hdr->addr1 :
+			fc & IEEE80211_FCTL_FROMDS ? hdr->addr2 :
+			hdr->addr3)) {
 
-				/* For good-looking singal strength. */
-				SignalStrengthIndex = NetgearSignalStrengthTranslate(
-								priv->LastSignalStrengthInPercent,
-								priv->SignalStrength);
+			/* Perform signal smoothing for dynamic
+			 * mechanism on demand. This is different
+			 * with PerformSignalSmoothing8185 in smoothing
+			 * fomula. No dramatic adjustion is apply
+			 * because dynamic mechanism need some degree
+			 * of correctness. */
+			PerformUndecoratedSignalSmoothing8185(priv, bCckRate);
 
-				priv->LastSignalStrengthInPercent = SignalStrengthIndex;
-				priv->Stats_SignalStrength = TranslateToDbm8185((u8)SignalStrengthIndex);
+			/* For good-looking singal strength. */
+			SignalStrengthIndex = NetgearSignalStrengthTranslate(
+							priv->LastSignalStrengthInPercent,
+							priv->SignalStrength);
+
+			priv->LastSignalStrengthInPercent = SignalStrengthIndex;
+			priv->Stats_SignalStrength = TranslateToDbm8185((u8)SignalStrengthIndex);
 		/*
 		 * We need more correct power of received packets and the  "SignalStrength" of RxStats is beautified,
 		 * so we record the correct power here.
 		 */
-				priv->Stats_SignalQuality = (long)(priv->Stats_SignalQuality * 5 + (long)priv->SignalQuality + 5) / 6;
-				priv->Stats_RecvSignalPower = (long)(priv->Stats_RecvSignalPower * 5 + priv->RecvSignalPower - 1) / 6;
+			priv->Stats_SignalQuality = (long)(priv->Stats_SignalQuality * 5 + (long)priv->SignalQuality + 5) / 6;
+			priv->Stats_RecvSignalPower = (long)(priv->Stats_RecvSignalPower * 5 + priv->RecvSignalPower - 1) / 6;
 
 		/* Figure out which antenna that received the lasted packet. */
-				priv->LastRxPktAntenna = Antenna ? 1 : 0; /* 0: aux, 1: main. */
-				SwAntennaDiversityRxOk8185(dev, priv->SignalStrength);
-			}
+			priv->LastRxPktAntenna = Antenna ? 1 : 0; /* 0: aux, 1: main. */
+			SwAntennaDiversityRxOk8185(dev, priv->SignalStrength);
+		}
 
 		if (first) {
 			if (!priv->rx_skb_complete) {
@@ -1654,7 +1662,7 @@
 			}
 			/* support for prism header has been originally added by Christian */
 			if (priv->prism_hdr && priv->ieee80211->iw_mode == IW_MODE_MONITOR) {
-				
+
 			} else {
 				priv->rx_skb = dev_alloc_skb(len+2);
 				if (!priv->rx_skb)
@@ -1766,7 +1774,7 @@
 	rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
 }
 
-/* 
+/*
  * This function TX data frames when the ieee80211 stack requires this.
  * It checks also if we need to stop the ieee tx queue, eventually do it
  */
@@ -1810,7 +1818,7 @@
 	spin_unlock_irqrestore(&priv->tx_lock, flags);
 }
 
-/* 
+/*
  * This is a rough attempt to TX a frame
  * This is called by the ieee 80211 stack to TX management frames.
  * If the ring is full packet are dropped (for data frame the queue
@@ -1916,7 +1924,7 @@
 	}
 }
 
-/* 
+/*
  * This function do the real dirty work: it enqueues a TX command
  * descriptor in the ring buffer, copyes the frame in a TX buffer
  * and kicks the NIC to ensure it does the DMA transfer.
@@ -2002,7 +2010,8 @@
 			bRTSEnable = 0;
 			bCTSEnable = 0;
 
-			ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), 0, bUseShortPreamble);
+			ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate),
+						      0, bUseShortPreamble);
 			TxDescDuration = ThisFrameTime;
 		} else { /* Unicast packet */
 			u16 AckTime;
@@ -2040,7 +2049,8 @@
 				bRTSEnable = 0;
 				RtsDur = 0;
 
-				ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), 0, bUseShortPreamble);
+				ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate),
+							      0, bUseShortPreamble);
 				TxDescDuration = ThisFrameTime + aSifsTime + AckTime;
 			}
 
@@ -2184,7 +2194,7 @@
 			priv->txhpbufstail = buflist;
 			break;
 		case BEACON_PRIORITY:
-			/* 
+			/*
 			 * The HW seems to be happy with the 1st
 			 * descriptor filled and the 2nd empty...
 			 * So always update descriptor 1 and never
@@ -2304,13 +2314,13 @@
 
 	spin_lock_irqsave(&priv->ps_lock, flags);
 
-	/* 
+	/*
 	 * Writing HW register with 0 equals to disable
 	 * the timer, that is not really what we want
 	 */
 	tl -= MSECS(4+16+7);
 
-	/* 
+	/*
 	 * If the interval in witch we are requested to sleep is too
 	 * short then give up and remain awake
 	 */
@@ -2325,10 +2335,10 @@
 		u32 tmp = (tl > rb) ? (tl-rb) : (rb-tl);
 
 		priv->DozePeriodInPast2Sec += jiffies_to_msecs(tmp);
-
-		queue_delayed_work(priv->ieee80211->wq, &priv->ieee80211->hw_wakeup_wq, tmp); /* as tl may be less than rb */
+		/* as tl may be less than rb */
+		queue_delayed_work(priv->ieee80211->wq, &priv->ieee80211->hw_wakeup_wq, tmp);
 	}
-	/* 
+	/*
 	 * If we suspect the TimerInt is gone beyond tl
 	 * while setting it, then give up
 	 */
@@ -3086,7 +3096,8 @@
 	max_rr_rate = ieeerate2rtlrate(240);
 
 	write_nic_byte(dev, RESP_RATE,
-			max_rr_rate<<MAX_RESP_RATE_SHIFT | min_rr_rate<<MIN_RESP_RATE_SHIFT);
+		       max_rr_rate<<MAX_RESP_RATE_SHIFT |
+		       min_rr_rate<<MIN_RESP_RATE_SHIFT);
 
 	word  = read_nic_word(dev, BRSR);
 	word &= ~BRSR_MBR_8185;
@@ -3168,7 +3179,7 @@
 	netif_start_queue(dev);
 }
 
-/* 
+/*
  * This configures registers for beacon tx and enables it via
  * rtl8180_beacon_tx_enable(). rtl8180_beacon_tx_disable() might
  * be used to stop beacon transmission
@@ -3227,7 +3238,8 @@
 {
 	if (priv->bLeisurePs) {
 		if (priv->ieee80211->ps == IEEE80211_PS_DISABLED)
-			MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST); /* IEEE80211_PS_ENABLE */
+			/* IEEE80211_PS_ENABLE */
+			MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST);
 	}
 }
 
@@ -3299,7 +3311,10 @@
 	u16 SlotIndex = 0;
 	u16 i = 0;
 	if (priv->ieee80211->actscanning == false) {
-		if ((priv->ieee80211->iw_mode != IW_MODE_ADHOC) && (priv->ieee80211->state == IEEE80211_NOLINK) && (priv->ieee80211->beinretry == false) && (priv->eRFPowerState == eRfOn))
+		if ((priv->ieee80211->iw_mode != IW_MODE_ADHOC) &&
+		    (priv->ieee80211->state == IEEE80211_NOLINK) &&
+		    (priv->ieee80211->beinretry == false) &&
+		    (priv->eRFPowerState == eRfOn))
 			IPSEnter(dev);
 	}
 	/* YJ,add,080828,for link state check */
@@ -3732,7 +3747,7 @@
 	DMESG("Wireless extensions version %d", WIRELESS_EXT);
 	rtl8180_proc_module_init();
 
-      if (pci_register_driver(&rtl8180_pci_driver)) {
+	if (pci_register_driver(&rtl8180_pci_driver)) {
 		DMESG("No device found");
 		return -ENODEV;
 	}
@@ -3839,7 +3854,7 @@
 			return;
 		}
 
-	/* 
+	/*
 	 * We check all the descriptors between the head and the nic,
 	 * but not the currently pointed by the nic (the next to be txed)
 	 * and the previous of the pointed (might be in process ??)
@@ -3877,7 +3892,7 @@
 			head += 8;
 	}
 
-	/* 
+	/*
 	 * The head has been moved to the last certainly TXed
 	 * (or at least processed by the nic) packet.
 	 * The driver take forcefully owning of all these packets
diff --git a/drivers/staging/rtl8187se/r8180_dm.c b/drivers/staging/rtl8187se/r8180_dm.c
index 261085d..4d7a595 100644
--- a/drivers/staging/rtl8187se/r8180_dm.c
+++ b/drivers/staging/rtl8187se/r8180_dm.c
@@ -1,14 +1,8 @@
-//#include "r8180.h"
 #include "r8180_dm.h"
 #include "r8180_hw.h"
 #include "r8180_93cx6.h"
-//{by amy 080312
 
-//
-//	Description:
-//		Return TRUE if we shall perform High Power Mecahnism, FALSE otherwise.
-//
-//+by amy 080312
+ /*	Return TRUE if we shall perform High Power Mecahnism, FALSE otherwise. */
 #define RATE_ADAPTIVE_TIMER_PERIOD      300
 
 bool CheckHighPower(struct net_device *dev)
@@ -17,33 +11,26 @@
 	struct ieee80211_device *ieee = priv->ieee80211;
 
 	if(!priv->bRegHighPowerMechanism)
-	{
 		return false;
-	}
 
 	if(ieee->state == IEEE80211_LINKED_SCANNING)
-	{
 		return false;
-	}
 
 	return true;
 }
 
-//
-//	Description:
-//		Update Tx power level if necessary.
-//		See also DoRxHighPower() and SetTxPowerLevel8185() for reference.
-//
-//	Note:
-//		The reason why we udpate Tx power level here instead of DoRxHighPower()
-//		is the number of IO to change Tx power is much more than channel TR switch
-//		and they are related to OFDM and MAC registers.
-//		So, we don't want to update it so frequently in per-Rx packet base.
-//
-void
-DoTxHighPower(
-	struct net_device *dev
-	)
+/*
+ *	Description:
+ *		Update Tx power level if necessary.
+ *		See also DoRxHighPower() and SetTxPowerLevel8185() for reference.
+ *
+ *	Note:
+ *		The reason why we udpate Tx power level here instead of DoRxHighPower()
+ *		is the number of IO to change Tx power is much more than channel TR switch
+ *		and they are related to OFDM and MAC registers.
+ *		So, we don't want to update it so frequently in per-Rx packet base.
+ */
+void DoTxHighPower(struct net_device *dev)
 {
 	struct r8180_priv *priv = ieee80211_priv(dev);
 	u16			HiPwrUpperTh = 0;
@@ -53,8 +40,6 @@
 	u8			u1bTmp;
 	char			OfdmTxPwrIdx, CckTxPwrIdx;
 
-	//printk("----> DoTxHighPower()\n");
-
 	HiPwrUpperTh = priv->RegHiPwrUpperTh;
 	HiPwrLowerTh = priv->RegHiPwrLowerTh;
 
@@ -63,526 +48,411 @@
 	RSSIHiPwrUpperTh = priv->RegRSSIHiPwrUpperTh;
 	RSSIHiPwrLowerTh = priv->RegRSSIHiPwrLowerTh;
 
-	//lzm add 080826
+	/* lzm add 080826 */
 	OfdmTxPwrIdx  = priv->chtxpwr_ofdm[priv->ieee80211->current_network.channel];
 	CckTxPwrIdx  = priv->chtxpwr[priv->ieee80211->current_network.channel];
 
-	//	printk("DoTxHighPower() - UndecoratedSmoothedSS:%d, CurCCKRSSI = %d , bCurCCKPkt= %d \n", priv->UndecoratedSmoothedSS, priv->CurCCKRSSI, priv->bCurCCKPkt );
+	if ((priv->UndecoratedSmoothedSS > HiPwrUpperTh) ||
+		(priv->bCurCCKPkt && (priv->CurCCKRSSI > RSSIHiPwrUpperTh))) {
+		/* Stevenl suggested that degrade 8dbm in high power sate. 2007-12-04 Isaiah */
 
-	if((priv->UndecoratedSmoothedSS > HiPwrUpperTh) ||
-		(priv->bCurCCKPkt && (priv->CurCCKRSSI > RSSIHiPwrUpperTh)))
-	{
-		// Stevenl suggested that degrade 8dbm in high power sate. 2007-12-04 Isaiah
-
-	//	printk("=====>DoTxHighPower() - High Power - UndecoratedSmoothedSS:%d,  HiPwrUpperTh = %d \n", priv->UndecoratedSmoothedSS, HiPwrUpperTh );
 		priv->bToUpdateTxPwr = true;
 		u1bTmp= read_nic_byte(dev, CCK_TXAGC);
 
-		// If it never enter High Power.
-		if( CckTxPwrIdx == u1bTmp)
-		{
-		u1bTmp = (u1bTmp > 16) ? (u1bTmp -16): 0;  // 8dbm
-		write_nic_byte(dev, CCK_TXAGC, u1bTmp);
+		/* If it never enter High Power. */
+		if (CckTxPwrIdx == u1bTmp) {
+			u1bTmp = (u1bTmp > 16) ? (u1bTmp -16): 0;  /* 8dbm */
+			write_nic_byte(dev, CCK_TXAGC, u1bTmp);
 
-		u1bTmp= read_nic_byte(dev, OFDM_TXAGC);
-		u1bTmp = (u1bTmp > 16) ? (u1bTmp -16): 0;  // 8dbm
-		write_nic_byte(dev, OFDM_TXAGC, u1bTmp);
+			u1bTmp= read_nic_byte(dev, OFDM_TXAGC);
+			u1bTmp = (u1bTmp > 16) ? (u1bTmp -16): 0;  /* 8dbm */
+			write_nic_byte(dev, OFDM_TXAGC, u1bTmp);
 		}
 
-	}
-	else if((priv->UndecoratedSmoothedSS < HiPwrLowerTh) &&
-		(!priv->bCurCCKPkt || priv->CurCCKRSSI < RSSIHiPwrLowerTh))
-	{
-	//	 printk("DoTxHighPower() - lower Power - UndecoratedSmoothedSS:%d,  HiPwrUpperTh = %d \n", priv->UndecoratedSmoothedSS, HiPwrLowerTh );
-		if(priv->bToUpdateTxPwr)
-		{
+	} else if ((priv->UndecoratedSmoothedSS < HiPwrLowerTh) &&
+		(!priv->bCurCCKPkt || priv->CurCCKRSSI < RSSIHiPwrLowerTh)) {
+		if (priv->bToUpdateTxPwr) {
 			priv->bToUpdateTxPwr = false;
-			//SD3 required.
+			/* SD3 required. */
 			u1bTmp= read_nic_byte(dev, CCK_TXAGC);
-			if(u1bTmp < CckTxPwrIdx)
-			{
-			//u1bTmp = ((u1bTmp+16) > 35) ? 35: (u1bTmp+16);  // 8dbm
-			//write_nic_byte(dev, CCK_TXAGC, u1bTmp);
-			write_nic_byte(dev, CCK_TXAGC, CckTxPwrIdx);
+			if (u1bTmp < CckTxPwrIdx) {
+				write_nic_byte(dev, CCK_TXAGC, CckTxPwrIdx);
 			}
 
 			u1bTmp= read_nic_byte(dev, OFDM_TXAGC);
-			if(u1bTmp < OfdmTxPwrIdx)
-			{
-			//u1bTmp = ((u1bTmp+16) > 35) ? 35: (u1bTmp+16);  // 8dbm
-			//write_nic_byte(dev, OFDM_TXAGC, u1bTmp);
-			write_nic_byte(dev, OFDM_TXAGC, OfdmTxPwrIdx);
+			if (u1bTmp < OfdmTxPwrIdx) {
+				write_nic_byte(dev, OFDM_TXAGC, OfdmTxPwrIdx);
 			}
 		}
 	}
-
-	//printk("<---- DoTxHighPower()\n");
 }
 
 
-//
-//	Description:
-//		Callback function of UpdateTxPowerWorkItem.
-//		Because of some event happened, e.g. CCX TPC, High Power Mechanism,
-//		We update Tx power of current channel again.
-//
-void rtl8180_tx_pw_wq (struct work_struct *work)
+/*
+ *	Description:
+ *		Callback function of UpdateTxPowerWorkItem.
+ *		Because of some event happened, e.g. CCX TPC, High Power Mechanism,
+ *		We update Tx power of current channel again.
+ */
+void rtl8180_tx_pw_wq(struct work_struct *work)
 {
-//      struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq);
-//      struct ieee80211_device * ieee = (struct ieee80211_device*)
-//                                             container_of(work, struct ieee80211_device, watch_dog_wq);
 	struct delayed_work *dwork = to_delayed_work(work);
-        struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,tx_pw_wq);
-        struct net_device *dev = ieee->dev;
-
-//	printk("----> UpdateTxPowerWorkItemCallback()\n");
+	struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,tx_pw_wq);
+	struct net_device *dev = ieee->dev;
 
 	DoTxHighPower(dev);
-
-//	printk("<---- UpdateTxPowerWorkItemCallback()\n");
 }
 
 
-//
-//	Description:
-//		Return TRUE if we shall perform DIG Mecahnism, FALSE otherwise.
-//
-bool
-CheckDig(
-	struct net_device *dev
-	)
+/*
+ *	Return TRUE if we shall perform DIG Mecahnism, FALSE otherwise.
+ */
+bool CheckDig(struct net_device *dev)
 {
 	struct r8180_priv *priv = ieee80211_priv(dev);
 	struct ieee80211_device *ieee = priv->ieee80211;
 
-	if(!priv->bDigMechanism)
+	if (!priv->bDigMechanism)
 		return false;
 
-	if(ieee->state != IEEE80211_LINKED)
+	if (ieee->state != IEEE80211_LINKED)
 		return false;
 
-	//if(priv->CurrentOperaRate < 36) // Schedule Dig under all OFDM rates. By Bruce, 2007-06-01.
-	if((priv->ieee80211->rate/5) < 36) // Schedule Dig under all OFDM rates. By Bruce, 2007-06-01.
+	if ((priv->ieee80211->rate / 5) < 36) /* Schedule Dig under all OFDM rates. By Bruce, 2007-06-01. */
 		return false;
 	return true;
 }
-//
-//	Description:
-//		Implementation of DIG for Zebra and Zebra2.
-//
-void
-DIG_Zebra(
-	struct net_device *dev
-	)
+/*
+ *	Implementation of DIG for Zebra and Zebra2.
+ */
+void DIG_Zebra(struct net_device *dev)
 {
 	struct r8180_priv *priv = ieee80211_priv(dev);
 	u16			CCKFalseAlarm, OFDMFalseAlarm;
 	u16			OfdmFA1, OfdmFA2;
-	int			InitialGainStep = 7; // The number of initial gain stages.
-	int			LowestGainStage = 4; // The capable lowest stage of performing dig workitem.
-	u32 			AwakePeriodIn2Sec=0;
-
-	//printk("---------> DIG_Zebra()\n");
+	int			InitialGainStep = 7; /* The number of initial gain stages. */
+	int			LowestGainStage = 4; /* The capable lowest stage of performing dig workitem. */
+	u32			AwakePeriodIn2Sec = 0;
 
 	CCKFalseAlarm = (u16)(priv->FalseAlarmRegValue & 0x0000ffff);
 	OFDMFalseAlarm = (u16)((priv->FalseAlarmRegValue >> 16) & 0x0000ffff);
 	OfdmFA1 =  0x15;
 	OfdmFA2 = ((u16)(priv->RegDigOfdmFaUpTh)) << 8;
 
-//	printk("DIG**********CCK False Alarm: %#X \n",CCKFalseAlarm);
-//	printk("DIG**********OFDM False Alarm: %#X \n",OFDMFalseAlarm);
-
-        // The number of initial gain steps is different, by Bruce, 2007-04-13.
-	if (priv->InitialGain == 0 ) //autoDIG
-	{ // Advised from SD3 DZ
-		priv->InitialGain = 4; // In 87B, m74dBm means State 4 (m82dBm)
+	/* The number of initial gain steps is different, by Bruce, 2007-04-13. */
+	if (priv->InitialGain == 0) { /* autoDIG */
+		/* Advised from SD3 DZ */
+		priv->InitialGain = 4; /* In 87B, m74dBm means State 4 (m82dBm) */
 	}
-	{ // Advised from SD3 DZ
-		OfdmFA1 =  0x20;
-	}
+	/* Advised from SD3 DZ */
+	OfdmFA1 = 0x20;
 
-#if 1 //lzm reserved 080826
-	AwakePeriodIn2Sec = (2000-priv ->DozePeriodInPast2Sec);
-	//printk("&&& DozePeriod=%d AwakePeriod=%d\n", priv->DozePeriodInPast2Sec, AwakePeriodIn2Sec);
-	priv ->DozePeriodInPast2Sec=0;
+#if 1 /* lzm reserved 080826 */
+	AwakePeriodIn2Sec = (2000 - priv->DozePeriodInPast2Sec);
+	priv ->DozePeriodInPast2Sec = 0;
 
-	if(AwakePeriodIn2Sec)
-	{
-		//RT_TRACE(COMP_DIG, DBG_TRACE, ("DIG: AwakePeriodIn2Sec(%d) - FATh(0x%X , 0x%X) ->",AwakePeriodIn2Sec, OfdmFA1, OfdmFA2));
-		// adjuest DIG threshold.
-		OfdmFA1 =  (u16)((OfdmFA1*AwakePeriodIn2Sec)  / 2000) ;
-		OfdmFA2 =  (u16)((OfdmFA2*AwakePeriodIn2Sec)  / 2000) ;
-		//RT_TRACE(COMP_DIG, DBG_TRACE, ("( 0x%X , 0x%X)\n", OfdmFA1, OfdmFA2));
-	}
-	else
-	{
-		;//RT_TRACE(COMP_DIG, DBG_WARNING, ("ERROR!!  AwakePeriodIn2Sec should not be ZERO!!\n"));
+	if (AwakePeriodIn2Sec) {
+		OfdmFA1 = (u16)((OfdmFA1 * AwakePeriodIn2Sec) / 2000) ;
+		OfdmFA2 = (u16)((OfdmFA2 * AwakePeriodIn2Sec) / 2000) ;
+	} else {
+		;
 	}
 #endif
 
 	InitialGainStep = 8;
-	LowestGainStage = priv->RegBModeGainStage; // Lowest gain stage.
+	LowestGainStage = priv->RegBModeGainStage; /* Lowest gain stage. */
 
-	if (OFDMFalseAlarm > OfdmFA1)
-	{
-		if (OFDMFalseAlarm > OfdmFA2)
-		{
+	if (OFDMFalseAlarm > OfdmFA1) {
+		if (OFDMFalseAlarm > OfdmFA2) {
 			priv->DIG_NumberFallbackVote++;
-			if (priv->DIG_NumberFallbackVote >1)
-			{
-				//serious OFDM  False Alarm, need fallback
-				if (priv->InitialGain < InitialGainStep)
-				{
-					priv->InitialGainBackUp= priv->InitialGain;
+			if (priv->DIG_NumberFallbackVote > 1) {
+				/* serious OFDM  False Alarm, need fallback */
+				if (priv->InitialGain < InitialGainStep) {
+					priv->InitialGainBackUp = priv->InitialGain;
 
 					priv->InitialGain = (priv->InitialGain + 1);
-//					printk("DIG**********OFDM False Alarm: %#X,  OfdmFA1: %#X, OfdmFA2: %#X\n", OFDMFalseAlarm, OfdmFA1, OfdmFA2);
-//					printk("DIG+++++++ fallback OFDM:%d \n", priv->InitialGain);
 					UpdateInitialGain(dev);
 				}
 				priv->DIG_NumberFallbackVote = 0;
-				priv->DIG_NumberUpgradeVote=0;
+				priv->DIG_NumberUpgradeVote = 0;
 			}
-		}
-		else
-		{
+		} else {
 			if (priv->DIG_NumberFallbackVote)
 				priv->DIG_NumberFallbackVote--;
 		}
-		priv->DIG_NumberUpgradeVote=0;
-	}
-	else
-	{
+		priv->DIG_NumberUpgradeVote = 0;
+	} else {
 		if (priv->DIG_NumberFallbackVote)
 			priv->DIG_NumberFallbackVote--;
 		priv->DIG_NumberUpgradeVote++;
 
-		if (priv->DIG_NumberUpgradeVote>9)
-		{
-			if (priv->InitialGain > LowestGainStage) // In 87B, m78dBm means State 4 (m864dBm)
-			{
-				priv->InitialGainBackUp= priv->InitialGain;
+		if (priv->DIG_NumberUpgradeVote > 9) {
+			if (priv->InitialGain > LowestGainStage) { /* In 87B, m78dBm means State 4 (m864dBm) */
+				priv->InitialGainBackUp = priv->InitialGain;
 
 				priv->InitialGain = (priv->InitialGain - 1);
-//				printk("DIG**********OFDM False Alarm: %#X,  OfdmFA1: %#X, OfdmFA2: %#X\n", OFDMFalseAlarm, OfdmFA1, OfdmFA2);
-//				printk("DIG--------- Upgrade OFDM:%d \n", priv->InitialGain);
 				UpdateInitialGain(dev);
 			}
 			priv->DIG_NumberFallbackVote = 0;
-			priv->DIG_NumberUpgradeVote=0;
+			priv->DIG_NumberUpgradeVote = 0;
 		}
 	}
-
-//	printk("DIG+++++++ OFDM:%d\n", priv->InitialGain);
-	//printk("<--------- DIG_Zebra()\n");
 }
 
-//
-//	Description:
-//		Dispatch DIG implementation according to RF.
-//
-void
-DynamicInitGain(struct net_device *dev)
+/*
+ *	Dispatch DIG implementation according to RF.
+ */
+void DynamicInitGain(struct net_device *dev)
 {
 	DIG_Zebra(dev);
 }
 
-void rtl8180_hw_dig_wq (struct work_struct *work)
+void rtl8180_hw_dig_wq(struct work_struct *work)
 {
 	struct delayed_work *dwork = to_delayed_work(work);
-        struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_dig_wq);
-        struct net_device *dev = ieee->dev;
+	struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_dig_wq);
+	struct net_device *dev = ieee->dev;
 	struct r8180_priv *priv = ieee80211_priv(dev);
 
-	// Read CCK and OFDM False Alarm.
+	/* Read CCK and OFDM False Alarm. */
 	priv->FalseAlarmRegValue = read_nic_dword(dev, CCK_FALSE_ALARM);
 
 
-	// Adjust Initial Gain dynamically.
+	/* Adjust Initial Gain dynamically. */
 	DynamicInitGain(dev);
 
 }
 
-int
-IncludedInSupportedRates(
-        struct r8180_priv       *priv,
-        u8              TxRate  )
+int IncludedInSupportedRates(struct r8180_priv *priv, u8 TxRate)
 {
-    u8 rate_len;
-        u8 rate_ex_len;
-        u8                      RateMask = 0x7F;
-        u8                      idx;
-        unsigned short          Found = 0;
-        u8                      NaiveTxRate = TxRate&RateMask;
+	u8 rate_len;
+	u8 rate_ex_len;
+	u8                      RateMask = 0x7F;
+	u8                      idx;
+	unsigned short          Found = 0;
+	u8                      NaiveTxRate = TxRate&RateMask;
 
-    rate_len = priv->ieee80211->current_network.rates_len;
-        rate_ex_len = priv->ieee80211->current_network.rates_ex_len;
-        for( idx=0; idx< rate_len; idx++ )
-        {
-                if( (priv->ieee80211->current_network.rates[idx] & RateMask) == NaiveTxRate )
-                {
-                        Found = 1;
-                        goto found_rate;
-                }
-        }
-    for( idx=0; idx< rate_ex_len; idx++ )
-        {
-                if( (priv->ieee80211->current_network.rates_ex[idx] & RateMask) == NaiveTxRate )
-                {
-                        Found = 1;
-                        goto found_rate;
-                }
-        }
-        return Found;
-        found_rate:
-        return Found;
+	rate_len = priv->ieee80211->current_network.rates_len;
+	rate_ex_len = priv->ieee80211->current_network.rates_ex_len;
+	for (idx=0; idx < rate_len; idx++) {
+		if ((priv->ieee80211->current_network.rates[idx] & RateMask) == NaiveTxRate) {
+			Found = 1;
+			goto found_rate;
+		}
+	}
+	for (idx = 0; idx < rate_ex_len; idx++) {
+		if ((priv->ieee80211->current_network.rates_ex[idx] & RateMask) == NaiveTxRate) {
+			Found = 1;
+			goto found_rate;
+		}
+	}
+	return Found;
+	found_rate:
+	return Found;
 }
 
-//
-//      Description:
-//              Get the Tx rate one degree up form the input rate in the supported rates.
-//              Return the upgrade rate if it is successed, otherwise return the input rate.
-//      By Bruce, 2007-06-05.
-//
-u8
-GetUpgradeTxRate(
-        struct net_device *dev,
-        u8                              rate
-        )
+/*
+ *	Get the Tx rate one degree up form the input rate in the supported rates.
+ *	Return the upgrade rate if it is successed, otherwise return the input rate.
+ */
+u8 GetUpgradeTxRate(struct net_device *dev, u8 rate)
 {
-        struct r8180_priv *priv = ieee80211_priv(dev);
-        u8                      UpRate;
+	struct r8180_priv *priv = ieee80211_priv(dev);
+	u8                      UpRate;
 
-        // Upgrade 1 degree.
-        switch(rate)
-        {
-        case 108: // Up to 54Mbps.
-                UpRate = 108;
-                break;
+	/* Upgrade 1 degree. */
+	switch (rate) {
+	case 108: /* Up to 54Mbps. */
+		UpRate = 108;
+		break;
 
-        case 96: // Up to 54Mbps.
-                UpRate = 108;
-                break;
+	case 96: /* Up to 54Mbps. */
+		UpRate = 108;
+		break;
 
-        case 72: // Up to 48Mbps.
-                UpRate = 96;
-                break;
+	case 72: /* Up to 48Mbps. */
+		UpRate = 96;
+		break;
 
-        case 48: // Up to 36Mbps.
-                UpRate = 72;
-                break;
+	case 48: /* Up to 36Mbps. */
+		UpRate = 72;
+		break;
 
-        case 36: // Up to 24Mbps.
-                UpRate = 48;
-                break;
+	case 36: /* Up to 24Mbps. */
+		UpRate = 48;
+		break;
 
-        case 22: // Up to 18Mbps.
-                UpRate = 36;
-                break;
+	case 22: /* Up to 18Mbps. */
+		UpRate = 36;
+		break;
 
-        case 11: // Up to 11Mbps.
-                UpRate = 22;
-                break;
+	case 11: /* Up to 11Mbps. */
+		UpRate = 22;
+		break;
 
-        case 4: // Up to 5.5Mbps.
-                UpRate = 11;
-                break;
+	case 4: /* Up to 5.5Mbps. */
+		UpRate = 11;
+		break;
 
-        case 2: // Up to 2Mbps.
-                UpRate = 4;
-                break;
+	case 2: /* Up to 2Mbps. */
+		UpRate = 4;
+		break;
 
-        default:
-                printk("GetUpgradeTxRate(): Input Tx Rate(%d) is undefined!\n", rate);
-                return rate;
-        }
-        // Check if the rate is valid.
-        if(IncludedInSupportedRates(priv, UpRate))
-        {
-//              printk("GetUpgradeTxRate(): GetUpgrade Tx rate(%d) from %d !\n", UpRate, priv->CurrentOperaRate);
-                return UpRate;
-        }
-        else
-        {
-                //printk("GetUpgradeTxRate(): Tx rate (%d) is not in supported rates\n", UpRate);
-                return rate;
-        }
-        return rate;
+	default:
+		printk("GetUpgradeTxRate(): Input Tx Rate(%d) is undefined!\n", rate);
+		return rate;
+	}
+	/* Check if the rate is valid. */
+	if (IncludedInSupportedRates(priv, UpRate)) {
+		return UpRate;
+	} else {
+		return rate;
+	}
+	return rate;
 }
-//
-//      Description:
-//              Get the Tx rate one degree down form the input rate in the supported rates.
-//              Return the degrade rate if it is successed, otherwise return the input rate.
-//      By Bruce, 2007-06-05.
-//
-u8
-GetDegradeTxRate(
-        struct net_device *dev,
-        u8         rate
-        )
+/*
+ *	Get the Tx rate one degree down form the input rate in the supported rates.
+ *	Return the degrade rate if it is successed, otherwise return the input rate.
+ */
+
+u8 GetDegradeTxRate(struct net_device *dev, u8 rate)
 {
-        struct r8180_priv *priv = ieee80211_priv(dev);
-        u8                      DownRate;
+	struct r8180_priv *priv = ieee80211_priv(dev);
+	u8                      DownRate;
 
-        // Upgrade 1 degree.
-        switch(rate)
-        {
-        case 108: // Down to 48Mbps.
-                DownRate = 96;
-                break;
+	/* Upgrade 1 degree. */
+	switch (rate) {
+	case 108: /* Down to 48Mbps. */
+		DownRate = 96;
+		break;
 
-        case 96: // Down to 36Mbps.
-                DownRate = 72;
-                break;
+	case 96: /* Down to 36Mbps. */
+		DownRate = 72;
+		break;
 
-        case 72: // Down to 24Mbps.
-                DownRate = 48;
-                break;
+	case 72: /* Down to 24Mbps. */
+		DownRate = 48;
+		break;
 
-        case 48: // Down to 18Mbps.
-                DownRate = 36;
-                break;
+	case 48: /* Down to 18Mbps. */
+		DownRate = 36;
+		break;
 
-        case 36: // Down to 11Mbps.
-                DownRate = 22;
-                break;
+	case 36: /* Down to 11Mbps. */
+		DownRate = 22;
+		break;
 
-        case 22: // Down to 5.5Mbps.
-                DownRate = 11;
-                break;
+	case 22: /* Down to 5.5Mbps. */
+		DownRate = 11;
+		break;
 
-        case 11: // Down to 2Mbps.
-                DownRate = 4;
-                break;
+	case 11: /* Down to 2Mbps. */
+		DownRate = 4;
+		break;
 
-        case 4: // Down to 1Mbps.
-                DownRate = 2;
-                break;
+	case 4: /* Down to 1Mbps. */
+		DownRate = 2;
+		break;
 
-        case 2: // Down to 1Mbps.
-                DownRate = 2;
-                break;
+	case 2: /* Down to 1Mbps. */
+		DownRate = 2;
+		break;
 
-        default:
-                printk("GetDegradeTxRate(): Input Tx Rate(%d) is undefined!\n", rate);
-                return rate;
-        }
-        // Check if the rate is valid.
-        if(IncludedInSupportedRates(priv, DownRate))
-        {
-//              printk("GetDegradeTxRate(): GetDegrade Tx rate(%d) from %d!\n", DownRate, priv->CurrentOperaRate);
-                return DownRate;
-        }
-        else
-        {
-                //printk("GetDegradeTxRate(): Tx rate (%d) is not in supported rates\n", DownRate);
-                return rate;
-        }
-        return rate;
+	default:
+		printk("GetDegradeTxRate(): Input Tx Rate(%d) is undefined!\n", rate);
+		return rate;
+	}
+	/* Check if the rate is valid. */
+	if (IncludedInSupportedRates(priv, DownRate)) {
+		return DownRate;
+	} else {
+		return rate;
+	}
+	return rate;
 }
-//
-//      Helper function to determine if specified data rate is
-//      CCK rate.
-//      2005.01.25, by rcnjko.
-//
-bool
-MgntIsCckRate(
-        u16     rate
-        )
+/*
+ *      Helper function to determine if specified data rate is
+ *      CCK rate.
+ */
+
+bool MgntIsCckRate(u16 rate)
 {
-        bool bReturn = false;
+	bool bReturn = false;
 
-        if((rate <= 22) && (rate != 12) && (rate != 18))
-        {
-                bReturn = true;
-        }
+	if ((rate <= 22) && (rate != 12) && (rate != 18)) {
+		bReturn = true;
+	}
 
-        return bReturn;
+	return bReturn;
 }
-//
-//	Description:
-//		Tx Power tracking mechanism routine on 87SE.
-// 	Created by Roger, 2007.12.11.
-//
-void
-TxPwrTracking87SE(
-	struct net_device *dev
-)
+/*
+ *	Description:
+ *		Tx Power tracking mechanism routine on 87SE.
+ */
+void TxPwrTracking87SE(struct net_device *dev)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
 	u8	tmpu1Byte, CurrentThermal, Idx;
 	char	CckTxPwrIdx, OfdmTxPwrIdx;
-	//u32	u4bRfReg;
 
 	tmpu1Byte = read_nic_byte(dev, EN_LPF_CAL);
-	CurrentThermal = (tmpu1Byte & 0xf0)>>4; //[ 7:4]: thermal meter indication.
-	CurrentThermal = (CurrentThermal>0x0c)? 0x0c:CurrentThermal;//lzm add 080826
+	CurrentThermal = (tmpu1Byte & 0xf0) >> 4; /*[ 7:4]: thermal meter indication. */
+	CurrentThermal = (CurrentThermal > 0x0c) ? 0x0c:CurrentThermal;/* lzm add 080826 */
 
-	//printk("TxPwrTracking87SE(): CurrentThermal(%d)\n", CurrentThermal);
-
-	if( CurrentThermal != priv->ThermalMeter)
-	{
-//		printk("TxPwrTracking87SE(): Thermal meter changed!!!\n");
-
-		// Update Tx Power level on each channel.
-		for(Idx = 1; Idx<15; Idx++)
-		{
+	if (CurrentThermal != priv->ThermalMeter) {
+		/* Update Tx Power level on each channel. */
+		for (Idx = 1; Idx < 15; Idx++) {
 			CckTxPwrIdx = priv->chtxpwr[Idx];
 			OfdmTxPwrIdx = priv->chtxpwr_ofdm[Idx];
 
-			if( CurrentThermal > priv->ThermalMeter )
-			{ // higher thermal meter.
-				CckTxPwrIdx += (CurrentThermal - priv->ThermalMeter)*2;
-				OfdmTxPwrIdx += (CurrentThermal - priv->ThermalMeter)*2;
+			if (CurrentThermal > priv->ThermalMeter) {
+				/* higher thermal meter. */
+				CckTxPwrIdx += (CurrentThermal - priv->ThermalMeter) * 2;
+				OfdmTxPwrIdx += (CurrentThermal - priv->ThermalMeter) * 2;
 
-				if(CckTxPwrIdx >35)
-					CckTxPwrIdx = 35; // Force TxPower to maximal index.
-				if(OfdmTxPwrIdx >35)
+				if (CckTxPwrIdx > 35)
+					CckTxPwrIdx = 35; /* Force TxPower to maximal index. */
+				if (OfdmTxPwrIdx > 35)
 					OfdmTxPwrIdx = 35;
-			}
-			else
-			{ // lower thermal meter.
-				CckTxPwrIdx -= (priv->ThermalMeter - CurrentThermal)*2;
-				OfdmTxPwrIdx -= (priv->ThermalMeter - CurrentThermal)*2;
+			} else {
+				/* lower thermal meter. */
+				CckTxPwrIdx -= (priv->ThermalMeter - CurrentThermal) * 2;
+				OfdmTxPwrIdx -= (priv->ThermalMeter - CurrentThermal) * 2;
 
-				if(CckTxPwrIdx <0)
+				if (CckTxPwrIdx < 0)
 					CckTxPwrIdx = 0;
-				if(OfdmTxPwrIdx <0)
+				if (OfdmTxPwrIdx < 0)
 					OfdmTxPwrIdx = 0;
 			}
 
-			// Update TxPower level on CCK and OFDM resp.
+			/* Update TxPower level on CCK and OFDM resp. */
 			priv->chtxpwr[Idx] = CckTxPwrIdx;
 			priv->chtxpwr_ofdm[Idx] = OfdmTxPwrIdx;
 		}
 
-		// Update TxPower level immediately.
+		/* Update TxPower level immediately. */
 		rtl8225z2_SetTXPowerLevel(dev, priv->ieee80211->current_network.channel);
 	}
 	priv->ThermalMeter = CurrentThermal;
 }
-void
-StaRateAdaptive87SE(
-	struct net_device *dev
-	)
+void StaRateAdaptive87SE(struct net_device *dev)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
-	unsigned long 			CurrTxokCnt;
-	u16			CurrRetryCnt;
-	u16			CurrRetryRate;
-	//u16			i,idx;
-	unsigned long       	CurrRxokCnt;
-	bool			bTryUp = false;
-	bool			bTryDown = false;
-	u8			TryUpTh = 1;
-	u8			TryDownTh = 2;
-	u32			TxThroughput;
+	unsigned long	CurrTxokCnt;
+	u16		CurrRetryCnt;
+	u16		CurrRetryRate;
+	unsigned long	CurrRxokCnt;
+	bool		bTryUp = false;
+	bool		bTryDown = false;
+	u8		TryUpTh = 1;
+	u8		TryDownTh = 2;
+	u32		TxThroughput;
 	long		CurrSignalStrength;
 	bool		bUpdateInitialGain = false;
-    	u8			u1bOfdm=0, u1bCck = 0;
+	u8		u1bOfdm = 0, u1bCck = 0;
 	char		OfdmTxPwrIdx, CckTxPwrIdx;
 
-	priv->RateAdaptivePeriod= RATE_ADAPTIVE_TIMER_PERIOD;
+	priv->RateAdaptivePeriod = RATE_ADAPTIVE_TIMER_PERIOD;
 
 
 	CurrRetryCnt	= priv->CurrRetryCnt;
@@ -591,707 +461,462 @@
 	CurrSignalStrength = priv->Stats_RecvSignalPower;
 	TxThroughput = (u32)(priv->NumTxOkBytesTotal - priv->LastTxOKBytes);
 	priv->LastTxOKBytes = priv->NumTxOkBytesTotal;
-	priv->CurrentOperaRate = priv->ieee80211->rate/5;
-	//printk("priv->CurrentOperaRate is %d\n",priv->CurrentOperaRate);
-	//2 Compute retry ratio.
-	if (CurrTxokCnt>0)
-	{
-		CurrRetryRate = (u16)(CurrRetryCnt*100/CurrTxokCnt);
+	priv->CurrentOperaRate = priv->ieee80211->rate / 5;
+	/* 2 Compute retry ratio. */
+	if (CurrTxokCnt > 0) {
+		CurrRetryRate = (u16)(CurrRetryCnt * 100 / CurrTxokCnt);
+	} else {
+	/* It may be serious retry. To distinguish serious retry or no packets modified by Bruce */
+		CurrRetryRate = (u16)(CurrRetryCnt * 100 / 1);
 	}
-	else
-	{ // It may be serious retry. To distinguish serious retry or no packets modified by Bruce
-		CurrRetryRate = (u16)(CurrRetryCnt*100/1);
-	}
-
-
-	//
-	// Added by Roger, 2007.01.02.
-	// For debug information.
-	//
-	//printk("\n(1) pHalData->LastRetryRate: %d \n",priv->LastRetryRate);
-	//printk("(2) RetryCnt = %d  \n", CurrRetryCnt);
-	//printk("(3) TxokCnt = %d \n", CurrTxokCnt);
-	//printk("(4) CurrRetryRate = %d \n", CurrRetryRate);
-	//printk("(5) CurrSignalStrength = %d \n",CurrSignalStrength);
-	//printk("(6) TxThroughput is %d\n",TxThroughput);
-	//printk("priv->NumTxOkBytesTotal is %d\n",priv->NumTxOkBytesTotal);
 
 	priv->LastRetryCnt = priv->CurrRetryCnt;
 	priv->LastTxokCnt = priv->NumTxOkTotal;
 	priv->LastRxokCnt = priv->ieee80211->NumRxOkTotal;
 	priv->CurrRetryCnt = 0;
 
-	//2No Tx packets, return to init_rate or not?
-	if (CurrRetryRate==0 && CurrTxokCnt == 0)
-	{
-		//
-		//After 9 (30*300ms) seconds in this condition, we try to raise rate.
-		//
+	/* 2No Tx packets, return to init_rate or not? */
+	if (CurrRetryRate == 0 && CurrTxokCnt == 0) {
+		/*
+		 * After 9 (30*300ms) seconds in this condition, we try to raise rate.
+		 */
 		priv->TryupingCountNoData++;
 
-//		printk("No Tx packets, TryupingCountNoData(%d)\n", priv->TryupingCountNoData);
-		//[TRC Dell Lab] Extend raised period from 4.5sec to 9sec, Isaiah 2008-02-15 18:00
-		if (priv->TryupingCountNoData>30)
-		{
+		/* [TRC Dell Lab] Extend raised period from 4.5sec to 9sec, Isaiah 2008-02-15 18:00 */
+		if (priv->TryupingCountNoData > 30) {
 			priv->TryupingCountNoData = 0;
-		 	priv->CurrentOperaRate = GetUpgradeTxRate(dev, priv->CurrentOperaRate);
-			// Reset Fail Record
+			priv->CurrentOperaRate = GetUpgradeTxRate(dev, priv->CurrentOperaRate);
+			/* Reset Fail Record */
 			priv->LastFailTxRate = 0;
 			priv->LastFailTxRateSS = -200;
 			priv->FailTxRateCount = 0;
 		}
 		goto SetInitialGain;
-	}
-        else
-	{
-		priv->TryupingCountNoData=0; //Reset trying up times.
+	} else {
+		priv->TryupingCountNoData = 0; /*Reset trying up times. */
 	}
 
 
-	//
-	// For Netgear case, I comment out the following signal strength estimation,
-	// which can results in lower rate to transmit when sample is NOT enough (e.g. PING request).
-	// 2007.04.09, by Roger.
-	//
+	/*
+	 * For Netgear case, I comment out the following signal strength estimation,
+	 * which can results in lower rate to transmit when sample is NOT enough (e.g. PING request).
+	 *
+	 * Restructure rate adaptive as the following main stages:
+	 * (1) Add retry threshold in 54M upgrading condition with signal strength.
+	 * (2) Add the mechanism to degrade to CCK rate according to signal strength
+	 *		and retry rate.
+	 * (3) Remove all Initial Gain Updates over OFDM rate. To avoid the complicated
+	 *		situation, Initial Gain Update is upon on DIG mechanism except CCK rate.
+	 * (4) Add the mehanism of trying to upgrade tx rate.
+	 * (5) Record the information of upping tx rate to avoid trying upping tx rate constantly.
+	 *
+	 */
 
-	//
-	// Restructure rate adaptive as the following main stages:
-	// (1) Add retry threshold in 54M upgrading condition with signal strength.
-	// (2) Add the mechanism to degrade to CCK rate according to signal strength
-	//		and retry rate.
-	// (3) Remove all Initial Gain Updates over OFDM rate. To avoid the complicated
-	//		situation, Initial Gain Update is upon on DIG mechanism except CCK rate.
-	// (4) Add the mehanism of trying to upgrade tx rate.
-	// (5) Record the information of upping tx rate to avoid trying upping tx rate constantly.
-	// By Bruce, 2007-06-05.
-	//
-	//
-
-	// 11Mbps or 36Mbps
-	// Check more times in these rate(key rates).
-	//
-	if(priv->CurrentOperaRate == 22 || priv->CurrentOperaRate == 72)
-	{
+	/*
+ 	 *  11Mbps or 36Mbps
+	 * Check more times in these rate(key rates).
+	 */
+	if (priv->CurrentOperaRate == 22 || priv->CurrentOperaRate == 72)
 		TryUpTh += 9;
-	}
-	//
-	// Let these rates down more difficult.
-	//
-	if(MgntIsCckRate(priv->CurrentOperaRate) || priv->CurrentOperaRate == 36)
-	{
-			TryDownTh += 1;
-	}
+	/*
+	 * Let these rates down more difficult.
+	 */
+	if (MgntIsCckRate(priv->CurrentOperaRate) || priv->CurrentOperaRate == 36)
+		TryDownTh += 1;
 
-	//1 Adjust Rate.
-	if (priv->bTryuping == true)
-	{
-		//2 For Test Upgrading mechanism
-		// Note:
-		// 	Sometimes the throughput is upon on the capability bwtween the AP and NIC,
-		// 	thus the low data rate does not improve the performance.
-		// 	We randomly upgrade the data rate and check if the retry rate is improved.
+	/* 1 Adjust Rate. */
+	if (priv->bTryuping == true) {
+		/* 2 For Test Upgrading mechanism
+		 * Note:
+		 *	Sometimes the throughput is upon on the capability bwtween the AP and NIC,
+		 *	thus the low data rate does not improve the performance.
+		 *	We randomly upgrade the data rate and check if the retry rate is improved.
+		 */
 
-		// Upgrading rate did not improve the retry rate, fallback to the original rate.
-		if ( (CurrRetryRate > 25) && TxThroughput < priv->LastTxThroughput)
-		{
-			//Not necessary raising rate, fall back rate.
+		/* Upgrading rate did not improve the retry rate, fallback to the original rate. */
+		if ((CurrRetryRate > 25) && TxThroughput < priv->LastTxThroughput) {
+			/*Not necessary raising rate, fall back rate. */
 			bTryDown = true;
-			//printk("case1-1: Not necessary raising rate, fall back rate....\n");
-			//printk("case1-1: pMgntInfo->CurrentOperaRate =%d, TxThroughput = %d, LastThroughput = %d\n",
-			//		priv->CurrentOperaRate, TxThroughput, priv->LastTxThroughput);
-		}
-		else
-		{
+		} else {
 			priv->bTryuping = false;
 		}
-	}
-	else if (CurrSignalStrength > -47 && (CurrRetryRate < 50))
-	{
-		//2For High Power
-		//
-		// Added by Roger, 2007.04.09.
-		// Return to highest data rate, if signal strength is good enough.
-		// SignalStrength threshold(-50dbm) is for RTL8186.
-		// Revise SignalStrength threshold to -51dbm.
-		//
-		// Also need to check retry rate for safety, by Bruce, 2007-06-05.
-		if(priv->CurrentOperaRate != priv->ieee80211->current_network.HighestOperaRate )
-		{
+	} else if (CurrSignalStrength > -47 && (CurrRetryRate < 50)) {
+		/*
+ 		 * 2For High Power
+		 *
+		 * Return to highest data rate, if signal strength is good enough.
+		 * SignalStrength threshold(-50dbm) is for RTL8186.
+		 * Revise SignalStrength threshold to -51dbm.
+		 */
+		/* Also need to check retry rate for safety, by Bruce, 2007-06-05. */
+		if (priv->CurrentOperaRate != priv->ieee80211->current_network.HighestOperaRate) {
 			bTryUp = true;
-			// Upgrade Tx Rate directly.
+			/* Upgrade Tx Rate directly. */
 			priv->TryupingCount += TryUpTh;
 		}
-//		printk("case2: StaRateAdaptive87SE: Power(%d) is high enough!!. \n", CurrSignalStrength);
 
-	}
-	else if(CurrTxokCnt > 9 && CurrTxokCnt< 100 && CurrRetryRate >= 600)
-	{
-		//2 For Serious Retry
-		//
-		// Traffic is not busy but our Tx retry is serious.
-		//
+	} else if (CurrTxokCnt > 9 && CurrTxokCnt < 100 && CurrRetryRate >= 600) {
+		/*
+		 *2 For Serious Retry
+		 *
+		 * Traffic is not busy but our Tx retry is serious.
+		 */
 		bTryDown = true;
-		// Let Rate Mechanism to degrade tx rate directly.
+		/* Let Rate Mechanism to degrade tx rate directly. */
 		priv->TryDownCountLowData += TryDownTh;
-//		printk("case3: RA: Tx Retry is serious. Degrade Tx Rate to %d directly...\n", priv->CurrentOperaRate);
-	}
-	else if ( priv->CurrentOperaRate == 108 )
-	{
-		//2For 54Mbps
-		// Air Link
-		if ( (CurrRetryRate>26)&&(priv->LastRetryRate>25))
-//		if ( (CurrRetryRate>40)&&(priv->LastRetryRate>39))
-		{
-			//Down to rate 48Mbps.
+	} else if (priv->CurrentOperaRate == 108) {
+		/* 2For 54Mbps */
+		/* Air Link */
+		if ((CurrRetryRate > 26) && (priv->LastRetryRate > 25)) {
 			bTryDown = true;
 		}
-		// Cable Link
-		else if ( (CurrRetryRate>17)&&(priv->LastRetryRate>16) && (CurrSignalStrength > -72))
-//		else if ( (CurrRetryRate>17)&&(priv->LastRetryRate>16) && (CurrSignalStrength > -72))
-		{
-			//Down to rate 48Mbps.
+		/* Cable Link */
+		else if ((CurrRetryRate > 17) && (priv->LastRetryRate > 16) && (CurrSignalStrength > -72)) {
 			bTryDown = true;
 		}
 
-		if(bTryDown && (CurrSignalStrength < -75)) //cable link
-		{
+		if (bTryDown && (CurrSignalStrength < -75)) /* cable link */
 			priv->TryDownCountLowData += TryDownTh;
-		}
-		//printk("case4---54M \n");
-
 	}
-	else if ( priv->CurrentOperaRate == 96 )
-	{
-		//2For 48Mbps
-		//Air Link
-		if ( ((CurrRetryRate>48) && (priv->LastRetryRate>47)))
-//		if ( ((CurrRetryRate>65) && (priv->LastRetryRate>64)))
-
-		{
-			//Down to rate 36Mbps.
+	else if (priv->CurrentOperaRate == 96) {
+		/* 2For 48Mbps */
+		/* Air Link */
+		if (((CurrRetryRate > 48) && (priv->LastRetryRate > 47))) {
 			bTryDown = true;
-		}
-		//Cable Link
-		else if ( ((CurrRetryRate>21) && (priv->LastRetryRate>20)) && (CurrSignalStrength > -74))
-		{
-			//Down to rate 36Mbps.
+		} else if (((CurrRetryRate > 21) && (priv->LastRetryRate > 20)) && (CurrSignalStrength > -74)) { /* Cable Link */
+			/* Down to rate 36Mbps. */
 			bTryDown = true;
-		}
-		else if((CurrRetryRate>  (priv->LastRetryRate + 50 )) && (priv->FailTxRateCount >2 ))
-//		else if((CurrRetryRate>  (priv->LastRetryRate + 70 )) && (priv->FailTxRateCount >2 ))
-		{
+		} else if ((CurrRetryRate > (priv->LastRetryRate + 50)) && (priv->FailTxRateCount > 2)) {
 			bTryDown = true;
 			priv->TryDownCountLowData += TryDownTh;
-		}
-		else if ( (CurrRetryRate<8) && (priv->LastRetryRate<8) ) //TO DO: need to consider (RSSI)
-//		else if ( (CurrRetryRate<28) && (priv->LastRetryRate<8) )
-		{
+		} else if ((CurrRetryRate < 8) && (priv->LastRetryRate < 8)) { /* TO DO: need to consider (RSSI) */
 			bTryUp = true;
 		}
 
-		if(bTryDown && (CurrSignalStrength < -75))
-		{
+		if (bTryDown && (CurrSignalStrength < -75)){
 			priv->TryDownCountLowData += TryDownTh;
 		}
-		//printk("case5---48M \n");
-	}
-	else if ( priv->CurrentOperaRate == 72 )
-	{
-		//2For 36Mbps
-		if ( (CurrRetryRate>43) && (priv->LastRetryRate>41))
-//		if ( (CurrRetryRate>60) && (priv->LastRetryRate>59))
-		{
-			//Down to rate 24Mbps.
+	} else if (priv->CurrentOperaRate == 72) {
+		/* 2For 36Mbps */
+		if ((CurrRetryRate > 43) && (priv->LastRetryRate > 41)) {
+			/* Down to rate 24Mbps. */
 			bTryDown = true;
-		}
-		else if((CurrRetryRate>  (priv->LastRetryRate + 50 )) && (priv->FailTxRateCount >2 ))
-//		else if((CurrRetryRate>  (priv->LastRetryRate + 70 )) && (priv->FailTxRateCount >2 ))
-		{
+		} else if ((CurrRetryRate > (priv->LastRetryRate + 50)) && (priv->FailTxRateCount > 2)) {
 			bTryDown = true;
 			priv->TryDownCountLowData += TryDownTh;
-		}
-		else if ( (CurrRetryRate<15) &&  (priv->LastRetryRate<16)) //TO DO: need to consider (RSSI)
-//		else if ( (CurrRetryRate<35) &&  (priv->LastRetryRate<36))
-		{
+		} else if ((CurrRetryRate < 15) &&  (priv->LastRetryRate < 16)) { /* TO DO: need to consider (RSSI) */
 			bTryUp = true;
 		}
 
-		if(bTryDown && (CurrSignalStrength < -80))
-		{
+		if (bTryDown && (CurrSignalStrength < -80))
 			priv->TryDownCountLowData += TryDownTh;
-		}
-		//printk("case6---36M \n");
-	}
-	else if ( priv->CurrentOperaRate == 48 )
-	{
-		//2For 24Mbps
-		// Air Link
-		if ( ((CurrRetryRate>63) && (priv->LastRetryRate>62)))
-//		if ( ((CurrRetryRate>83) && (priv->LastRetryRate>82)))
-		{
-			//Down to rate 18Mbps.
-			bTryDown = true;
-		}
-		//Cable Link
-		else if ( ((CurrRetryRate>33) && (priv->LastRetryRate>32)) && (CurrSignalStrength > -82) )
-//		 else if ( ((CurrRetryRate>50) && (priv->LastRetryRate>49)) && (CurrSignalStrength > -82) )
-		{
-			//Down to rate 18Mbps.
-			bTryDown = true;
-		}
-		else if((CurrRetryRate>  (priv->LastRetryRate + 50 )) && (priv->FailTxRateCount >2 ))
-//		else if((CurrRetryRate>  (priv->LastRetryRate + 70 )) && (priv->FailTxRateCount >2 ))
 
-		{
+	} else if (priv->CurrentOperaRate == 48) {
+		/* 2For 24Mbps */
+		/* Air Link */
+		if (((CurrRetryRate > 63) && (priv->LastRetryRate > 62))) {
+			bTryDown = true;
+		} else if (((CurrRetryRate > 33) && (priv->LastRetryRate > 32)) && (CurrSignalStrength > -82)) { /* Cable Link */
+			bTryDown = true;
+		} else if ((CurrRetryRate > (priv->LastRetryRate + 50)) && (priv->FailTxRateCount > 2 )) {
 			bTryDown = true;
 			priv->TryDownCountLowData += TryDownTh;
-		}
-  		else if ( (CurrRetryRate<20) && (priv->LastRetryRate<21)) //TO DO: need to consider (RSSI)
-//		else if ( (CurrRetryRate<40) && (priv->LastRetryRate<41))
-		{
+		} else if ((CurrRetryRate < 20) && (priv->LastRetryRate < 21)) { /* TO DO: need to consider (RSSI) */
 			bTryUp = true;
 		}
 
-		if(bTryDown && (CurrSignalStrength < -82))
-		{
+		if (bTryDown && (CurrSignalStrength < -82))
 			priv->TryDownCountLowData += TryDownTh;
-		}
-		//printk("case7---24M \n");
-	}
-	else if ( priv->CurrentOperaRate == 36 )
-	{
-		//2For 18Mbps
-		// original (109, 109)
-		//[TRC Dell Lab] (90, 91), Isaiah 2008-02-18 23:24
-		//			     (85, 86), Isaiah 2008-02-18 24:00
-		if ( ((CurrRetryRate>85) && (priv->LastRetryRate>86)))
-//		if ( ((CurrRetryRate>115) && (priv->LastRetryRate>116)))
-		{
-			//Down to rate 11Mbps.
+
+	} else if (priv->CurrentOperaRate == 36) {
+		if (((CurrRetryRate > 85) && (priv->LastRetryRate > 86))) {
 			bTryDown = true;
-		}
-		//[TRC Dell Lab]  Isaiah 2008-02-18 23:24
-		else if((CurrRetryRate>  (priv->LastRetryRate + 50 )) && (priv->FailTxRateCount >2 ))
-//		else if((CurrRetryRate>  (priv->LastRetryRate + 70 )) && (priv->FailTxRateCount >2 ))
-		{
+		} else if ((CurrRetryRate > (priv->LastRetryRate + 50)) && (priv->FailTxRateCount > 2)) {
 			bTryDown = true;
 			priv->TryDownCountLowData += TryDownTh;
-		}
-		else if ( (CurrRetryRate<22) && (priv->LastRetryRate<23)) //TO DO: need to consider (RSSI)
-//		else if ( (CurrRetryRate<42) && (priv->LastRetryRate<43))
-		{
+		} else if ((CurrRetryRate < 22) && (priv->LastRetryRate < 23)) { /* TO DO: need to consider (RSSI) */
 			bTryUp = true;
 		}
-		//printk("case8---18M \n");
-	}
-	else if ( priv->CurrentOperaRate == 22 )
-	{
-		//2For 11Mbps
-		if (CurrRetryRate>95)
-//		if (CurrRetryRate>155)
-		{
+	} else if (priv->CurrentOperaRate == 22) {
+		/* 2For 11Mbps */
+		if (CurrRetryRate > 95) {
 			bTryDown = true;
 		}
-		else if ( (CurrRetryRate<29) && (priv->LastRetryRate <30) )//TO DO: need to consider (RSSI)
-//		else if ( (CurrRetryRate<49) && (priv->LastRetryRate <50) )
-			{
+		else if ((CurrRetryRate < 29) && (priv->LastRetryRate < 30)) { /*TO DO: need to consider (RSSI) */
 			bTryUp = true;
-			}
-		//printk("case9---11M \n");
 		}
-	else if ( priv->CurrentOperaRate == 11 )
-	{
-		//2For 5.5Mbps
-		if (CurrRetryRate>149)
-//		if (CurrRetryRate>189)
-		{
+	} else if (priv->CurrentOperaRate == 11) {
+		/* 2For 5.5Mbps */
+		if (CurrRetryRate > 149) {
 			bTryDown = true;
-		}
-		else if ( (CurrRetryRate<60) && (priv->LastRetryRate < 65))
-//		else if ( (CurrRetryRate<80) && (priv->LastRetryRate < 85))
-
-			{
+		} else if ((CurrRetryRate < 60) && (priv->LastRetryRate < 65)) {
 			bTryUp = true;
-			}
-		//printk("case10---5.5M \n");
 		}
-	else if ( priv->CurrentOperaRate == 4 )
-	{
-		//2For 2 Mbps
-		if((CurrRetryRate>99) && (priv->LastRetryRate>99))
-//		if((CurrRetryRate>199) && (priv->LastRetryRate>199))
-		{
+	} else if (priv->CurrentOperaRate == 4) {
+		/* 2For 2 Mbps */
+		if ((CurrRetryRate > 99) && (priv->LastRetryRate > 99)) {
 			bTryDown = true;
-		}
-		else if ( (CurrRetryRate < 65) && (priv->LastRetryRate < 70))
-//		else if ( (CurrRetryRate < 85) && (priv->LastRetryRate < 90))
-		{
+		} else if ((CurrRetryRate < 65) && (priv->LastRetryRate < 70)) {
 			bTryUp = true;
 		}
-		//printk("case11---2M \n");
-	}
-	else if ( priv->CurrentOperaRate == 2 )
-	{
-		//2For 1 Mbps
-		if( (CurrRetryRate<70) && (priv->LastRetryRate<75))
-//		if( (CurrRetryRate<90) && (priv->LastRetryRate<95))
-		{
+	} else if (priv->CurrentOperaRate == 2) {
+		/* 2For 1 Mbps */
+		if ((CurrRetryRate < 70) && (priv->LastRetryRate < 75)) {
 			bTryUp = true;
 		}
-		//printk("case12---1M \n");
 	}
 
-	if(bTryUp && bTryDown)
-    	printk("StaRateAdaptive87B(): Tx Rate tried upping and downing simultaneously!\n");
+	if (bTryUp && bTryDown)
+	printk("StaRateAdaptive87B(): Tx Rate tried upping and downing simultaneously!\n");
 
-	//1 Test Upgrading Tx Rate
-	// Sometimes the cause of the low throughput (high retry rate) is the compatibility between the AP and NIC.
-	// To test if the upper rate may cause lower retry rate, this mechanism randomly occurs to test upgrading tx rate.
-	if(!bTryUp && !bTryDown && (priv->TryupingCount == 0) && (priv->TryDownCountLowData == 0)
-		&& priv->CurrentOperaRate != priv->ieee80211->current_network.HighestOperaRate && priv->FailTxRateCount < 2)
-	{
-		if(jiffies% (CurrRetryRate + 101) == 0)
-		{
+	/* 1 Test Upgrading Tx Rate
+	 * Sometimes the cause of the low throughput (high retry rate) is the compatibility between the AP and NIC.
+	 * To test if the upper rate may cause lower retry rate, this mechanism randomly occurs to test upgrading tx rate.
+	 */ 
+	if (!bTryUp && !bTryDown && (priv->TryupingCount == 0) && (priv->TryDownCountLowData == 0)
+		&& priv->CurrentOperaRate != priv->ieee80211->current_network.HighestOperaRate && priv->FailTxRateCount < 2) {
+		if (jiffies % (CurrRetryRate + 101) == 0) {
 			bTryUp = true;
 			priv->bTryuping = true;
-			//printk("StaRateAdaptive87SE(): Randomly try upgrading...\n");
 		}
 	}
 
-	//1 Rate Mechanism
-	if(bTryUp)
-	{
+	/* 1 Rate Mechanism */
+	if (bTryUp) {
 		priv->TryupingCount++;
 		priv->TryDownCountLowData = 0;
 
-		{
-//			printk("UP: pHalData->TryupingCount = %d\n", priv->TryupingCount);
-//			printk("UP: TryUpTh(%d)+ (FailTxRateCount(%d))^2 =%d\n",
-//				TryUpTh, priv->FailTxRateCount, (TryUpTh + priv->FailTxRateCount * priv->FailTxRateCount) );
-//			printk("UP: pHalData->bTryuping=%d\n",  priv->bTryuping);
+		/*
+		 * Check more times if we need to upgrade indeed.
+		 * Because the largest value of pHalData->TryupingCount is 0xFFFF and
+		 * the largest value of pHalData->FailTxRateCount is 0x14,
+		 * this condition will be satisfied at most every 2 min.
+		 */
 
-		}
-
-		//
-		// Check more times if we need to upgrade indeed.
-		// Because the largest value of pHalData->TryupingCount is 0xFFFF and
-		// the largest value of pHalData->FailTxRateCount is 0x14,
-		// this condition will be satisfied at most every 2 min.
-		//
-
-		if((priv->TryupingCount > (TryUpTh + priv->FailTxRateCount * priv->FailTxRateCount)) ||
-			(CurrSignalStrength > priv->LastFailTxRateSS) || priv->bTryuping)
-		{
+		if ((priv->TryupingCount > (TryUpTh + priv->FailTxRateCount * priv->FailTxRateCount)) ||
+			(CurrSignalStrength > priv->LastFailTxRateSS) || priv->bTryuping) {
 			priv->TryupingCount = 0;
-			//
-			// When transferring from CCK to OFDM, DIG is an important issue.
-			//
-			if(priv->CurrentOperaRate == 22)
+			/*
+			 * When transferring from CCK to OFDM, DIG is an important issue.
+			 */
+			if (priv->CurrentOperaRate == 22)
 				bUpdateInitialGain = true;
 
-			// The difference in throughput between 48Mbps and 36Mbps is 8M.
-			// So, we must be carefully in this rate scale. Isaiah 2008-02-15.
-			//
-			if(  ((priv->CurrentOperaRate == 72) || (priv->CurrentOperaRate == 48) || (priv->CurrentOperaRate == 36)) &&
-				(priv->FailTxRateCount > 2) )
-				priv->RateAdaptivePeriod= (RATE_ADAPTIVE_TIMER_PERIOD/2);
+			/* 
+			 * The difference in throughput between 48Mbps and 36Mbps is 8M.
+			 * So, we must be carefully in this rate scale. Isaiah 2008-02-15.
+			 */
+			if (((priv->CurrentOperaRate == 72) || (priv->CurrentOperaRate == 48) || (priv->CurrentOperaRate == 36)) &&
+				(priv->FailTxRateCount > 2))
+				priv->RateAdaptivePeriod = (RATE_ADAPTIVE_TIMER_PERIOD / 2);
 
-			// (1)To avoid upgrade frequently to the fail tx rate, add the FailTxRateCount into the threshold.
-			// (2)If the signal strength is increased, it may be able to upgrade.
+			/* (1)To avoid upgrade frequently to the fail tx rate, add the FailTxRateCount into the threshold. */
+			/* (2)If the signal strength is increased, it may be able to upgrade. */
 
 			priv->CurrentOperaRate = GetUpgradeTxRate(dev, priv->CurrentOperaRate);
-//			printk("StaRateAdaptive87SE(): Upgrade Tx Rate to %d\n", priv->CurrentOperaRate);
 
-			//[TRC Dell Lab] Bypass 12/9/6, Isaiah 2008-02-18 20:00
-			if(priv->CurrentOperaRate ==36)
-			{
-				priv->bUpdateARFR=true;
-				write_nic_word(dev, ARFR, 0x0F8F); //bypass 12/9/6
-//				printk("UP: ARFR=0xF8F\n");
-			}
-			else if(priv->bUpdateARFR)
-			{
-				priv->bUpdateARFR=false;
-				write_nic_word(dev, ARFR, 0x0FFF); //set 1M ~ 54Mbps.
-//				printk("UP: ARFR=0xFFF\n");
+			if (priv->CurrentOperaRate == 36) {
+				priv->bUpdateARFR = true;
+				write_nic_word(dev, ARFR, 0x0F8F); /* bypass 12/9/6 */
+			} else if(priv->bUpdateARFR) {
+				priv->bUpdateARFR = false;
+				write_nic_word(dev, ARFR, 0x0FFF); /* set 1M ~ 54Mbps. */
 			}
 
-			// Update Fail Tx rate and count.
-			if(priv->LastFailTxRate != priv->CurrentOperaRate)
-			{
+			/* Update Fail Tx rate and count. */
+			if (priv->LastFailTxRate != priv->CurrentOperaRate) {
 				priv->LastFailTxRate = priv->CurrentOperaRate;
 				priv->FailTxRateCount = 0;
-				priv->LastFailTxRateSS = -200; // Set lowest power.
+				priv->LastFailTxRateSS = -200; /* Set lowest power. */
 			}
 		}
-	}
-	else
-	{
-		if(priv->TryupingCount > 0)
+	} else {
+		if (priv->TryupingCount > 0)
 			priv->TryupingCount --;
 	}
 
-	if(bTryDown)
-	{
+	if (bTryDown) {
 		priv->TryDownCountLowData++;
 		priv->TryupingCount = 0;
-		{
-//			printk("DN: pHalData->TryDownCountLowData = %d\n",priv->TryDownCountLowData);
-//			printk("DN: TryDownTh =%d\n", TryDownTh);
-//			printk("DN: pHalData->bTryuping=%d\n",  priv->bTryuping);
-		}
 
-		//Check if Tx rate can be degraded or Test trying upgrading should fallback.
-		if(priv->TryDownCountLowData > TryDownTh || priv->bTryuping)
-		{
+		/* Check if Tx rate can be degraded or Test trying upgrading should fallback. */
+		if (priv->TryDownCountLowData > TryDownTh || priv->bTryuping) {
 			priv->TryDownCountLowData = 0;
 			priv->bTryuping = false;
-			// Update fail information.
-			if(priv->LastFailTxRate == priv->CurrentOperaRate)
-			{
-				priv->FailTxRateCount ++;
-				// Record the Tx fail rate signal strength.
-				if(CurrSignalStrength > priv->LastFailTxRateSS)
-				{
+			/* Update fail information. */
+			if (priv->LastFailTxRate == priv->CurrentOperaRate) {
+				priv->FailTxRateCount++;
+				/* Record the Tx fail rate signal strength. */
+				if (CurrSignalStrength > priv->LastFailTxRateSS)
 					priv->LastFailTxRateSS = CurrSignalStrength;
-				}
-			}
-			else
-			{
+			} else {
 				priv->LastFailTxRate = priv->CurrentOperaRate;
 				priv->FailTxRateCount = 1;
 				priv->LastFailTxRateSS = CurrSignalStrength;
 			}
 			priv->CurrentOperaRate = GetDegradeTxRate(dev, priv->CurrentOperaRate);
 
-			// Reduce chariot training time at weak signal strength situation. SD3 ED demand.
-			//[TRC Dell Lab] Revise Signal Threshold from -75 to -80 , Isaiah 2008-02-18 20:00
-			if( (CurrSignalStrength < -80) && (priv->CurrentOperaRate > 72 ))
-			{
+			/* Reduce chariot training time at weak signal strength situation. SD3 ED demand. */
+			if ((CurrSignalStrength < -80) && (priv->CurrentOperaRate > 72 )) {
 				priv->CurrentOperaRate = 72;
-//				printk("DN: weak signal strength (%d), degrade to 36Mbps\n", CurrSignalStrength);
 			}
 
-			//[TRC Dell Lab] Bypass 12/9/6, Isaiah 2008-02-18 20:00
-			if(priv->CurrentOperaRate ==36)
-			{
-				priv->bUpdateARFR=true;
-				write_nic_word(dev, ARFR, 0x0F8F); //bypass 12/9/6
-//				printk("DN: ARFR=0xF8F\n");
-			}
-			else if(priv->bUpdateARFR)
-			{
-				priv->bUpdateARFR=false;
-				write_nic_word(dev, ARFR, 0x0FFF); //set 1M ~ 54Mbps.
-//				printk("DN: ARFR=0xFFF\n");
+			if (priv->CurrentOperaRate == 36) {
+				priv->bUpdateARFR = true;
+				write_nic_word(dev, ARFR, 0x0F8F); /* bypass 12/9/6 */
+			} else if (priv->bUpdateARFR) {
+				priv->bUpdateARFR = false;
+				write_nic_word(dev, ARFR, 0x0FFF); /* set 1M ~ 54Mbps. */
 			}
 
-			//
-			// When it is CCK rate, it may need to update initial gain to receive lower power packets.
-			//
-			if(MgntIsCckRate(priv->CurrentOperaRate))
-			{
+			/*
+			 * When it is CCK rate, it may need to update initial gain to receive lower power packets.
+			 */
+			if (MgntIsCckRate(priv->CurrentOperaRate)) {
 				bUpdateInitialGain = true;
 			}
-//			printk("StaRateAdaptive87SE(): Degrade Tx Rate to %d\n", priv->CurrentOperaRate);
 		}
-	}
-	else
-	{
-		if(priv->TryDownCountLowData > 0)
-			priv->TryDownCountLowData --;
+	} else {
+		if (priv->TryDownCountLowData > 0)
+			priv->TryDownCountLowData--;
 	}
 
-	// Keep the Tx fail rate count to equal to 0x15 at most.
-	// Reduce the fail count at least to 10 sec if tx rate is tending stable.
-	if(priv->FailTxRateCount >= 0x15 ||
-		(!bTryUp && !bTryDown && priv->TryDownCountLowData == 0 && priv->TryupingCount && priv->FailTxRateCount > 0x6))
-	{
-		priv->FailTxRateCount --;
+	/* 
+ 	 * Keep the Tx fail rate count to equal to 0x15 at most. 
+	 * Reduce the fail count at least to 10 sec if tx rate is tending stable.
+	 */
+	if (priv->FailTxRateCount >= 0x15 ||
+		(!bTryUp && !bTryDown && priv->TryDownCountLowData == 0 && priv->TryupingCount && priv->FailTxRateCount > 0x6)) {
+		priv->FailTxRateCount--;
 	}
 
 
 	OfdmTxPwrIdx  = priv->chtxpwr_ofdm[priv->ieee80211->current_network.channel];
 	CckTxPwrIdx  = priv->chtxpwr[priv->ieee80211->current_network.channel];
 
-	//[TRC Dell Lab] Mac0x9e increase 2 level in 36M~18M situation, Isaiah 2008-02-18 24:00
-	if((priv->CurrentOperaRate < 96) &&(priv->CurrentOperaRate > 22))
-	{
+	/* Mac0x9e increase 2 level in 36M~18M situation */
+	if ((priv->CurrentOperaRate < 96) && (priv->CurrentOperaRate > 22)) {
 		u1bCck = read_nic_byte(dev, CCK_TXAGC);
 		u1bOfdm = read_nic_byte(dev, OFDM_TXAGC);
 
-		// case 1: Never enter High power
-		if(u1bCck == CckTxPwrIdx )
-		{
-			if(u1bOfdm != (OfdmTxPwrIdx+2) )
-			{
-			priv->bEnhanceTxPwr= true;
-			u1bOfdm = ((u1bOfdm+2) > 35) ? 35: (u1bOfdm+2);
+		/* case 1: Never enter High power */
+		if (u1bCck == CckTxPwrIdx) {
+			if (u1bOfdm != (OfdmTxPwrIdx + 2)) {
+			priv->bEnhanceTxPwr = true;
+			u1bOfdm = ((u1bOfdm + 2) > 35) ? 35: (u1bOfdm + 2);
 			write_nic_byte(dev, OFDM_TXAGC, u1bOfdm);
-//			printk("Enhance OFDM_TXAGC : +++++ u1bOfdm= 0x%x\n", u1bOfdm);
 			}
-		}
-		// case 2: enter high power
-		else if(u1bCck < CckTxPwrIdx)
-		{
-			if(!priv->bEnhanceTxPwr)
-			{
-				priv->bEnhanceTxPwr= true;
-				u1bOfdm = ((u1bOfdm+2) > 35) ? 35: (u1bOfdm+2);
+		} else if (u1bCck < CckTxPwrIdx) {
+		/* case 2: enter high power */
+			if (!priv->bEnhanceTxPwr) {
+				priv->bEnhanceTxPwr = true;
+				u1bOfdm = ((u1bOfdm + 2) > 35) ? 35: (u1bOfdm + 2);
 				write_nic_byte(dev, OFDM_TXAGC, u1bOfdm);
-				//RT_TRACE(COMP_RATE, DBG_TRACE, ("Enhance OFDM_TXAGC(2) : +++++ u1bOfdm= 0x%x\n", u1bOfdm));
 			}
 		}
-	}
-	else if(priv->bEnhanceTxPwr)  //54/48/11/5.5/2/1
-	{
+	} else if (priv->bEnhanceTxPwr) {  /* 54/48/11/5.5/2/1 */
 		u1bCck = read_nic_byte(dev, CCK_TXAGC);
 		u1bOfdm = read_nic_byte(dev, OFDM_TXAGC);
 
-		// case 1: Never enter High power
-		if(u1bCck == CckTxPwrIdx )
-		{
-		priv->bEnhanceTxPwr= false;
-		write_nic_byte(dev, OFDM_TXAGC, OfdmTxPwrIdx);
-		//printk("Recover OFDM_TXAGC : ===== u1bOfdm= 0x%x\n", OfdmTxPwrIdx);
+		/* case 1: Never enter High power */
+		if (u1bCck == CckTxPwrIdx) {
+			priv->bEnhanceTxPwr = false;
+			write_nic_byte(dev, OFDM_TXAGC, OfdmTxPwrIdx);
 		}
-		// case 2: enter high power
-		else if(u1bCck < CckTxPwrIdx)
-		{
-			priv->bEnhanceTxPwr= false;
-			u1bOfdm = ((u1bOfdm-2) > 0) ? (u1bOfdm-2): 0;
+		/* case 2: enter high power */
+		else if (u1bCck < CckTxPwrIdx) {
+			priv->bEnhanceTxPwr = false;
+			u1bOfdm = ((u1bOfdm - 2) > 0) ? (u1bOfdm - 2): 0;
 			write_nic_byte(dev, OFDM_TXAGC, u1bOfdm);
-			//RT_TRACE(COMP_RATE, DBG_TRACE, ("Recover OFDM_TXAGC(2): ===== u1bOfdm= 0x%x\n", u1bOfdm));
-
 		}
 	}
 
-	//
-	// We need update initial gain when we set tx rate "from OFDM to CCK" or
-	// "from CCK to OFDM".
-	//
+	/*
+	 * We need update initial gain when we set tx rate "from OFDM to CCK" or
+	 * "from CCK to OFDM".
+	 */
 SetInitialGain:
-	if(bUpdateInitialGain)
-	{
-		if(MgntIsCckRate(priv->CurrentOperaRate)) // CCK
-		{
-			if(priv->InitialGain > priv->RegBModeGainStage)
-			{
-				priv->InitialGainBackUp= priv->InitialGain;
+	if (bUpdateInitialGain) {
+		if (MgntIsCckRate(priv->CurrentOperaRate)) { /* CCK */
+			if (priv->InitialGain > priv->RegBModeGainStage) {
+				priv->InitialGainBackUp = priv->InitialGain;
 
-				if(CurrSignalStrength < -85) // Low power, OFDM [0x17] = 26.
-				{
-					//SD3 SYs suggest that CurrSignalStrength < -65, ofdm 0x17=26.
+				if (CurrSignalStrength < -85) /* Low power, OFDM [0x17] = 26. */
+					/* SD3 SYs suggest that CurrSignalStrength < -65, ofdm 0x17=26. */
 					priv->InitialGain = priv->RegBModeGainStage;
-				}
-				else if(priv->InitialGain > priv->RegBModeGainStage + 1)
-				{
+
+				else if (priv->InitialGain > priv->RegBModeGainStage + 1)
 					priv->InitialGain -= 2;
-				}
+
 				else
-				{
-					priv->InitialGain --;
-				}
+					priv->InitialGain--;
+
 				printk("StaRateAdaptive87SE(): update init_gain to index %d for date rate %d\n",priv->InitialGain, priv->CurrentOperaRate);
 				UpdateInitialGain(dev);
 			}
-		}
-		else // OFDM
-		{
-			if(priv->InitialGain < 4)
-			{
-				priv->InitialGainBackUp= priv->InitialGain;
+		} else { /* OFDM */
+			if (priv->InitialGain < 4) {
+				priv->InitialGainBackUp = priv->InitialGain;
 
-				priv->InitialGain ++;
+				priv->InitialGain++;
 				printk("StaRateAdaptive87SE(): update init_gain to index %d for date rate %d\n",priv->InitialGain, priv->CurrentOperaRate);
 				UpdateInitialGain(dev);
 			}
 		}
 	}
 
-	//Record the related info
+	/* Record the related info */
 	priv->LastRetryRate = CurrRetryRate;
 	priv->LastTxThroughput = TxThroughput;
 	priv->ieee80211->rate = priv->CurrentOperaRate * 5;
 }
 
-void rtl8180_rate_adapter(struct work_struct * work)
+void rtl8180_rate_adapter(struct work_struct *work)
 {
 	struct delayed_work *dwork = to_delayed_work(work);
-        struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,rate_adapter_wq);
-        struct net_device *dev = ieee->dev;
-        //struct r8180_priv *priv = ieee80211_priv(dev);
-//    DMESG("---->rtl8180_rate_adapter");
-        StaRateAdaptive87SE(dev);
-//   DMESG("<----rtl8180_rate_adapter");
+	struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, rate_adapter_wq);
+	struct net_device *dev = ieee->dev;
+	StaRateAdaptive87SE(dev);
 }
 void timer_rate_adaptive(unsigned long data)
 {
-	struct r8180_priv* priv = ieee80211_priv((struct net_device *)data);
-	//DMESG("---->timer_rate_adaptive()\n");
-	if(!priv->up)
-	{
-//		DMESG("<----timer_rate_adaptive():driver is not up!\n");
+	struct r8180_priv *priv = ieee80211_priv((struct net_device *)data);
+	if (!priv->up) {
 		return;
 	}
-	if((priv->ieee80211->iw_mode != IW_MODE_MASTER)
+	if ((priv->ieee80211->iw_mode != IW_MODE_MASTER)
 			&& (priv->ieee80211->state == IEEE80211_LINKED) &&
-			(priv->ForcedDataRate == 0) )
-	{
-//	DMESG("timer_rate_adaptive():schedule rate_adapter_wq\n");
+			(priv->ForcedDataRate == 0)) {
 		queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->rate_adapter_wq);
-//		StaRateAdaptive87SE((struct net_device *)data);
 	}
 	priv->rateadapter_timer.expires = jiffies + MSECS(priv->RateAdaptivePeriod);
 	add_timer(&priv->rateadapter_timer);
-	//DMESG("<----timer_rate_adaptive()\n");
 }
-//by amy 080312}
-void
-SwAntennaDiversityRxOk8185(
-	struct net_device *dev,
-	u8 SignalStrength
-	)
+
+void SwAntennaDiversityRxOk8185(struct net_device *dev, u8 SignalStrength)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
 
-//	printk("+SwAntennaDiversityRxOk8185: RxSs: %d\n", SignalStrength);
-
 	priv->AdRxOkCnt++;
 
-	if( priv->AdRxSignalStrength != -1)
-	{
-		priv->AdRxSignalStrength = ((priv->AdRxSignalStrength*7) + (SignalStrength*3)) / 10;
-	}
-	else
-	{ // Initialization case.
+	if (priv->AdRxSignalStrength != -1) {
+		priv->AdRxSignalStrength = ((priv->AdRxSignalStrength * 7) + (SignalStrength * 3)) / 10;
+	} else { /* Initialization case. */
 		priv->AdRxSignalStrength = SignalStrength;
 	}
-//{+by amy 080312
-	if( priv->LastRxPktAntenna ) //Main antenna.
+	
+	if (priv->LastRxPktAntenna) /* Main antenna. */
 		priv->AdMainAntennaRxOkCnt++;
-	else	 // Aux antenna.
+	else	 /* Aux antenna. */
 		priv->AdAuxAntennaRxOkCnt++;
-//+by amy 080312
-//	printk("-SwAntennaDiversityRxOk8185: AdRxOkCnt: %d AdRxSignalStrength: %d\n", priv->AdRxOkCnt, priv->AdRxSignalStrength);
 }
-//
-//	Description:
-//		Change Antenna Switch.
-//
-bool
-SetAntenna8185(
-	struct net_device *dev,
-	u8		u1bAntennaIndex
-	)
+ /*	Change Antenna Switch. */
+bool SetAntenna8185(struct net_device *dev, u8 u1bAntennaIndex)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
 	bool bAntennaSwitched = false;
 
-//	printk("+SetAntenna8185(): Antenna is switching to: %d \n", u1bAntennaIndex);
-
-	switch(u1bAntennaIndex)
-	{
+	switch (u1bAntennaIndex) {
 	case 0:
 		/* Mac register, main antenna */
 		write_nic_byte(dev, ANTSEL, 0x03);
@@ -1319,64 +944,35 @@
 	}
 
 	if(bAntennaSwitched)
-	{
 		priv->CurrAntennaIndex = u1bAntennaIndex;
-	}
-
-//	printk("-SetAntenna8185(): return (%#X)\n", bAntennaSwitched);
 
 	return bAntennaSwitched;
 }
-//
-//	Description:
-//		Toggle Antenna switch.
-//
-bool
-SwitchAntenna(
-	struct net_device *dev
-	)
+ /*	Toggle Antenna switch. */
+bool SwitchAntenna(struct net_device *dev)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
 
 	bool		bResult;
 
-	if(priv->CurrAntennaIndex == 0)
-	{
-			bResult = SetAntenna8185(dev, 1);
-//by amy 080312
-//		printk("SwitchAntenna(): switching to antenna 1 ......\n");
-//		bResult = SetAntenna8185(dev, 1);//-by amy 080312
-	}
-	else
-	{
-			bResult = SetAntenna8185(dev, 0);
-//by amy 080312
-//		printk("SwitchAntenna(): switching to antenna 0 ......\n");
-//		bResult = SetAntenna8185(dev, 0);//-by amy 080312
+	if (priv->CurrAntennaIndex == 0) {
+		bResult = SetAntenna8185(dev, 1);
+	} else {
+		bResult = SetAntenna8185(dev, 0);
 	}
 
 	return bResult;
 }
-//
-//	Description:
-//		Engine of SW Antenna Diversity mechanism.
-//		Since 8187 has no Tx part information,
-//		this implementation is only dependend on Rx part information.
-//
-//	2006.04.17, by rcnjko.
-//
-void
-SwAntennaDiversity(
-	struct net_device *dev
-	)
+/*
+ * Engine of SW Antenna Diversity mechanism.
+ * Since 8187 has no Tx part information,
+ * this implementation is only dependend on Rx part information.
+ */
+void SwAntennaDiversity(struct net_device *dev)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
-	bool   bSwCheckSS=false;
-//	printk("+SwAntennaDiversity(): CurrAntennaIndex: %d\n", priv->CurrAntennaIndex);
-//	printk("AdTickCount is %d\n",priv->AdTickCount);
-//by amy 080312
-	if(bSwCheckSS)
-	{
+	bool   bSwCheckSS = false;
+	if (bSwCheckSS) {
 		priv->AdTickCount++;
 
 		printk("(1) AdTickCount: %d, AdCheckPeriod: %d\n",
@@ -1384,246 +980,162 @@
 		printk("(2) AdRxSignalStrength: %ld, AdRxSsThreshold: %ld\n",
 			priv->AdRxSignalStrength, priv->AdRxSsThreshold);
 	}
-//	priv->AdTickCount++;//-by amy 080312
 
-	// Case 1. No Link.
-	if(priv->ieee80211->state != IEEE80211_LINKED)
-	{
-	//	printk("SwAntennaDiversity(): Case 1. No Link.\n");
-
+	/* Case 1. No Link. */
+	if (priv->ieee80211->state != IEEE80211_LINKED) {
 		priv->bAdSwitchedChecking = false;
-		// I switch antenna here to prevent any one of antenna is broken before link established, 2006.04.18, by rcnjko..
+		/* I switch antenna here to prevent any one of antenna is broken before link established, 2006.04.18, by rcnjko.. */
 		SwitchAntenna(dev);
-	}
-	// Case 2. Linked but no packet received.
-	else if(priv->AdRxOkCnt == 0)
-	{
-	//	printk("SwAntennaDiversity(): Case 2. Linked but no packet received.\n");
 
+	  /* Case 2. Linked but no packet receive.d */
+	} else if (priv->AdRxOkCnt == 0) {
 		priv->bAdSwitchedChecking = false;
 		SwitchAntenna(dev);
-	}
-	// Case 3. Evaluate last antenna switch action and undo it if necessary.
-	else if(priv->bAdSwitchedChecking == true)
-	{
-	//	printk("SwAntennaDiversity(): Case 3. Evaluate last antenna switch action.\n");
 
+	  /* Case 3. Evaluate last antenna switch action and undo it if necessary. */
+	} else if (priv->bAdSwitchedChecking == true) {
 		priv->bAdSwitchedChecking = false;
 
-		// Adjust Rx signal strength threshold.
+		/* Adjust Rx signal strength threshold. */
 		priv->AdRxSsThreshold = (priv->AdRxSignalStrength + priv->AdRxSsBeforeSwitched) / 2;
 
 		priv->AdRxSsThreshold = (priv->AdRxSsThreshold > priv->AdMaxRxSsThreshold) ?
 					priv->AdMaxRxSsThreshold: priv->AdRxSsThreshold;
-		if(priv->AdRxSignalStrength < priv->AdRxSsBeforeSwitched)
-		{ // Rx signal strength is not improved after we swtiched antenna. => Swich back.
-//			printk("SwAntennaDiversity(): Rx Signal Strength is not improved, CurrRxSs: %d, LastRxSs: %d\n",
-//				priv->AdRxSignalStrength, priv->AdRxSsBeforeSwitched);
-//by amy 080312
-			// Increase Antenna Diversity checking period due to bad decision.
+		if(priv->AdRxSignalStrength < priv->AdRxSsBeforeSwitched) {
+		/* Rx signal strength is not improved after we swtiched antenna. => Swich back. */
+			/* Increase Antenna Diversity checking period due to bad decision. */
 			priv->AdCheckPeriod *= 2;
-//by amy 080312
-			// Increase Antenna Diversity checking period.
-			if(priv->AdCheckPeriod > priv->AdMaxCheckPeriod)
+			/* Increase Antenna Diversity checking period. */
+			if (priv->AdCheckPeriod > priv->AdMaxCheckPeriod)
 				priv->AdCheckPeriod = priv->AdMaxCheckPeriod;
 
-			// Wrong deceision => switch back.
+			/* Wrong deceision => switch back. */
 			SwitchAntenna(dev);
-		}
-		else
-		{ // Rx Signal Strength is improved.
-//			printk("SwAntennaDiversity(): Rx Signal Strength is improved, CurrRxSs: %d, LastRxSs: %d\n",
-//				priv->AdRxSignalStrength, priv->AdRxSsBeforeSwitched);
+		} else {
+		/* Rx Signal Strength is improved. */
 
-			// Reset Antenna Diversity checking period to its min value.
+			/* Reset Antenna Diversity checking period to its min value. */
 			priv->AdCheckPeriod = priv->AdMinCheckPeriod;
 		}
 
-//		printk("SwAntennaDiversity(): AdRxSsThreshold: %d, AdCheckPeriod: %d\n",
-//			priv->AdRxSsThreshold, priv->AdCheckPeriod);
 	}
-	// Case 4. Evaluate if we shall switch antenna now.
-	// Cause Table Speed is very fast in TRC Dell Lab, we check it every time.
-	else// if(priv->AdTickCount >= priv->AdCheckPeriod)//-by amy 080312
-	{
-//		printk("SwAntennaDiversity(): Case 4. Evaluate if we shall switch antenna now.\n");
-
+	/* Case 4. Evaluate if we shall switch antenna now. */
+	/* Cause Table Speed is very fast in TRC Dell Lab, we check it every time. */
+	else {
 		priv->AdTickCount = 0;
 
-		//
-		// <Roger_Notes> We evaluate RxOk counts for each antenna first and than
-		// evaluate signal strength.
-		// The following operation can overcome the disability of CCA on both two antennas
-		// When signal strength was extremely low or high.
-		// 2008.01.30.
-		//
+		/*
+		 * <Roger_Notes> We evaluate RxOk counts for each antenna first and than
+		 * evaluate signal strength.
+		 * The following operation can overcome the disability of CCA on both two antennas
+		 * When signal strength was extremely low or high.
+		 * 2008.01.30.
+		 */
 
-		//
-		// Evaluate RxOk count from each antenna if we shall switch default antenna now.
-		// Added by Roger, 2008.02.21.
-//{by amy 080312
-		if((priv->AdMainAntennaRxOkCnt < priv->AdAuxAntennaRxOkCnt)
-			&& (priv->CurrAntennaIndex == 0))
-		{ // We set Main antenna as default but RxOk count was less than Aux ones.
+		/*
+		 * Evaluate RxOk count from each antenna if we shall switch default antenna now.
+		 */
+		if ((priv->AdMainAntennaRxOkCnt < priv->AdAuxAntennaRxOkCnt)
+			&& (priv->CurrAntennaIndex == 0)) {
+		/* We set Main antenna as default but RxOk count was less than Aux ones. */
 
-	//		printk("SwAntennaDiversity(): Main antenna RxOK is poor, AdMainAntennaRxOkCnt: %d, AdAuxAntennaRxOkCnt: %d\n",
-	//			priv->AdMainAntennaRxOkCnt, priv->AdAuxAntennaRxOkCnt);
-
-			// Switch to Aux antenna.
+			/* Switch to Aux antenna. */
 			SwitchAntenna(dev);
 			priv->bHWAdSwitched = true;
-		}
-		else if((priv->AdAuxAntennaRxOkCnt < priv->AdMainAntennaRxOkCnt)
-			&& (priv->CurrAntennaIndex == 1))
-		{ // We set Aux antenna as default but RxOk count was less than Main ones.
+		} else if ((priv->AdAuxAntennaRxOkCnt < priv->AdMainAntennaRxOkCnt)
+			&& (priv->CurrAntennaIndex == 1)) {
+		/* We set Aux antenna as default but RxOk count was less than Main ones. */
 
-	//		printk("SwAntennaDiversity(): Aux antenna RxOK is poor, AdMainAntennaRxOkCnt: %d, AdAuxAntennaRxOkCnt: %d\n",
-	//			priv->AdMainAntennaRxOkCnt, priv->AdAuxAntennaRxOkCnt);
-
-			// Switch to Main antenna.
+			/* Switch to Main antenna. */
 			SwitchAntenna(dev);
 			priv->bHWAdSwitched = true;
-		}
-		else
-		{// Default antenna is better.
+		} else {
+		/* Default antenna is better. */
 
-	//		printk("SwAntennaDiversity(): Default antenna is better., AdMainAntennaRxOkCnt: %d, AdAuxAntennaRxOkCnt: %d\n",
-	//			priv->AdMainAntennaRxOkCnt, priv->AdAuxAntennaRxOkCnt);
-
-			// Still need to check current signal strength.
+			/* Still need to check current signal strength. */
 			priv->bHWAdSwitched = false;
 		}
-		//
-		// <Roger_Notes> We evaluate Rx signal strength ONLY when default antenna
-		// didn't changed by HW evaluation.
-		// 2008.02.27.
-		//
-		// [TRC Dell Lab] SignalStrength is inaccuracy. Isaiah 2008-03-05
-		// For example, Throughput of aux is better than main antenna(about 10M v.s 2M),
-		// but AdRxSignalStrength is less than main.
-		// Our guess is that main antenna have lower throughput and get many change
-		// to receive more CCK packets(ex.Beacon) which have stronger SignalStrength.
-		//
-		if( (!priv->bHWAdSwitched) && (bSwCheckSS))
-		{
-//by amy 080312}
-		// Evaluate Rx signal strength if we shall switch antenna now.
-		if(priv->AdRxSignalStrength < priv->AdRxSsThreshold)
-		{ // Rx signal strength is weak => Switch Antenna.
-//			printk("SwAntennaDiversity(): Rx Signal Strength is weak, CurrRxSs: %d, RxSsThreshold: %d\n",
-//				priv->AdRxSignalStrength, priv->AdRxSsThreshold);
+		/*
+		 * <Roger_Notes> We evaluate Rx signal strength ONLY when default antenna
+		 * didn't changed by HW evaluation.
+		 * 2008.02.27.
+		 *
+		 * [TRC Dell Lab] SignalStrength is inaccuracy. Isaiah 2008-03-05
+		 * For example, Throughput of aux is better than main antenna(about 10M v.s 2M),
+		 * but AdRxSignalStrength is less than main.
+		 * Our guess is that main antenna have lower throughput and get many change
+		 * to receive more CCK packets(ex.Beacon) which have stronger SignalStrength.
+		 */
+		if ((!priv->bHWAdSwitched) && (bSwCheckSS)) {
+			/* Evaluate Rx signal strength if we shall switch antenna now. */
+			if (priv->AdRxSignalStrength < priv->AdRxSsThreshold) {
+			/* Rx signal strength is weak => Switch Antenna. */
+				priv->AdRxSsBeforeSwitched = priv->AdRxSignalStrength;
+				priv->bAdSwitchedChecking = true;
 
-			priv->AdRxSsBeforeSwitched = priv->AdRxSignalStrength;
-			priv->bAdSwitchedChecking = true;
+				SwitchAntenna(dev);
+			} else {
+			/* Rx signal strength is OK. */
+				priv->bAdSwitchedChecking = false;
+				/* Increase Rx signal strength threshold if necessary. */
+				if ((priv->AdRxSignalStrength > (priv->AdRxSsThreshold + 10)) && /* Signal is much stronger than current threshold */
+					priv->AdRxSsThreshold <= priv->AdMaxRxSsThreshold) { /* Current threhold is not yet reach upper limit. */
 
-			SwitchAntenna(dev);
-		}
-		else
-		{ // Rx signal strength is OK.
-//			printk("SwAntennaDiversity(): Rx Signal Strength is OK, CurrRxSs: %d, RxSsThreshold: %d\n",
-//				priv->AdRxSignalStrength, priv->AdRxSsThreshold);
+					priv->AdRxSsThreshold = (priv->AdRxSsThreshold + priv->AdRxSignalStrength) / 2;
+					priv->AdRxSsThreshold = (priv->AdRxSsThreshold > priv->AdMaxRxSsThreshold) ?
+								priv->AdMaxRxSsThreshold: priv->AdRxSsThreshold;/* +by amy 080312 */
+				}
 
-			priv->bAdSwitchedChecking = false;
-			// Increase Rx signal strength threshold if necessary.
-			if(	(priv->AdRxSignalStrength > (priv->AdRxSsThreshold + 10)) && // Signal is much stronger than current threshold
-				priv->AdRxSsThreshold <= priv->AdMaxRxSsThreshold) // Current threhold is not yet reach upper limit.
-			{
-				priv->AdRxSsThreshold = (priv->AdRxSsThreshold + priv->AdRxSignalStrength) / 2;
-				priv->AdRxSsThreshold = (priv->AdRxSsThreshold > priv->AdMaxRxSsThreshold) ?
-												priv->AdMaxRxSsThreshold: priv->AdRxSsThreshold;//+by amy 080312
+				/* Reduce Antenna Diversity checking period if possible. */
+				if (priv->AdCheckPeriod > priv->AdMinCheckPeriod)
+					priv->AdCheckPeriod /= 2;
 			}
-
-			// Reduce Antenna Diversity checking period if possible.
-			if( priv->AdCheckPeriod > priv->AdMinCheckPeriod )
-			{
-				priv->AdCheckPeriod /= 2;
-			}
-		}
 		}
 	}
-//by amy 080312
-	// Reset antenna diversity Rx related statistics.
+	/* Reset antenna diversity Rx related statistics. */
 	priv->AdRxOkCnt = 0;
 	priv->AdMainAntennaRxOkCnt = 0;
 	priv->AdAuxAntennaRxOkCnt = 0;
-//by amy 080312
-
-//	priv->AdRxOkCnt = 0;//-by amy 080312
-
-//	printk("-SwAntennaDiversity()\n");
 }
 
-//
-//	Description:
-//		Return TRUE if we shall perform Tx Power Tracking Mecahnism, FALSE otherwise.
-//
-bool
-CheckTxPwrTracking(	struct net_device *dev)
+ /*	Return TRUE if we shall perform Tx Power Tracking Mecahnism, FALSE otherwise. */
+bool CheckTxPwrTracking(struct net_device *dev)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
 
-	if(!priv->bTxPowerTrack)
-	{
+	if (!priv->bTxPowerTrack)
 		return false;
-	}
 
-//lzm reserved 080826
-	//if(priv->bScanInProgress)
-	//{
-	//	return false;
-	//}
-
-	//if 87SE is in High Power , don't do Tx Power Tracking. asked by SD3 ED. 2008-08-08 Isaiah
-	if(priv->bToUpdateTxPwr)
-	{
+	/* if 87SE is in High Power , don't do Tx Power Tracking. asked by SD3 ED. 2008-08-08 Isaiah */
+	if (priv->bToUpdateTxPwr)
 		return false;
-	}
 
 	return true;
 }
 
 
-//
-//	Description:
-//		Timer callback function of SW Antenna Diversity.
-//
-void
-SwAntennaDiversityTimerCallback(
-	struct net_device *dev
-	)
+ /*	Timer callback function of SW Antenna Diversity. */
+void SwAntennaDiversityTimerCallback(struct net_device *dev)
 {
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
 	RT_RF_POWER_STATE rtState;
 
-	//printk("+SwAntennaDiversityTimerCallback()\n");
-
-	//
-	// We do NOT need to switch antenna while RF is off.
-	// 2007.05.09, added by Roger.
-	//
+	 /* We do NOT need to switch antenna while RF is off. */
 	rtState = priv->eRFPowerState;
-	do{
-		if (rtState == eRfOff)
-		{
-//			printk("SwAntennaDiversityTimer - RF is OFF.\n");
+	do {
+		if (rtState == eRfOff) {
 			break;
-		}
-		else if (rtState == eRfSleep)
-		{
-			// Don't access BB/RF under Disable PLL situation.
-			//RT_TRACE((COMP_RF|COMP_ANTENNA), DBG_LOUD, ("SwAntennaDiversityTimerCallback(): RF is Sleep => skip it\n"));
+		} else if (rtState == eRfSleep) {
+			/* Don't access BB/RF under Disable PLL situation. */
 			break;
 		}
 		SwAntennaDiversity(dev);
 
-	}while(false);
+	} while (false);
 
-	if(priv->up)
-	{
+	if (priv->up) {
 		priv->SwAntennaDiversityTimer.expires = jiffies + MSECS(ANTENNA_DIVERSITY_TIMER_PERIOD);
 		add_timer(&priv->SwAntennaDiversityTimer);
 	}
-
-	//printk("-SwAntennaDiversityTimerCallback()\n");
 }
 
diff --git a/drivers/staging/rtl8187se/r8180_wx.c b/drivers/staging/rtl8187se/r8180_wx.c
index 39ef7e0..303ec69 100644
--- a/drivers/staging/rtl8187se/r8180_wx.c
+++ b/drivers/staging/rtl8187se/r8180_wx.c
@@ -23,24 +23,22 @@
 
 #include "ieee80211/dot11d.h"
 
-/* #define RATE_COUNT 4 */
 u32 rtl8180_rates[] = {1000000, 2000000, 5500000, 11000000,
 	6000000, 9000000, 12000000, 18000000, 24000000, 36000000, 48000000, 54000000};
 
 #define RATE_COUNT ARRAY_SIZE(rtl8180_rates)
 
 static CHANNEL_LIST DefaultChannelPlan[] = {
-/*	{{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14},	*/	/*Default channel plan	*/
-	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64}, 19},			/*FCC							*/
-	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11},											/*IC							*/
-	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64}, 21},	/*ETSI							*/
-	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64}, 21},	/*Spain. Change to ETSI.		*/
-	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64}, 21},	/*France. Change to ETSI.		*/
-	{{14, 36, 40, 44, 48, 52, 56, 60, 64}, 9},											/*MKK							*/
-	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52, 56, 60, 64}, 22},/*MKK1						*/
-	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64}, 21},	/*Israel.						*/
-	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 34, 38, 42, 46}, 17},					/*For 11a , TELEC				*/
-	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14}								/*For Global Domain. 1-11:active scan, 12-14 passive scan.*/	/* +YJ, 080626 */
+	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64}, 19},		/* FCC */
+	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11},						/* IC */
+	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64}, 21},	/* ETSI	*/
+	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64}, 21},	/* Spain. Change to ETSI. */
+	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64}, 21},	/* France. Change to ETSI. */
+	{{14, 36, 40, 44, 48, 52, 56, 60, 64}, 9},						/* MKK */
+	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52, 56, 60, 64}, 22},	/* MKK1	*/
+	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64}, 21},	/* Israel */
+	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 34, 38, 42, 46}, 17},			/* For 11a , TELEC */
+	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14}					/* For Global Domain. 1-11:active scan, 12-14 passive scan.*/	/* +YJ, 080626 */
 };
 static int r8180_wx_get_freq(struct net_device *dev,
 			     struct iw_request_info *a,
@@ -63,14 +61,7 @@
 
 	if (erq->flags & IW_ENCODE_DISABLED)
 
-/*	i = erq->flags & IW_ENCODE_INDEX;
-	if (i < 1 || i > 4)
-*/
-
 	if (erq->length > 0) {
-
-		/*int len = erq->length <= 5 ? 5 : 13;	*/
-
 		u32* tkey = (u32*) key;
 		priv->key0[0] = tkey[0];
 		priv->key0[1] = tkey[1];
@@ -192,33 +183,32 @@
 		return 0;
 
 	down(&priv->wx_sem);
-/*	printk("set mode ENABLE_IPS\n");	*/
 	if (priv->bInactivePs)	{
 		if (wrqu->mode == IW_MODE_ADHOC)
 			IPSLeave(dev);
 	}
 	ret = ieee80211_wx_set_mode(priv->ieee80211, a, wrqu, b);
 
-/*	rtl8180_commit(dev);	*/
-
 	up(&priv->wx_sem);
 	return ret;
 }
 
 /* YJ,add,080819,for hidden ap */
 struct  iw_range_with_scan_capa	{
-		/* Informative stuff (to choose between different interface)	*/
-		__u32		throughput;		/* To give an idea...				*/
+		/* Informative stuff (to choose between different interface) */
+
+		__u32		throughput; /* To give an idea... */
+
 		/* In theory this value should be the maximum benchmarked
-		* TCP/IP throughput, because with most of these devices the
-		* bit rate is meaningless (overhead an co) to estimate how
-		* fast the connection will go and pick the fastest one.
-		* I suggest people to play with Netperf or any benchmark...
-		*/
+		 * TCP/IP throughput, because with most of these devices the
+		 * bit rate is meaningless (overhead an co) to estimate how
+		 * fast the connection will go and pick the fastest one.
+		 * I suggest people to play with Netperf or any benchmark...
+		 */
 
 		/* NWID (or domain id)	*/
-		__u32           min_nwid;       /* Minimal NWID we are able to set */
-		__u32			max_nwid;		/* Maximal NWID we are able to set */
+		__u32           min_nwid; /* Minimal NWID we are able to set */
+		__u32			max_nwid; /* Maximal NWID we are able to set */
 
 		/* Old Frequency (backward compat - moved lower ) */
 		__u16			old_num_channels;
@@ -238,7 +228,6 @@
 	struct r8180_priv *priv = ieee80211_priv(dev);
 	u16 val;
 	int i;
-	/*struct iw_range_with_scan_capa* tmp = (struct iw_range_with_scan_capa*)range; */ /*YJ,add,080819,for hidden ap */
 
 	wrqu->data.length = sizeof(*range);
 	memset(range, 0, sizeof(*range));
@@ -291,14 +280,6 @@
 	range->we_version_compiled = WIRELESS_EXT;
 	range->we_version_source = 16;
 
-/*	range->retry_capa;	*/	/* What retry options are supported */
-/*	range->retry_flags;	*/	/* How to decode max/min retry limit */
-/*	range->r_time_flags;*/	/* How to decode max/min retry life */
-/*	range->min_retry;	*/	/* Minimal number of retries */
-/*	range->max_retry;	*/	/* Maximal number of retries */
-/*	range->min_r_time;	*/	/* Minimal retry lifetime */
-/*	range->max_r_time;	*/	/* Maximal retry lifetime */
-
 		range->num_channels = 14;
 
 	for (i = 0, val = 0; i < 14; i++) {
@@ -310,8 +291,8 @@
 			range->freq[val].e = 1;
 			val++;
 		} else {
-			/* FIXME: do we need to set anything for channels	*/
-			/* we don't use ?	*/
+			/* FIXME: do we need to set anything for channels */
+			/* we don't use ? */
 		}
 
 		if (val == IW_MAX_FREQUENCIES)
@@ -322,8 +303,6 @@
 	range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
 						IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
 
-	/*tmp->scan_capa = 0x01;	*/	/*YJ,add,080819,for hidden ap	*/
-
 	return 0;
 }
 
@@ -339,50 +318,29 @@
 	if (priv->ieee80211->bHwRadioOff)
 		return 0;
 
-/*YJ,add,080819, for hidden ap	*/
-	/*printk("==*&*&*&==>%s in\n", __func__);	*/
-	/*printk("=*&*&*&*===>flag:%x, %x\n", wrqu->data.flags, IW_SCAN_THIS_ESSID);	*/
 	if (wrqu->data.flags & IW_SCAN_THIS_ESSID)	{
 		struct iw_scan_req* req = (struct iw_scan_req*)b;
 		if (req->essid_len)		{
-			/*printk("==**&*&*&**===>scan set ssid:%s\n", req->essid); */
 			ieee->current_network.ssid_len = req->essid_len;
 			memcpy(ieee->current_network.ssid, req->essid, req->essid_len);
-			/*printk("=====>network ssid:%s\n", ieee->current_network.ssid); */
 		}
 	}
-/*YJ,add,080819, for hidden ap, end */
 
 	down(&priv->wx_sem);
 	if (priv->up)	{
-/*		printk("set scan ENABLE_IPS\n");	*/
 		priv->ieee80211->actscanning = true;
 		if (priv->bInactivePs && (priv->ieee80211->state != IEEE80211_LINKED))	{
 			IPSLeave(dev);
-			/*down(&priv->ieee80211->wx_sem);	*/
-/*
-			if (priv->ieee80211->iw_mode == IW_MODE_MONITOR || !(priv->ieee80211->proto_started)){
-				ret = -1;
-				up(&priv->ieee80211->wx_sem);
-				up(&priv->wx_sem);
-				return ret;
-			}
-*/
-	/*	queue_work(priv->ieee80211->wq, &priv->ieee80211->wx_sync_scan_wq); */
-		/* printk("start scan============================>\n"); */
 		ieee80211_softmac_ips_scan_syncro(priv->ieee80211);
-/* ieee80211_rtl_start_scan(priv->ieee80211); */
-		/* intentionally forget to up sem */
-/*			up(&priv->ieee80211->wx_sem); */
 			ret = 0;
 		}	else	{
-			/* YJ,add,080828, prevent scan in BusyTraffic */
+			/* prevent scan in BusyTraffic */
 			/* FIXME: Need to consider last scan time */
 			if ((priv->link_detect.bBusyTraffic) && (true))	{
 				ret = 0;
 				printk("Now traffic is busy, please try later!\n");
 			}	else
-				/* YJ,add,080828, prevent scan in BusyTraffic,end */
+				/* prevent scan in BusyTraffic,end */
 				ret = ieee80211_wx_set_scan(priv->ieee80211, a, wrqu, b);
 		}
 	}	else
@@ -424,10 +382,8 @@
 		return 0;
 
 	down(&priv->wx_sem);
-	/* printk("set essid ENABLE_IPS\n"); */
 	if (priv->bInactivePs)
 		IPSLeave(dev);
-/*	printk("haha:set essid %s essid_len = %d essid_flgs = %d\n",b,  wrqu->essid.length, wrqu->essid.flags);	*/
 
 	ret = ieee80211_wx_set_essid(priv->ieee80211, a, wrqu, b);
 
@@ -597,28 +553,6 @@
 	return 1;
 }
 
-
-/* added by christian */
-/*
-static int r8180_wx_set_monitor_type(struct net_device *dev, struct iw_request_info *aa, union
-	iwreq_data *wrqu, char *p){
-
-	struct r8180_priv *priv = ieee80211_priv(dev);
-	int *parms=(int*)p;
-	int mode=parms[0];
-
-	if(priv->ieee80211->iw_mode != IW_MODE_MONITOR) return -1;
-	priv->prism_hdr = mode;
-	if(!mode)dev->type=ARPHRD_IEEE80211;
-	else dev->type=ARPHRD_IEEE80211_PRISM;
-	DMESG("using %s RX encap", mode ? "AVS":"80211");
-	return 0;
-
-}
-*/
-/*of         r8180_wx_set_monitor_type */
-/* end added christian */
-
 static int r8180_wx_set_retry(struct net_device *dev,
 				struct iw_request_info *info,
 				union iwreq_data *wrqu, char *extra)
@@ -661,14 +595,6 @@
 	 */
 
 	rtl8180_commit(dev);
-	/*
-	if(priv->up){
-		rtl8180_rtx_disable(dev);
-		rtl8180_rx_enable(dev);
-		rtl8180_tx_enable(dev);
-
-	}
-	*/
 exit:
 	up(&priv->wx_sem);
 
@@ -695,8 +621,6 @@
 		wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MIN;
 		wrqu->retry.value = priv->retry_data;
 	}
-	/* DMESG("returning %d",wrqu->retry.value); */
-
 
 	return 0;
 }
@@ -726,7 +650,6 @@
 		return 0;
 
 	down(&priv->wx_sem);
-	/* DMESG("attempt to set sensivity to %ddb",wrqu->sens.value); */
 	if (priv->rf_set_sens == NULL) {
 		err = -1; /* we have not this support for this radio */
 		goto exit;
@@ -847,58 +770,6 @@
 	return -1;
 }
 
-/*
-static int r8180_wx_get_psmode(struct net_device *dev,
-			       struct iw_request_info *info,
-			       union iwreq_data *wrqu, char *extra)
-{
-	struct r8180_priv *priv = ieee80211_priv(dev);
-	struct ieee80211_device *ieee;
-	int ret = 0;
-
-
-
-	down(&priv->wx_sem);
-
-	if(priv) {
-		ieee = priv->ieee80211;
-		if(ieee->ps == IEEE80211_PS_DISABLED) {
-			*((unsigned int *)extra) = IEEE80211_PS_DISABLED;
-			goto exit;
-		}
-		*((unsigned int *)extra) = IW_POWER_TIMEOUT;
-	if (ieee->ps & IEEE80211_PS_MBCAST)
-			*((unsigned int *)extra) |= IW_POWER_ALL_R;
-		else
-			*((unsigned int *)extra) |= IW_POWER_UNICAST_R;
-	} else
-		ret = -1;
-exit:
-	up(&priv->wx_sem);
-
-	return ret;
-}
-static int r8180_wx_set_psmode(struct net_device *dev,
-			       struct iw_request_info *info,
-			       union iwreq_data *wrqu, char *extra)
-{
-	struct r8180_priv *priv = ieee80211_priv(dev);
-	//struct ieee80211_device *ieee;
-	int ret = 0;
-
-
-
-	down(&priv->wx_sem);
-
-	ret = ieee80211_wx_set_power(priv->ieee80211, info, wrqu, extra);
-
-	up(&priv->wx_sem);
-
-	return ret;
-
-}
-*/
-
 static int r8180_wx_get_iwmode(struct net_device *dev,
 			       struct iw_request_info *info,
 			       union iwreq_data *wrqu, char *extra)
@@ -964,7 +835,6 @@
 	} else {
 		ieee->mode = mode;
 		ieee->modulation = modulation;
-/*		ieee80211_start_protocol(ieee); */
 	}
 
 	up(&priv->wx_sem);
@@ -1016,7 +886,6 @@
 			       union iwreq_data *wrqu, char *extra)
 {
 	struct r8180_priv *priv = ieee80211_priv(dev);
-	/* struct ieee80211_network *network = &(priv->ieee80211->current_network); */
 	int ret = 0;
 
 
@@ -1036,7 +905,6 @@
 			       union iwreq_data *wrqu, char *extra)
 {
 	struct r8180_priv *priv = ieee80211_priv(dev);
-	/* struct ieee80211_network *network = &(priv->ieee80211->current_network); */
 	int ret = 0;
 
 
@@ -1150,7 +1018,6 @@
 			     union iwreq_data *wrqu, char *extra)
 {
 	struct r8180_priv *priv = ieee80211_priv(dev);
-	/* struct ieee80211_device *ieee = netdev_priv(dev); */
 	int *val = (int *)extra;
 	int i;
 	printk("-----in fun %s\n", __func__);
@@ -1223,7 +1090,6 @@
 {
 
 	struct r8180_priv *priv = ieee80211_priv(dev);
-	/* printk("===>%s()\n", __func__); */
 
 	int ret = 0;
 
@@ -1240,7 +1106,6 @@
 			     struct iw_request_info *info,
 			     union iwreq_data *wrqu, char *extra)
 {
-	/* printk("====>%s()\n", __func__); */
 	struct r8180_priv *priv = ieee80211_priv(dev);
 	int ret = 0;
 
@@ -1257,8 +1122,6 @@
 										struct iw_request_info *info,
 										union iwreq_data *wrqu, char *extra)
 {
-	/* printk("====>%s()\n", __func__); */
-
 	int ret = 0;
 	struct r8180_priv *priv = ieee80211_priv(dev);
 
@@ -1278,7 +1141,6 @@
 			       struct iw_request_info *info,
 			       union iwreq_data *wrqu, char *extra)
 {
-/*	printk("====>%s(), len:%d\n", __func__, data->length); */
 	int ret = 0;
 		struct r8180_priv *priv = ieee80211_priv(dev);
 
@@ -1291,68 +1153,67 @@
 		ret = ieee80211_wx_set_gen_ie(priv->ieee80211, extra, wrqu->data.length);
 #endif
 		up(&priv->wx_sem);
-	/* printk("<======%s(), ret:%d\n", __func__, ret); */
 		return ret;
 
 
 }
 static iw_handler r8180_wx_handlers[] =	{
-		NULL,						/* SIOCSIWCOMMIT */
+		NULL,					/* SIOCSIWCOMMIT */
 		r8180_wx_get_name,			/* SIOCGIWNAME */
-		dummy,						/* SIOCSIWNWID */
-		dummy,						/* SIOCGIWNWID */
+		dummy,					/* SIOCSIWNWID */
+		dummy,					/* SIOCGIWNWID */
 		r8180_wx_set_freq,			/* SIOCSIWFREQ */
 		r8180_wx_get_freq,			/* SIOCGIWFREQ */
 		r8180_wx_set_mode,			/* SIOCSIWMODE */
 		r8180_wx_get_mode,			/* SIOCGIWMODE */
 		r8180_wx_set_sens,			/* SIOCSIWSENS */
 		r8180_wx_get_sens,			/* SIOCGIWSENS */
-		NULL,						/* SIOCSIWRANGE */
-		rtl8180_wx_get_range,		/* SIOCGIWRANGE */
-		NULL,						/* SIOCSIWPRIV */
-		NULL,						/* SIOCGIWPRIV */
-		NULL,						/* SIOCSIWSTATS */
-		NULL,						/* SIOCGIWSTATS */
-		dummy,						/* SIOCSIWSPY */
-		dummy,						/* SIOCGIWSPY */
-		NULL,						/* SIOCGIWTHRSPY */
-		NULL,						/* SIOCWIWTHRSPY */
+		NULL,					/* SIOCSIWRANGE */
+		rtl8180_wx_get_range,			/* SIOCGIWRANGE */
+		NULL,					/* SIOCSIWPRIV */
+		NULL,					/* SIOCGIWPRIV */
+		NULL,					/* SIOCSIWSTATS */
+		NULL,					/* SIOCGIWSTATS */
+		dummy,					/* SIOCSIWSPY */
+		dummy,					/* SIOCGIWSPY */
+		NULL,					/* SIOCGIWTHRSPY */
+		NULL,					/* SIOCWIWTHRSPY */
 		r8180_wx_set_wap,			/* SIOCSIWAP */
 		r8180_wx_get_wap,			/* SIOCGIWAP */
 		r8180_wx_set_mlme,			/* SIOCSIWMLME*/
-		dummy,						/* SIOCGIWAPLIST -- depricated */
+		dummy,					/* SIOCGIWAPLIST -- depricated */
 		r8180_wx_set_scan,			/* SIOCSIWSCAN */
 		r8180_wx_get_scan,			/* SIOCGIWSCAN */
 		r8180_wx_set_essid,			/* SIOCSIWESSID */
 		r8180_wx_get_essid,			/* SIOCGIWESSID */
-		dummy,						/* SIOCSIWNICKN */
-		dummy,						/* SIOCGIWNICKN */
-		NULL,						/* -- hole -- */
-		NULL,						/* -- hole -- */
+		dummy,					/* SIOCSIWNICKN */
+		dummy,					/* SIOCGIWNICKN */
+		NULL,					/* -- hole -- */
+		NULL,					/* -- hole -- */
 		r8180_wx_set_rate,			/* SIOCSIWRATE */
 		r8180_wx_get_rate,			/* SIOCGIWRATE */
 		r8180_wx_set_rts,			/* SIOCSIWRTS */
 		r8180_wx_get_rts,			/* SIOCGIWRTS */
 		r8180_wx_set_frag,			/* SIOCSIWFRAG */
 		r8180_wx_get_frag,			/* SIOCGIWFRAG */
-		dummy,						/* SIOCSIWTXPOW */
-		dummy,						/* SIOCGIWTXPOW */
+		dummy,					/* SIOCSIWTXPOW */
+		dummy,					/* SIOCGIWTXPOW */
 		r8180_wx_set_retry,			/* SIOCSIWRETRY */
 		r8180_wx_get_retry,			/* SIOCGIWRETRY */
 		r8180_wx_set_enc,			/* SIOCSIWENCODE */
 		r8180_wx_get_enc,			/* SIOCGIWENCODE */
 		r8180_wx_set_power,			/* SIOCSIWPOWER */
 		r8180_wx_get_power,			/* SIOCGIWPOWER */
-		NULL,						/*---hole---*/
-		NULL,						/*---hole---*/
-		r8180_wx_set_gen_ie,		/* SIOCSIWGENIE */
-		NULL,						/* SIOCSIWGENIE */
+		NULL,					/*---hole---*/
+		NULL,					/*---hole---*/
+		r8180_wx_set_gen_ie,			/* SIOCSIWGENIE */
+		NULL,					/* SIOCSIWGENIE */
 		r8180_wx_set_auth,			/* SIOCSIWAUTH */
-		NULL,						/* SIOCSIWAUTH */
-		r8180_wx_set_enc_ext,		/* SIOCSIWENCODEEXT */
-		NULL,						/* SIOCSIWENCODEEXT */
-		NULL,						/* SIOCSIWPMKSA */
-		NULL,						/*---hole---*/
+		NULL,					/* SIOCSIWAUTH */
+		r8180_wx_set_enc_ext,			/* SIOCSIWENCODEEXT */
+		NULL,					/* SIOCSIWENCODEEXT */
+		NULL,					/* SIOCSIWPMKSA */
+		NULL,					/*---hole---*/
 };
 
 
@@ -1373,14 +1234,6 @@
 		0, 0, "dummy"
 
 	},
-	/* added by christian */
-	/*
-	{
-		SIOCIWFIRSTPRIV + 0x2,
-		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "prismhdr"
-	},
-	*/
-	/* end added by christian */
 	{
 		SIOCIWFIRSTPRIV + 0x4,
 		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "activescan"
@@ -1399,18 +1252,6 @@
 		0, 0, "dummy"
 
 	},
-/*
-	{
-		SIOCIWFIRSTPRIV + 0x5,
-		0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpsmode"
-	},
-	{
-		SIOCIWFIRSTPRIV + 0x6,
-		IW_PRIV_SIZE_FIXED, 0, "setpsmode"
-	},
-*/
-/* set/get mode have been realized in public handlers */
-
 	{
 		SIOCIWFIRSTPRIV + 0x8,
 		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setiwmode"
@@ -1481,7 +1322,7 @@
 
 
 static iw_handler r8180_private_handler[] = {
-	r8180_wx_set_crcmon,   /*SIOCIWSECONDPRIV*/
+	r8180_wx_set_crcmon, /*SIOCIWSECONDPRIV*/
 	dummy,
 	r8180_wx_set_beaconinterval,
 	dummy,
@@ -1513,16 +1354,15 @@
 									struct ieee80211_network *dst,
 				  struct ieee80211_device *ieee)
 {
-		/*		A network is only a duplicate if the channel, BSSID, ESSID
-		* and the capability field (in particular IBSS and BSS) all match.
-		* We treat all <hidden> with the same BSSID and channel
-		* as one network		*/
-		return (((src->ssid_len == dst->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) &&	/* YJ,mod, 080819,for hidden ap	*/
-			/* ((src->ssid_len == dst->ssid_len) && */
+		/* A network is only a duplicate if the channel, BSSID, ESSID
+		 * and the capability field (in particular IBSS and BSS) all match.
+		 * We treat all <hidden> with the same BSSID and channel
+		 * as one network
+		 */
+		return (((src->ssid_len == dst->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) && /* YJ,mod, 080819,for hidden ap */
 			(src->channel == dst->channel) &&
 			!memcmp(src->bssid, dst->bssid, ETH_ALEN) &&
 			(!memcmp(src->ssid, dst->ssid, src->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) &&  /* YJ,mod, 080819,for hidden ap */
-			/*!memcmp(src->ssid, dst->ssid, src->ssid_len) && */
 			((src->capability & WLAN_CAPABILITY_IBSS) ==
 			(dst->capability & WLAN_CAPABILITY_IBSS)) &&
 			((src->capability & WLAN_CAPABILITY_BSS) ==
@@ -1535,11 +1375,9 @@
 	struct r8180_priv *priv = ieee80211_priv(dev);
 	struct ieee80211_device* ieee = priv->ieee80211;
 	struct iw_statistics* wstats = &priv->wstats;
-	/* struct ieee80211_network* target = NULL; */
 	int tmp_level = 0;
 	int tmp_qual = 0;
 	int tmp_noise = 0;
-	/* unsigned long flag; */
 
 	if (ieee->state < IEEE80211_LINKED)	{
 		wstats->qual.qual = 0;
@@ -1552,9 +1390,7 @@
 	tmp_level = (&ieee->current_network)->stats.signal;
 	tmp_qual = (&ieee->current_network)->stats.signalstrength;
 	tmp_noise = (&ieee->current_network)->stats.noise;
-	/* printk("level:%d, qual:%d, noise:%d\n", tmp_level, tmp_qual, tmp_noise); */
 
-/*	printk("level:%d\n", tmp_level);	*/
 	wstats->qual.level = tmp_level;
 	wstats->qual.qual = tmp_qual;
 	wstats->qual.noise = tmp_noise;
diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c
index 6c5061f..13979b5 100644
--- a/drivers/staging/rtl8192e/rtllib_rx.c
+++ b/drivers/staging/rtl8192e/rtllib_rx.c
@@ -2453,7 +2453,7 @@
 	if (src->wmm_param[0].ac_aci_acm_aifsn ||
 	   src->wmm_param[1].ac_aci_acm_aifsn ||
 	   src->wmm_param[2].ac_aci_acm_aifsn ||
-	   src->wmm_param[1].ac_aci_acm_aifsn)
+	   src->wmm_param[3].ac_aci_acm_aifsn)
 		memcpy(dst->wmm_param, src->wmm_param, WME_AC_PRAM_LEN);
 
 	dst->SignalStrength = src->SignalStrength;
diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c
index 1637f11..c5a15db 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac.c
@@ -2234,7 +2234,6 @@
 
 			if (!network)
 				return 1;
-			memset(network, 0, sizeof(*network));
 			ieee->state = RTLLIB_LINKED;
 			ieee->assoc_id = aid;
 			ieee->softmac_stats.rx_ass_ok++;
@@ -2259,8 +2258,8 @@
 					ieee->handle_assoc_response(ieee->dev,
 						 (struct rtllib_assoc_response_frame *)header,
 						 network);
-				kfree(network);
 			}
+			kfree(network);
 
 			kfree(ieee->assocresp_ies);
 			ieee->assocresp_ies = NULL;
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
index c9bdc7f..be2a28c 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
@@ -237,7 +237,7 @@
 
 	#ifdef NOT_YET
 	if (ieee->iw_mode == IW_MODE_MASTER) {
-		printk(KERN_DEBUG "%s: Master mode not yet suppported.\n",
+		printk(KERN_DEBUG "%s: Master mode not yet supported.\n",
 		       ieee->dev->name);
 		return 0;
 /*
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index c09be0a..9c00865 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -105,7 +105,6 @@
 
 static const struct usb_device_id rtl8192_usb_id_tbl[] = {
 	/* Realtek */
-	{USB_DEVICE(0x0bda, 0x8192)},
 	{USB_DEVICE(0x0bda, 0x8709)},
 	/* Corega */
 	{USB_DEVICE(0x07aa, 0x0043)},
diff --git a/drivers/staging/rtl8712/Kconfig b/drivers/staging/rtl8712/Kconfig
index ea37473..6a43312 100644
--- a/drivers/staging/rtl8712/Kconfig
+++ b/drivers/staging/rtl8712/Kconfig
@@ -9,13 +9,6 @@
 	This option adds the Realtek RTL8712 USB device such as the D-Link DWA-130.
 	If built as a module, it will be called r8712u.
 
-config R8712_AP
-	bool "Realtek RTL8712U AP code"
-	depends on R8712U
-	default N
-	---help---
-	This option allows the Realtek RTL8712 USB device to be an Access Point.
-
 config R8712_TX_AGGR
 	bool "Realtek RTL8712U Transmit Aggregation code"
 	depends on R8712U && BROKEN
diff --git a/drivers/staging/rtl8712/drv_types.h b/drivers/staging/rtl8712/drv_types.h
index ed85b44..e83665d 100644
--- a/drivers/staging/rtl8712/drv_types.h
+++ b/drivers/staging/rtl8712/drv_types.h
@@ -140,7 +140,6 @@
 	u8   ishighspeed;
 	uint(*inirp_init)(struct _adapter *adapter);
 	uint(*inirp_deinit)(struct _adapter *adapter);
-	struct semaphore usb_suspend_sema;
 	struct usb_device *pusbdev;
 };
 
diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c
index 98a3d68..7bbd53a 100644
--- a/drivers/staging/rtl8712/os_intfs.c
+++ b/drivers/staging/rtl8712/os_intfs.c
@@ -330,7 +330,6 @@
 	padapter->stapriv.padapter = padapter;
 	r8712_init_bcmc_stainfo(padapter);
 	r8712_init_pwrctrl_priv(padapter);
-	sema_init(&(padapter->pwrctrlpriv.pnp_pwr_mgnt_sema), 0);
 	mp871xinit(padapter);
 	if (init_default_value(padapter) != _SUCCESS)
 		return _FAIL;
@@ -476,11 +475,6 @@
 	r8712_free_assoc_resources(padapter);
 	/*s2-4.*/
 	r8712_free_network_queue(padapter);
-	/* The interface is no longer Up: */
-	padapter->bup = false;
-	release_firmware(padapter->fw);
-	/* never exit with a firmware callback pending */
-	wait_for_completion(&padapter->rtl8712_fw_ready);
 	return 0;
 }
 
diff --git a/drivers/staging/rtl8712/osdep_service.h b/drivers/staging/rtl8712/osdep_service.h
index 1ee943a..9ba6033 100644
--- a/drivers/staging/rtl8712/osdep_service.h
+++ b/drivers/staging/rtl8712/osdep_service.h
@@ -72,18 +72,6 @@
 #define LIST_CONTAINOR(ptr, type, member) \
 	((type *)((char *)(ptr)-(SIZE_T)(&((type *)0)->member)))
 
-static inline void _enter_hwio_critical(struct semaphore *prwlock,
-					unsigned long *pirqL)
-{
-	down(prwlock);
-}
-
-static inline void _exit_hwio_critical(struct semaphore *prwlock,
-				       unsigned long *pirqL)
-{
-	up(prwlock);
-}
-
 static inline void list_delete(struct list_head *plist)
 {
 	list_del_init(plist);
@@ -152,11 +140,6 @@
 		return _SUCCESS;
 }
 
-static inline void _rtl_rwlock_init(struct semaphore *prwlock)
-{
-	sema_init(prwlock, 1);
-}
-
 static inline void _init_listhead(struct list_head *list)
 {
 	INIT_LIST_HEAD(list);
diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c
index 6d69265..fa6dc9c 100644
--- a/drivers/staging/rtl8712/rtl8712_recv.c
+++ b/drivers/staging/rtl8712/rtl8712_recv.c
@@ -55,8 +55,6 @@
 	int alignment = 0;
 	struct sk_buff *pskb = NULL;
 
-	sema_init(&precvpriv->recv_sema, 0);
-	sema_init(&precvpriv->terminate_recvthread_sema, 0);
 	/*init recv_buf*/
 	_init_queue(&precvpriv->free_recv_buf_queue);
 	precvpriv->pallocated_recv_buf = _malloc(NR_RECVBUFF *
diff --git a/drivers/staging/rtl8712/rtl871x_io.c b/drivers/staging/rtl8712/rtl871x_io.c
index ca84ee0..abc1c97 100644
--- a/drivers/staging/rtl8712/rtl871x_io.c
+++ b/drivers/staging/rtl8712/rtl871x_io.c
@@ -131,7 +131,6 @@
 	pio_req = (struct io_req *)(pio_queue->free_ioreqs_buf);
 	for (i = 0; i < NUM_IOREQ; i++) {
 		_init_listhead(&pio_req->list);
-		sema_init(&pio_req->sema, 0);
 		list_insert_tail(&pio_req->list, &pio_queue->free_ioreqs);
 		pio_req++;
 	}
diff --git a/drivers/staging/rtl8712/rtl871x_io.h b/drivers/staging/rtl8712/rtl871x_io.h
index 86308a0..d3d8727 100644
--- a/drivers/staging/rtl8712/rtl871x_io.h
+++ b/drivers/staging/rtl8712/rtl871x_io.h
@@ -117,7 +117,6 @@
 	u32	command;
 	u32	status;
 	u8	*pbuf;
-	struct semaphore sema;
 	void (*_async_io_callback)(struct _adapter *padater,
 				   struct io_req *pio_req, u8 *cnxt);
 	u8 *cnxt;
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
index 507584b8..ef35bc2 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
@@ -2380,13 +2380,7 @@
 		tmp_qual = padapter->recvpriv.signal;
 		tmp_noise = padapter->recvpriv.noise;
 		piwstats->qual.level = tmp_level;
-		/*piwstats->qual.qual = tmp_qual;
-		 * The NetworkManager of Fedora 10, 13 will use the link
-		 * quality for its display.
-		 * So, use the fw_rssi on link quality variable because
-		 * fw_rssi will be updated per 2 seconds.
-		 */
-		piwstats->qual.qual = tmp_level;
+		piwstats->qual.qual = tmp_qual;
 		piwstats->qual.noise = tmp_noise;
 	}
 	piwstats->qual.updated = IW_QUAL_ALL_UPDATED;
diff --git a/drivers/staging/rtl8712/rtl871x_pwrctrl.c b/drivers/staging/rtl8712/rtl871x_pwrctrl.c
index 23e72a0..9fd2ec7 100644
--- a/drivers/staging/rtl8712/rtl871x_pwrctrl.c
+++ b/drivers/staging/rtl8712/rtl871x_pwrctrl.c
@@ -100,7 +100,6 @@
 {
 	struct pwrctrl_priv *pwrpriv = &(padapter->pwrctrlpriv);
 	struct cmd_priv	*pcmdpriv = &(padapter->cmdpriv);
-	struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
 
 	if (pwrpriv->cpwm_tog == ((preportpwrstate->state) & 0x80))
 		return;
@@ -110,8 +109,6 @@
 	if (pwrpriv->cpwm >= PS_STATE_S2) {
 		if (pwrpriv->alives & CMD_ALIVE)
 			up(&(pcmdpriv->cmd_queue_sema));
-		if (pwrpriv->alives & XMIT_ALIVE)
-			up(&(pxmitpriv->xmit_sema));
 	}
 	pwrpriv->cpwm_tog = (preportpwrstate->state) & 0x80;
 	up(&pwrpriv->lock);
@@ -145,12 +142,12 @@
 				       struct pwrctrl_priv, SetPSModeWorkItem);
 	struct _adapter *padapter = container_of(pwrpriv,
 				    struct _adapter, pwrctrlpriv);
-	_enter_pwrlock(&pwrpriv->lock);
 	if (!pwrpriv->bSleep) {
+		_enter_pwrlock(&pwrpriv->lock);
 		if (pwrpriv->pwr_mode == PS_MODE_ACTIVE)
 			r8712_set_rpwm(padapter, PS_STATE_S4);
+		up(&pwrpriv->lock);
 	}
-	up(&pwrpriv->lock);
 }
 
 static void rpwm_workitem_callback(struct work_struct *work)
@@ -160,13 +157,13 @@
 	struct _adapter *padapter = container_of(pwrpriv,
 				    struct _adapter, pwrctrlpriv);
 	u8 cpwm = pwrpriv->cpwm;
-	_enter_pwrlock(&pwrpriv->lock);
 	if (pwrpriv->cpwm != pwrpriv->rpwm) {
+		_enter_pwrlock(&pwrpriv->lock);
 		cpwm = r8712_read8(padapter, SDIO_HCPWM);
 		pwrpriv->rpwm_retry = 1;
 		r8712_set_rpwm(padapter, pwrpriv->rpwm);
+		up(&pwrpriv->lock);
 	}
-	up(&pwrpriv->lock);
 }
 
 static void rpwm_check_handler (void *FunctionContext)
diff --git a/drivers/staging/rtl8712/rtl871x_pwrctrl.h b/drivers/staging/rtl8712/rtl871x_pwrctrl.h
index b41ca28..6024c4f 100644
--- a/drivers/staging/rtl8712/rtl871x_pwrctrl.h
+++ b/drivers/staging/rtl8712/rtl871x_pwrctrl.h
@@ -133,7 +133,6 @@
 	u8	rpwm_retry;
 	uint	bSetPSModeWorkItemInProgress;
 
-	struct semaphore pnp_pwr_mgnt_sema;
 	spinlock_t pnp_pwr_mgnt_lock;
 	s32	pnp_current_pwr_state;
 	u8	pnp_bstop_trx;
diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c
index 7069f06..5b03b40 100644
--- a/drivers/staging/rtl8712/rtl871x_recv.c
+++ b/drivers/staging/rtl8712/rtl871x_recv.c
@@ -93,7 +93,6 @@
 		precvframe++;
 	}
 	precvpriv->rx_pending_cnt = 1;
-	sema_init(&precvpriv->allrxreturnevt, 0);
 	return r8712_init_recv_priv(precvpriv, padapter);
 }
 
diff --git a/drivers/staging/rtl8712/rtl871x_recv.h b/drivers/staging/rtl8712/rtl871x_recv.h
index cc7a72f..e42e6f0 100644
--- a/drivers/staging/rtl8712/rtl871x_recv.h
+++ b/drivers/staging/rtl8712/rtl871x_recv.h
@@ -85,8 +85,6 @@
 */
 struct recv_priv {
 	spinlock_t lock;
-	struct semaphore recv_sema;
-	struct semaphore terminate_recvthread_sema;
 	struct  __queue	free_recv_queue;
 	struct  __queue	recv_pending_queue;
 	u8 *pallocated_frame_buf;
@@ -100,7 +98,6 @@
 	uint  rx_largepacket_crcerr;
 	uint  rx_smallpacket_crcerr;
 	uint  rx_middlepacket_crcerr;
-	struct semaphore allrxreturnevt;
 	u8  rx_pending_cnt;
 	uint	ff_hwaddr;
 	struct tasklet_struct recv_tasklet;
diff --git a/drivers/staging/rtl8712/rtl871x_sta_mgt.c b/drivers/staging/rtl8712/rtl871x_sta_mgt.c
index 81bde80..1247b3d 100644
--- a/drivers/staging/rtl8712/rtl871x_sta_mgt.c
+++ b/drivers/staging/rtl8712/rtl871x_sta_mgt.c
@@ -42,10 +42,8 @@
 	_init_listhead(&psta->hash_list);
 	_r8712_init_sta_xmit_priv(&psta->sta_xmitpriv);
 	_r8712_init_sta_recv_priv(&psta->sta_recvpriv);
-#ifdef CONFIG_R8712_AP
 	_init_listhead(&psta->asoc_list);
 	_init_listhead(&psta->auth_list);
-#endif
 }
 
 u32 _r8712_init_sta_priv(struct	sta_priv *pstapriv)
@@ -72,10 +70,8 @@
 				 get_list_head(&pstapriv->free_sta_queue));
 		psta++;
 	}
-#ifdef CONFIG_R8712_AP
 	_init_listhead(&pstapriv->asoc_list);
 	_init_listhead(&pstapriv->auth_list);
-#endif
 	return _SUCCESS;
 }
 
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c
index 8bbdee7..aa57e77 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.c
+++ b/drivers/staging/rtl8712/rtl871x_xmit.c
@@ -71,8 +71,6 @@
 
 	memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv));
 	spin_lock_init(&pxmitpriv->lock);
-	sema_init(&pxmitpriv->xmit_sema, 0);
-	sema_init(&pxmitpriv->terminate_xmitthread_sema, 0);
 	/*
 	Please insert all the queue initializaiton using _init_queue below
 	*/
@@ -121,7 +119,6 @@
 	_r8712_init_hw_txqueue(&pxmitpriv->bmc_txqueue, BMC_QUEUE_INX);
 	pxmitpriv->frag_len = MAX_FRAG_THRESHOLD;
 	pxmitpriv->txirp_cnt = 1;
-	sema_init(&(pxmitpriv->tx_retevt), 0);
 	/*per AC pending irp*/
 	pxmitpriv->beq_cnt = 0;
 	pxmitpriv->bkq_cnt = 0;
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.h b/drivers/staging/rtl8712/rtl871x_xmit.h
index a034c0f..638b79b 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.h
+++ b/drivers/staging/rtl8712/rtl871x_xmit.h
@@ -202,8 +202,6 @@
 
 struct	xmit_priv {
 	spinlock_t lock;
-	struct semaphore xmit_sema;
-	struct semaphore terminate_xmitthread_sema;
 	struct  __queue	be_pending;
 	struct  __queue	bk_pending;
 	struct  __queue	vi_pending;
@@ -233,7 +231,6 @@
 	uint	tx_drop;
 	struct hw_xmit *hwxmits;
 	u8	hwxmit_entry;
-	struct semaphore tx_retevt;/*all tx return event;*/
 	u8	txirp_cnt;
 	struct tasklet_struct xmit_tasklet;
 	_workitem xmit_pipe4_reset_wi;
diff --git a/drivers/staging/rtl8712/sta_info.h b/drivers/staging/rtl8712/sta_info.h
index 48d6a14..f8016e9 100644
--- a/drivers/staging/rtl8712/sta_info.h
+++ b/drivers/staging/rtl8712/sta_info.h
@@ -90,7 +90,6 @@
 	 * curr_network(mlme_priv/security_priv/qos/ht) : AP CAP/INFO
 	 * sta_info: (AP & STA) CAP/INFO
 	 */
-#ifdef CONFIG_R8712_AP
 	struct list_head asoc_list;
 	struct list_head auth_list;
 	unsigned int expire_to;
@@ -98,7 +97,6 @@
 	unsigned int authalg;
 	unsigned char chg_txt[128];
 	unsigned int tx_ra_bitmap;
-#endif
 };
 
 struct	sta_priv {
@@ -111,13 +109,11 @@
 	struct  __queue sleep_q;
 	struct  __queue wakeup_q;
 	struct _adapter *padapter;
-#ifdef CONFIG_R8712_AP
 	struct list_head asoc_list;
 	struct list_head auth_list;
 	unsigned int auth_to;  /* sec, time to expire in authenticating. */
 	unsigned int assoc_to; /* sec, time to expire before associating. */
 	unsigned int expire_to; /* sec , time to expire after associated. */
-#endif
 };
 
 static inline u32 wifi_mac_hash(u8 *mac)
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
index 9bade18..e419b4f 100644
--- a/drivers/staging/rtl8712/usb_intf.c
+++ b/drivers/staging/rtl8712/usb_intf.c
@@ -30,6 +30,7 @@
 
 #include <linux/usb.h>
 #include <linux/module.h>
+#include <linux/firmware.h>
 
 #include "osdep_service.h"
 #include "drv_types.h"
@@ -105,10 +106,10 @@
 /* RTL8191SU */
 	/* Realtek */
 	{USB_DEVICE(0x0BDA, 0x8172)},
+	{USB_DEVICE(0x0BDA, 0x8192)},
 	/* Amigo */
 	{USB_DEVICE(0x0EB0, 0x9061)},
 	/* ASUS/EKB */
-	{USB_DEVICE(0x0BDA, 0x8172)},
 	{USB_DEVICE(0x13D3, 0x3323)},
 	{USB_DEVICE(0x13D3, 0x3311)}, /* 11n mode disable */
 	{USB_DEVICE(0x13D3, 0x3342)},
@@ -160,7 +161,6 @@
 /* RTL8192SU */
 	/* Realtek */
 	{USB_DEVICE(0x0BDA, 0x8174)},
-	{USB_DEVICE(0x0BDA, 0x8174)},
 	/* Belkin */
 	{USB_DEVICE(0x050D, 0x845A)},
 	/* Corega */
@@ -281,7 +281,6 @@
 	}
 	if ((r8712_alloc_io_queue(padapter)) == _FAIL)
 		status = _FAIL;
-	sema_init(&(padapter->dvobjpriv.usb_suspend_sema), 0);
 	return status;
 }
 
@@ -623,6 +622,10 @@
 
 	usb_set_intfdata(pusb_intf, NULL);
 	if (padapter) {
+		if (padapter->fw_found)
+			release_firmware(padapter->fw);
+		/* never exit with a firmware callback pending */
+		wait_for_completion(&padapter->rtl8712_fw_ready);
 		if (drvpriv.drv_registered == true)
 			padapter->bSurpriseRemoved = true;
 		if (pnetdev != NULL) {
diff --git a/drivers/staging/rts5139/TODO b/drivers/staging/rts5139/TODO
index 4bde726..dd5fabb 100644
--- a/drivers/staging/rts5139/TODO
+++ b/drivers/staging/rts5139/TODO
@@ -2,4 +2,8 @@
 - support more USB card reader of Realtek family
 - use kernel coding style
 - checkpatch.pl fixes
-
+- stop having thousands of lines of code duplicated with staging/rts_pstor
+- This driver contains an entire SD/MMC stack -- it should use the stack in
+  drivers/mmc instead, as a host driver e.g. drivers/mmc/host/realtek-usb.c;
+  see drivers/mmc/host/ushc.c as an example.
+- This driver presents cards as SCSI devices, but they should be MMC devices.
diff --git a/drivers/staging/rts5139/ms.h b/drivers/staging/rts5139/ms.h
index f9d46d2..3ce1dc9 100644
--- a/drivers/staging/rts5139/ms.h
+++ b/drivers/staging/rts5139/ms.h
@@ -249,9 +249,9 @@
 #ifdef SUPPORT_MAGIC_GATE
 
 int ms_switch_clock(struct rts51x_chip *chip);
-int ms_write_bytes(struct rts51x_chip *chip, u8 tpc, u8 cnt, u8 cfg, u8 * data,
+int ms_write_bytes(struct rts51x_chip *chip, u8 tpc, u8 cnt, u8 cfg, u8 *data,
 		   int data_len);
-int ms_read_bytes(struct rts51x_chip *chip, u8 tpc, u8 cnt, u8 cfg, u8 * data,
+int ms_read_bytes(struct rts51x_chip *chip, u8 tpc, u8 cnt, u8 cfg, u8 *data,
 		  int data_len);
 int ms_set_rw_reg_addr(struct rts51x_chip *chip, u8 read_start, u8 read_cnt,
 		       u8 write_start, u8 write_cnt);
diff --git a/drivers/staging/rts5139/rts51x_chip.c b/drivers/staging/rts5139/rts51x_chip.c
index adc0d00..b3e0bb2 100644
--- a/drivers/staging/rts5139/rts51x_chip.c
+++ b/drivers/staging/rts5139/rts51x_chip.c
@@ -541,7 +541,7 @@
 	return STATUS_SUCCESS;
 }
 
-int rts51x_get_card_status(struct rts51x_chip *chip, u16 * status)
+int rts51x_get_card_status(struct rts51x_chip *chip, u16 *status)
 {
 	int retval;
 	u16 val;
@@ -577,7 +577,7 @@
 	return STATUS_SUCCESS;
 }
 
-int rts51x_read_register(struct rts51x_chip *chip, u16 addr, u8 * data)
+int rts51x_read_register(struct rts51x_chip *chip, u16 addr, u8 *data)
 {
 	int retval;
 
@@ -620,7 +620,7 @@
 	return STATUS_SUCCESS;
 }
 
-int rts51x_ep0_read_register(struct rts51x_chip *chip, u16 addr, u8 * data)
+int rts51x_ep0_read_register(struct rts51x_chip *chip, u16 addr, u8 *data)
 {
 	int retval;
 	u16 value = 0;
@@ -720,7 +720,7 @@
 	return STATUS_SUCCESS;
 }
 
-int rts51x_read_ppbuf(struct rts51x_chip *chip, u8 * buf, int buf_len)
+int rts51x_read_ppbuf(struct rts51x_chip *chip, u8 *buf, int buf_len)
 {
 	int retval;
 
@@ -735,7 +735,7 @@
 	return STATUS_SUCCESS;
 }
 
-int rts51x_write_ppbuf(struct rts51x_chip *chip, u8 * buf, int buf_len)
+int rts51x_write_ppbuf(struct rts51x_chip *chip, u8 *buf, int buf_len)
 {
 	int retval;
 
@@ -776,7 +776,7 @@
 	return STATUS_SUCCESS;
 }
 
-int rts51x_read_phy_register(struct rts51x_chip *chip, u8 addr, u8 * val)
+int rts51x_read_phy_register(struct rts51x_chip *chip, u8 addr, u8 *val)
 {
 	int retval;
 
@@ -921,7 +921,7 @@
 }
 #endif
 
-void rts51x_pp_status(struct rts51x_chip *chip, unsigned int lun, u8 * status,
+void rts51x_pp_status(struct rts51x_chip *chip, unsigned int lun, u8 *status,
 		      u8 status_len)
 {
 	struct sd_info *sd_card = &(chip->sd_card);
diff --git a/drivers/staging/rts5139/rts51x_chip.h b/drivers/staging/rts5139/rts51x_chip.h
index 321ece7..13fc2a4 100644
--- a/drivers/staging/rts5139/rts51x_chip.h
+++ b/drivers/staging/rts5139/rts51x_chip.h
@@ -857,12 +857,12 @@
 	return chip->rsp_buf;
 }
 
-int rts51x_get_card_status(struct rts51x_chip *chip, u16 * status);
+int rts51x_get_card_status(struct rts51x_chip *chip, u16 *status);
 int rts51x_write_register(struct rts51x_chip *chip, u16 addr, u8 mask, u8 data);
-int rts51x_read_register(struct rts51x_chip *chip, u16 addr, u8 * data);
+int rts51x_read_register(struct rts51x_chip *chip, u16 addr, u8 *data);
 int rts51x_ep0_write_register(struct rts51x_chip *chip, u16 addr, u8 mask,
 			      u8 data);
-int rts51x_ep0_read_register(struct rts51x_chip *chip, u16 addr, u8 * data);
+int rts51x_ep0_read_register(struct rts51x_chip *chip, u16 addr, u8 *data);
 int rts51x_seq_write_register(struct rts51x_chip *chip, u16 addr, u16 len,
 			      u8 *data);
 int rts51x_seq_read_register(struct rts51x_chip *chip, u16 addr, u16 len,
diff --git a/drivers/staging/rts5139/rts51x_fop.h b/drivers/staging/rts5139/rts51x_fop.h
index 0453f57..94d75f0 100644
--- a/drivers/staging/rts5139/rts51x_fop.h
+++ b/drivers/staging/rts5139/rts51x_fop.h
@@ -48,7 +48,7 @@
 int rts51x_release(struct inode *inode, struct file *filp);
 ssize_t rts51x_read(struct file *filp, char __user *buf, size_t count,
 		    loff_t *f_pos);
-ssize_t rts51x_write(struct file *filp, const char __user * buf, size_t count,
+ssize_t rts51x_write(struct file *filp, const char __user *buf, size_t count,
 		     loff_t *f_pos);
 #if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) */
 int rts51x_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
diff --git a/drivers/staging/rts5139/rts51x_transport.c b/drivers/staging/rts5139/rts51x_transport.c
index e11467a..da9c83b 100644
--- a/drivers/staging/rts5139/rts51x_transport.c
+++ b/drivers/staging/rts5139/rts51x_transport.c
@@ -883,7 +883,7 @@
 	return result;
 }
 
-int rts51x_get_epc_status(struct rts51x_chip *chip, u16 * status)
+int rts51x_get_epc_status(struct rts51x_chip *chip, u16 *status)
 {
 	unsigned int pipe = RCV_INTR_PIPE(chip);
 	struct usb_host_endpoint *ep;
diff --git a/drivers/staging/rts5139/rts51x_transport.h b/drivers/staging/rts5139/rts51x_transport.h
index 8464c48..9dd556e 100644
--- a/drivers/staging/rts5139/rts51x_transport.h
+++ b/drivers/staging/rts5139/rts51x_transport.h
@@ -73,7 +73,7 @@
 void rts51x_cancel_epc_transfer(struct rts51x_chip *chip);
 #endif
 
-int rts51x_get_epc_status(struct rts51x_chip *chip, u16 * status);
+int rts51x_get_epc_status(struct rts51x_chip *chip, u16 *status);
 void rts51x_invoke_transport(struct scsi_cmnd *srb, struct rts51x_chip *chip);
 
 #endif /* __RTS51X_TRANSPORT_H */
diff --git a/drivers/staging/rts5139/sd_cprm.c b/drivers/staging/rts5139/sd_cprm.c
index 407cd43..d5969d9 100644
--- a/drivers/staging/rts5139/sd_cprm.c
+++ b/drivers/staging/rts5139/sd_cprm.c
@@ -233,7 +233,7 @@
 	return STATUS_SUCCESS;
 }
 
-int ext_sd_get_rsp(struct rts51x_chip *chip, int len, u8 * rsp, u8 rsp_type)
+int ext_sd_get_rsp(struct rts51x_chip *chip, int len, u8 *rsp, u8 rsp_type)
 {
 	int retval, rsp_len;
 	u16 reg_addr;
diff --git a/drivers/staging/rts_pstor/TODO b/drivers/staging/rts_pstor/TODO
index 2f93a7c..becb95e 100644
--- a/drivers/staging/rts_pstor/TODO
+++ b/drivers/staging/rts_pstor/TODO
@@ -2,4 +2,8 @@
 - support more pcie card reader of Realtek family
 - use kernel coding style
 - checkpatch.pl fixes
-
+- stop having thousands of lines of code duplicated with staging/rts5139
+- This driver contains an entire SD/MMC stack -- it should use the stack in
+  drivers/mmc instead, as a host driver e.g. drivers/mmc/host/realtek-pci.c;
+  see drivers/mmc/host/via-sdmmc.c as an example.
+- This driver presents cards as SCSI devices, but they should be MMC devices.
diff --git a/drivers/staging/sbe-2t3e3/intr.c b/drivers/staging/sbe-2t3e3/intr.c
index 7ad1a83..1336aab 100644
--- a/drivers/staging/sbe-2t3e3/intr.c
+++ b/drivers/staging/sbe-2t3e3/intr.c
@@ -188,7 +188,7 @@
 			}
 
 			if (sc->s.LOS) {
-				error_mask &= ~(SBE_2T3E3_RX_DESC_DRIBBLING_BIT ||
+				error_mask &= ~(SBE_2T3E3_RX_DESC_DRIBBLING_BIT |
 						SBE_2T3E3_RX_DESC_MII_ERROR);
 			}
 
diff --git a/drivers/staging/sep/Kconfig b/drivers/staging/sep/Kconfig
index 92bf166..185b676 100644
--- a/drivers/staging/sep/Kconfig
+++ b/drivers/staging/sep/Kconfig
@@ -3,7 +3,8 @@
 	depends on PCI
 	help
 	  Discretix SEP driver; used for the security processor subsystem
-	  on bard the Intel Mobile Internet Device.
+	  on board the Intel Mobile Internet Device and adds SEP availability
+	  to the kernel crypto infrastructure
 
 	  The driver's name is sep_driver.
 
diff --git a/drivers/staging/sep/Makefile b/drivers/staging/sep/Makefile
index 628d5f9..e48a795 100644
--- a/drivers/staging/sep/Makefile
+++ b/drivers/staging/sep/Makefile
@@ -1,2 +1,3 @@
-obj-$(CONFIG_DX_SEP) := sep_driver.o
-
+ccflags-y += -I$(srctree)/$(src)
+obj-$(CONFIG_DX_SEP) += sep_driver.o
+sep_driver-objs := sep_crypto.o sep_main.o
diff --git a/drivers/staging/sep/TODO b/drivers/staging/sep/TODO
index 8f3b878..3524d0c 100644
--- a/drivers/staging/sep/TODO
+++ b/drivers/staging/sep/TODO
@@ -1,4 +1,3 @@
 Todo's so far (from Alan Cox)
-- Check whether it can be plugged into any of the kernel crypto API
-  interfaces - Crypto API 'glue' is still not ready to submit
-- Clean up un-needed debug prints - Started to work on this
+- Clean up unused ioctls
+- Clean up unused fields in ioctl structures
diff --git a/drivers/staging/sep/sep_crypto.c b/drivers/staging/sep/sep_crypto.c
new file mode 100644
index 0000000..1cc790e
--- /dev/null
+++ b/drivers/staging/sep/sep_crypto.c
@@ -0,0 +1,4058 @@
+/*
+ *
+ *  sep_crypto.c - Crypto interface structures
+ *
+ *  Copyright(c) 2009-2011 Intel Corporation. All rights reserved.
+ *  Contributions(c) 2009-2010 Discretix. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; version 2 of the License.
+ *
+ *  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., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ *  CONTACTS:
+ *
+ *  Mark Allyn		mark.a.allyn@intel.com
+ *  Jayant Mangalampalli jayant.mangalampalli@intel.com
+ *
+ *  CHANGES:
+ *
+ *  2009.06.26	Initial publish
+ *  2010.09.14  Upgrade to Medfield
+ *  2011.02.22  Enable Kernel Crypto
+ *
+ */
+
+/* #define DEBUG */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/kdev_t.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <linux/pci.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+#include <linux/crypto.h>
+#include <crypto/internal/hash.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/sha.h>
+#include <crypto/md5.h>
+#include <crypto/aes.h>
+#include <crypto/des.h>
+#include <crypto/hash.h>
+#include "sep_driver_hw_defs.h"
+#include "sep_driver_config.h"
+#include "sep_driver_api.h"
+#include "sep_dev.h"
+#include "sep_crypto.h"
+
+#if defined(CONFIG_CRYPTO) || defined(CONFIG_CRYPTO_MODULE)
+
+/* Globals for queuing */
+static spinlock_t queue_lock;
+static struct crypto_queue sep_queue;
+
+/* Declare of dequeuer */
+static void sep_dequeuer(void *data);
+
+/* TESTING */
+/**
+ * crypto_sep_dump_message - dump the message that is pending
+ * @sep: SEP device
+ * This will only print dump if DEBUG is set; it does
+ * follow kernel debug print enabling
+ */
+static void crypto_sep_dump_message(struct sep_device *sep, void *msg)
+{
+#if 0
+	u32 *p;
+	u32 *i;
+	int count;
+
+	p = sep->shared_addr;
+	i = (u32 *)msg;
+	for (count = 0; count < 10 * 4; count += 4)
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] Word %d of the message is %x (local)%x\n",
+				current->pid, count/4, *p++, *i++);
+#endif
+}
+
+/**
+ *	sep_do_callback
+ *	@work: pointer to work_struct
+ *	This is what is called by the queue; it is generic so that it
+ *	can be used by any type of operation as each different callback
+ *	function can use the data parameter in its own way
+ */
+static void sep_do_callback(struct work_struct *work)
+{
+	struct sep_work_struct *sep_work = container_of(work,
+		struct sep_work_struct, work);
+	if (sep_work != NULL) {
+		(sep_work->callback)(sep_work->data);
+		kfree(sep_work);
+	} else {
+		pr_debug("sep crypto: do callback - NULL container\n");
+	}
+}
+
+/**
+ *	sep_submit_work
+ *	@work_queue: pointer to struct_workqueue
+ *	@funct: pointer to function to execute
+ *	@data: pointer to data; function will know
+ *		how to use it
+ *	This is a generic API to submit something to
+ *	the queue. The callback function will depend
+ *	on what operation is to be done
+ */
+static int sep_submit_work(struct workqueue_struct *work_queue,
+	void(*funct)(void *),
+	void *data)
+{
+	struct sep_work_struct *sep_work;
+	int result;
+
+	sep_work = kmalloc(sizeof(struct sep_work_struct), GFP_ATOMIC);
+
+	if (sep_work == NULL) {
+		pr_debug("sep crypto: cant allocate work structure\n");
+		return -ENOMEM;
+	}
+
+	sep_work->callback = funct;
+	sep_work->data = data;
+	INIT_WORK(&sep_work->work, sep_do_callback);
+	result = queue_work(work_queue, &sep_work->work);
+	if (!result) {
+		pr_debug("sep_crypto: queue_work failed\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/**
+ *	sep_alloc_sg_buf -
+ *	@sep: pointer to struct sep_device
+ *	@size: total size of area
+ *	@block_size: minimum size of chunks
+ *	each page is minimum or modulo this size
+ *	@returns: pointer to struct scatterlist for new
+ *	buffer
+ **/
+static struct scatterlist *sep_alloc_sg_buf(
+	struct sep_device *sep,
+	size_t size,
+	size_t block_size)
+{
+	u32 nbr_pages;
+	u32 ct1;
+	void *buf;
+	size_t current_size;
+	size_t real_page_size;
+
+	struct scatterlist *sg, *sg_temp;
+
+	if (size == 0)
+		return NULL;
+
+	dev_dbg(&sep->pdev->dev, "sep alloc sg buf\n");
+
+	current_size = 0;
+	nbr_pages = 0;
+	real_page_size = PAGE_SIZE - (PAGE_SIZE % block_size);
+	/**
+	 * The size of each page must be modulo of the operation
+	 * block size; increment by the modified page size until
+	 * the total size is reached, then you have the number of
+	 * pages
+	 */
+	while (current_size < size) {
+		current_size += real_page_size;
+		nbr_pages += 1;
+	}
+
+	sg = kmalloc((sizeof(struct scatterlist) * nbr_pages), GFP_ATOMIC);
+	if (!sg) {
+		dev_warn(&sep->pdev->dev, "Cannot allocate page for new sg\n");
+		return NULL;
+	}
+
+	sg_init_table(sg, nbr_pages);
+
+	current_size = 0;
+	sg_temp = sg;
+	for (ct1 = 0; ct1 < nbr_pages; ct1 += 1) {
+		buf = (void *)get_zeroed_page(GFP_ATOMIC);
+		if (!buf) {
+			dev_warn(&sep->pdev->dev,
+				"Cannot allocate page for new buffer\n");
+			kfree(sg);
+			return NULL;
+		}
+
+		sg_set_buf(sg_temp, buf, real_page_size);
+		if ((size - current_size) > real_page_size) {
+			sg_temp->length = real_page_size;
+			current_size += real_page_size;
+		} else {
+			sg_temp->length = (size - current_size);
+			current_size = size;
+		}
+		sg_temp = sg_next(sg);
+	}
+	return sg;
+}
+
+/**
+ *	sep_free_sg_buf -
+ *	@sg: pointer to struct scatterlist; points to area to free
+ */
+static void sep_free_sg_buf(struct scatterlist *sg)
+{
+	struct scatterlist *sg_temp = sg;
+		while (sg_temp) {
+			free_page((unsigned long)sg_virt(sg_temp));
+			sg_temp = sg_next(sg_temp);
+		}
+		kfree(sg);
+}
+
+/**
+ *	sep_copy_sg -
+ *	@sep: pointer to struct sep_device
+ *	@sg_src: pointer to struct scatterlist for source
+ *	@sg_dst: pointer to struct scatterlist for destination
+ *      @size: size (in bytes) of data to copy
+ *
+ *	Copy data from one scatterlist to another; both must
+ *	be the same size
+ */
+static void sep_copy_sg(
+	struct sep_device *sep,
+	struct scatterlist *sg_src,
+	struct scatterlist *sg_dst,
+	size_t size)
+{
+	u32 seg_size;
+	u32 in_offset, out_offset;
+
+	u32 count = 0;
+	struct scatterlist *sg_src_tmp = sg_src;
+	struct scatterlist *sg_dst_tmp = sg_dst;
+	in_offset = 0;
+	out_offset = 0;
+
+	dev_dbg(&sep->pdev->dev, "sep copy sg\n");
+
+	if ((sg_src == NULL) || (sg_dst == NULL) || (size == 0))
+		return;
+
+	dev_dbg(&sep->pdev->dev, "sep copy sg not null\n");
+
+	while (count < size) {
+		if ((sg_src_tmp->length - in_offset) >
+			(sg_dst_tmp->length - out_offset))
+			seg_size = sg_dst_tmp->length - out_offset;
+		else
+			seg_size = sg_src_tmp->length - in_offset;
+
+		if (seg_size > (size - count))
+			seg_size = (size = count);
+
+		memcpy(sg_virt(sg_dst_tmp) + out_offset,
+			sg_virt(sg_src_tmp) + in_offset,
+			seg_size);
+
+		in_offset += seg_size;
+		out_offset += seg_size;
+		count += seg_size;
+
+		if (in_offset >= sg_src_tmp->length) {
+			sg_src_tmp = sg_next(sg_src_tmp);
+			in_offset = 0;
+		}
+
+		if (out_offset >= sg_dst_tmp->length) {
+			sg_dst_tmp = sg_next(sg_dst_tmp);
+			out_offset = 0;
+		}
+	}
+}
+
+/**
+ *	sep_oddball_pages -
+ *	@sep: pointer to struct sep_device
+ *	@sg: pointer to struct scatterlist - buffer to check
+ *	@size: total data size
+ *	@blocksize: minimum block size; must be multiples of this size
+ *	@to_copy: 1 means do copy, 0 means do not copy
+ *	@new_sg: pointer to location to put pointer to new sg area
+ *	@returns: 1 if new scatterlist is needed; 0 if not needed;
+ *		error value if operation failed
+ *
+ *	The SEP device requires all pages to be multiples of the
+ *	minimum block size appropriate for the operation
+ *	This function check all pages; if any are oddball sizes
+ *	(not multiple of block sizes), it creates a new scatterlist.
+ *	If the to_copy parameter is set to 1, then a scatter list
+ *	copy is performed. The pointer to the new scatterlist is
+ *	put into the address supplied by the new_sg parameter; if
+ *	no new scatterlist is needed, then a NULL is put into
+ *	the location at new_sg.
+ *
+ */
+static int sep_oddball_pages(
+	struct sep_device *sep,
+	struct scatterlist *sg,
+	size_t data_size,
+	u32 block_size,
+	struct scatterlist **new_sg,
+	u32 do_copy)
+{
+	struct scatterlist *sg_temp;
+	u32 flag;
+	u32 nbr_pages, page_count;
+
+	dev_dbg(&sep->pdev->dev, "sep oddball\n");
+	if ((sg == NULL) || (data_size == 0) || (data_size < block_size))
+		return 0;
+
+	dev_dbg(&sep->pdev->dev, "sep oddball not null\n");
+	flag = 0;
+	nbr_pages = 0;
+	page_count = 0;
+	sg_temp = sg;
+
+	while (sg_temp) {
+		nbr_pages += 1;
+		sg_temp = sg_next(sg_temp);
+	}
+
+	sg_temp = sg;
+	while ((sg_temp) && (flag == 0)) {
+		page_count += 1;
+		if (sg_temp->length % block_size)
+			flag = 1;
+		else
+			sg_temp = sg_next(sg_temp);
+	}
+
+	/* Do not process if last (or only) page is oddball */
+	if (nbr_pages == page_count)
+		flag = 0;
+
+	if (flag) {
+		dev_dbg(&sep->pdev->dev, "sep oddball processing\n");
+		*new_sg = sep_alloc_sg_buf(sep, data_size, block_size);
+		if (*new_sg == NULL) {
+			dev_warn(&sep->pdev->dev, "cannot allocate new sg\n");
+			return -ENOMEM;
+		}
+
+		if (do_copy)
+			sep_copy_sg(sep, sg, *new_sg, data_size);
+
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+/**
+ *	sep_copy_offset_sg -
+ *	@sep: pointer to struct sep_device;
+ *	@sg: pointer to struct scatterlist
+ *	@offset: offset into scatterlist memory
+ *	@dst: place to put data
+ *	@len: length of data
+ *	@returns: number of bytes copies
+ *
+ *	This copies data from scatterlist buffer
+ *	offset from beginning - it is needed for
+ *	handling tail data in hash
+ */
+static size_t sep_copy_offset_sg(
+	struct sep_device *sep,
+	struct scatterlist *sg,
+	u32 offset,
+	void *dst,
+	u32 len)
+{
+	size_t page_start;
+	size_t page_end;
+	size_t offset_within_page;
+	size_t length_within_page;
+	size_t length_remaining;
+	size_t current_offset;
+
+	/* Find which page is beginning of segment */
+	page_start = 0;
+	page_end = sg->length;
+	while ((sg) && (offset > page_end)) {
+		page_start += sg->length;
+		sg = sg_next(sg);
+		if (sg)
+			page_end += sg->length;
+	}
+
+	if (sg == NULL)
+		return -ENOMEM;
+
+	offset_within_page = offset - page_start;
+	if ((sg->length - offset_within_page) >= len) {
+		/* All within this page */
+		memcpy(dst, sg_virt(sg) + offset_within_page, len);
+		return len;
+	} else {
+		/* Scattered multiple pages */
+		current_offset = 0;
+		length_remaining = len;
+		while ((sg) && (current_offset < len)) {
+			length_within_page = sg->length - offset_within_page;
+			if (length_within_page >= length_remaining) {
+				memcpy(dst+current_offset,
+					sg_virt(sg) + offset_within_page,
+					length_remaining);
+				length_remaining = 0;
+				current_offset = len;
+			} else {
+				memcpy(dst+current_offset,
+					sg_virt(sg) + offset_within_page,
+					length_within_page);
+				length_remaining -= length_within_page;
+				current_offset += length_within_page;
+				offset_within_page = 0;
+				sg = sg_next(sg);
+			}
+		}
+
+		if (sg == NULL)
+			return -ENOMEM;
+	}
+	return len;
+}
+
+/**
+ *	partial_overlap -
+ *	@src_ptr: source pointer
+ *	@dst_ptr: destination pointer
+ *	@nbytes: number of bytes
+ *	@returns: 0 for success; -1 for failure
+ *	We cannot have any partial overlap. Total overlap
+ *	where src is the same as dst is okay
+ */
+static int partial_overlap(void *src_ptr, void *dst_ptr, u32 nbytes)
+{
+	/* Check for partial overlap */
+	if (src_ptr != dst_ptr) {
+		if (src_ptr < dst_ptr) {
+			if ((src_ptr + nbytes) > dst_ptr)
+				return -EINVAL;
+		} else {
+			if ((dst_ptr + nbytes) > src_ptr)
+				return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+/* Debug - prints only if DEBUG is defined; follows kernel debug model */
+static void sep_dump(struct sep_device *sep, char *stg, void *start, int len)
+{
+#if 0
+	int ct1;
+	u8 *ptt;
+
+	dev_dbg(&sep->pdev->dev,
+		"Dump of %s starting at %08lx for %08x bytes\n",
+		stg, (unsigned long)start, len);
+	for (ct1 = 0; ct1 < len; ct1 += 1) {
+		ptt = (u8 *)(start + ct1);
+		dev_dbg(&sep->pdev->dev, "%02x ", *ptt);
+		if (ct1 % 16 == 15)
+			dev_dbg(&sep->pdev->dev, "\n");
+	}
+	dev_dbg(&sep->pdev->dev, "\n");
+#endif
+}
+
+/* Debug - prints only if DEBUG is defined; follows kernel debug model */
+static void sep_dump_sg(struct sep_device *sep, char *stg,
+			struct scatterlist *sg)
+{
+#if 0
+	int ct1, ct2;
+	u8 *ptt;
+
+	dev_dbg(&sep->pdev->dev, "Dump of scatterlist %s\n", stg);
+
+	ct1 = 0;
+	while (sg) {
+		dev_dbg(&sep->pdev->dev, "page %x\n size %x", ct1,
+			sg->length);
+		dev_dbg(&sep->pdev->dev, "phys addr is %lx",
+			(unsigned long)sg_phys(sg));
+		ptt = sg_virt(sg);
+		for (ct2 = 0; ct2 < sg->length; ct2 += 1) {
+			dev_dbg(&sep->pdev->dev, "byte %x is %02x\n",
+				ct2, (unsigned char)*(ptt + ct2));
+		}
+
+		ct1 += 1;
+		sg = sg_next(sg);
+	}
+	dev_dbg(&sep->pdev->dev, "\n");
+#endif
+}
+
+/* Debug - prints only if DEBUG is defined */
+static void sep_dump_ivs(struct ablkcipher_request *req, char *reason)
+
+	{
+	unsigned char *cptr;
+	struct sep_aes_internal_context *aes_internal;
+	struct sep_des_internal_context *des_internal;
+	int ct1;
+
+	struct this_task_ctx *ta_ctx;
+	struct crypto_ablkcipher *tfm;
+	struct sep_system_ctx *sctx;
+
+	ta_ctx = ablkcipher_request_ctx(req);
+	tfm = crypto_ablkcipher_reqtfm(req);
+	sctx = crypto_ablkcipher_ctx(tfm);
+
+	dev_dbg(&ta_ctx->sep_used->pdev->dev, "IV DUMP - %s\n", reason);
+	if ((ta_ctx->current_request == DES_CBC) &&
+		(ta_ctx->des_opmode == SEP_DES_CBC)) {
+
+		des_internal = (struct sep_des_internal_context *)
+			sctx->des_private_ctx.ctx_buf;
+		/* print vendor */
+		dev_dbg(&ta_ctx->sep_used->pdev->dev,
+			"sep - vendor iv for DES\n");
+		cptr = (unsigned char *)des_internal->iv_context;
+		for (ct1 = 0; ct1 < crypto_ablkcipher_ivsize(tfm); ct1 += 1)
+			dev_dbg(&ta_ctx->sep_used->pdev->dev,
+				"%02x\n", *(cptr + ct1));
+
+		/* print walk */
+		dev_dbg(&ta_ctx->sep_used->pdev->dev,
+			"sep - walk from kernel crypto iv for DES\n");
+		cptr = (unsigned char *)ta_ctx->walk.iv;
+		for (ct1 = 0; ct1 < crypto_ablkcipher_ivsize(tfm); ct1 += 1)
+			dev_dbg(&ta_ctx->sep_used->pdev->dev,
+				"%02x\n", *(cptr + ct1));
+	} else if ((ta_ctx->current_request == AES_CBC) &&
+		(ta_ctx->aes_opmode == SEP_AES_CBC)) {
+
+		aes_internal = (struct sep_aes_internal_context *)
+			sctx->aes_private_ctx.cbuff;
+		/* print vendor */
+		dev_dbg(&ta_ctx->sep_used->pdev->dev,
+			"sep - vendor iv for AES\n");
+		cptr = (unsigned char *)aes_internal->aes_ctx_iv;
+		for (ct1 = 0; ct1 < crypto_ablkcipher_ivsize(tfm); ct1 += 1)
+			dev_dbg(&ta_ctx->sep_used->pdev->dev,
+				"%02x\n", *(cptr + ct1));
+
+		/* print walk */
+		dev_dbg(&ta_ctx->sep_used->pdev->dev,
+			"sep - walk from kernel crypto iv for AES\n");
+		cptr = (unsigned char *)ta_ctx->walk.iv;
+		for (ct1 = 0; ct1 < crypto_ablkcipher_ivsize(tfm); ct1 += 1)
+			dev_dbg(&ta_ctx->sep_used->pdev->dev,
+				"%02x\n", *(cptr + ct1));
+	}
+}
+
+/**
+ * RFC2451: Weak key check
+ * Returns: 1 (weak), 0 (not weak)
+ */
+static int sep_weak_key(const u8 *key, unsigned int keylen)
+{
+	static const u8 parity[] = {
+	8, 1, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 2, 8,
+	0, 8, 8, 0, 8, 0, 0, 8, 8,
+	0, 0, 8, 0, 8, 8, 3,
+	0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0,
+	8, 0, 0, 8, 0, 8, 8, 0, 0,
+	8, 8, 0, 8, 0, 0, 8,
+	0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0,
+	8, 0, 0, 8, 0, 8, 8, 0, 0,
+	8, 8, 0, 8, 0, 0, 8,
+	8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8,
+	0, 8, 8, 0, 8, 0, 0, 8, 8,
+	0, 0, 8, 0, 8, 8, 0,
+	0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0,
+	8, 0, 0, 8, 0, 8, 8, 0, 0,
+	8, 8, 0, 8, 0, 0, 8,
+	8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8,
+	0, 8, 8, 0, 8, 0, 0, 8, 8,
+	0, 0, 8, 0, 8, 8, 0,
+	8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8,
+	0, 8, 8, 0, 8, 0, 0, 8, 8,
+	0, 0, 8, 0, 8, 8, 0,
+	4, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0,
+	8, 5, 0, 8, 0, 8, 8, 0, 0,
+	8, 8, 0, 8, 0, 6, 8,
+	};
+
+	u32 n, w;
+
+	n  = parity[key[0]]; n <<= 4;
+	n |= parity[key[1]]; n <<= 4;
+	n |= parity[key[2]]; n <<= 4;
+	n |= parity[key[3]]; n <<= 4;
+	n |= parity[key[4]]; n <<= 4;
+	n |= parity[key[5]]; n <<= 4;
+	n |= parity[key[6]]; n <<= 4;
+	n |= parity[key[7]];
+	w = 0x88888888L;
+
+	/* 1 in 10^10 keys passes this test */
+	if (!((n - (w >> 3)) & w)) {
+		if (n < 0x41415151) {
+			if (n < 0x31312121) {
+				if (n < 0x14141515) {
+					/* 01 01 01 01 01 01 01 01 */
+					if (n == 0x11111111)
+						goto weak;
+					/* 01 1F 01 1F 01 0E 01 0E */
+					if (n == 0x13131212)
+						goto weak;
+				} else {
+					/* 01 E0 01 E0 01 F1 01 F1 */
+					if (n == 0x14141515)
+						goto weak;
+					/* 01 FE 01 FE 01 FE 01 FE */
+					if (n == 0x16161616)
+						goto weak;
+				}
+			} else {
+				if (n < 0x34342525) {
+					/* 1F 01 1F 01 0E 01 0E 01 */
+					if (n == 0x31312121)
+						goto weak;
+					/* 1F 1F 1F 1F 0E 0E 0E 0E (?) */
+					if (n == 0x33332222)
+						goto weak;
+				} else {
+					/* 1F E0 1F E0 0E F1 0E F1 */
+					if (n == 0x34342525)
+						goto weak;
+					/* 1F FE 1F FE 0E FE 0E FE */
+					if (n == 0x36362626)
+						goto weak;
+				}
+			}
+		} else {
+			if (n < 0x61616161) {
+				if (n < 0x44445555) {
+					/* E0 01 E0 01 F1 01 F1 01 */
+					if (n == 0x41415151)
+						goto weak;
+					/* E0 1F E0 1F F1 0E F1 0E */
+					if (n == 0x43435252)
+						goto weak;
+				} else {
+					/* E0 E0 E0 E0 F1 F1 F1 F1 (?) */
+					if (n == 0x44445555)
+						goto weak;
+					/* E0 FE E0 FE F1 FE F1 FE */
+					if (n == 0x46465656)
+						goto weak;
+				}
+			} else {
+				if (n < 0x64646565) {
+					/* FE 01 FE 01 FE 01 FE 01 */
+					if (n == 0x61616161)
+						goto weak;
+					/* FE 1F FE 1F FE 0E FE 0E */
+					if (n == 0x63636262)
+						goto weak;
+				} else {
+					/* FE E0 FE E0 FE F1 FE F1 */
+					if (n == 0x64646565)
+						goto weak;
+					/* FE FE FE FE FE FE FE FE */
+					if (n == 0x66666666)
+						goto weak;
+				}
+			}
+		}
+	}
+	return 0;
+weak:
+	return 1;
+}
+/**
+ *	sep_sg_nents
+ */
+static u32 sep_sg_nents(struct scatterlist *sg)
+{
+	u32 ct1 = 0;
+	while (sg) {
+		ct1 += 1;
+		sg = sg_next(sg);
+	}
+
+	return ct1;
+}
+
+/**
+ *	sep_start_msg -
+ *	@ta_ctx: pointer to struct this_task_ctx
+ *	@returns: offset to place for the next word in the message
+ *	Set up pointer in message pool for new message
+ */
+static u32 sep_start_msg(struct this_task_ctx *ta_ctx)
+{
+	u32 *word_ptr;
+	ta_ctx->msg_len_words = 2;
+	ta_ctx->msgptr = ta_ctx->msg;
+	memset(ta_ctx->msg, 0, SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES);
+	ta_ctx->msgptr += sizeof(u32) * 2;
+	word_ptr = (u32 *)ta_ctx->msgptr;
+	*word_ptr = SEP_START_MSG_TOKEN;
+	return sizeof(u32) * 2;
+}
+
+/**
+ *	sep_end_msg -
+ *	@ta_ctx: pointer to struct this_task_ctx
+ *	@messages_offset: current message offset
+ *	Returns: 0 for success; <0 otherwise
+ *	End message; set length and CRC; and
+ *	send interrupt to the SEP
+ */
+static void sep_end_msg(struct this_task_ctx *ta_ctx, u32 msg_offset)
+{
+	u32 *word_ptr;
+	/* Msg size goes into msg after token */
+	ta_ctx->msg_len_words = msg_offset / sizeof(u32) + 1;
+	word_ptr = (u32 *)ta_ctx->msgptr;
+	word_ptr += 1;
+	*word_ptr = ta_ctx->msg_len_words;
+
+	/* CRC (currently 0) goes at end of msg */
+	word_ptr = (u32 *)(ta_ctx->msgptr + msg_offset);
+	*word_ptr = 0;
+}
+
+/**
+ *	sep_start_inbound_msg -
+ *	@ta_ctx: pointer to struct this_task_ctx
+ *	@msg_offset: offset to place for the next word in the message
+ *	@returns: 0 for success; error value for failure
+ *	Set up pointer in message pool for inbound message
+ */
+static u32 sep_start_inbound_msg(struct this_task_ctx *ta_ctx, u32 *msg_offset)
+{
+	u32 *word_ptr;
+	u32 token;
+	u32 error = SEP_OK;
+
+	*msg_offset = sizeof(u32) * 2;
+	word_ptr = (u32 *)ta_ctx->msgptr;
+	token = *word_ptr;
+	ta_ctx->msg_len_words = *(word_ptr + 1);
+
+	if (token != SEP_START_MSG_TOKEN) {
+		error = SEP_INVALID_START;
+		goto end_function;
+	}
+
+end_function:
+
+	return error;
+}
+
+/**
+ *	sep_write_msg -
+ *	@ta_ctx: pointer to struct this_task_ctx
+ *	@in_addr: pointer to start of parameter
+ *	@size: size of parameter to copy (in bytes)
+ *	@max_size: size to move up offset; SEP mesg is in word sizes
+ *	@msg_offset: pointer to current offset (is updated)
+ *	@byte_array: flag ti indicate wheter endian must be changed
+ *	Copies data into the message area from caller
+ */
+static void sep_write_msg(struct this_task_ctx *ta_ctx, void *in_addr,
+	u32 size, u32 max_size, u32 *msg_offset, u32 byte_array)
+{
+	u32 *word_ptr;
+	void *void_ptr;
+	void_ptr = ta_ctx->msgptr + *msg_offset;
+	word_ptr = (u32 *)void_ptr;
+	memcpy(void_ptr, in_addr, size);
+	*msg_offset += max_size;
+
+	/* Do we need to manipulate endian? */
+	if (byte_array) {
+		u32 i;
+		for (i = 0; i < ((size + 3) / 4); i += 1)
+			*(word_ptr + i) = CHG_ENDIAN(*(word_ptr + i));
+	}
+}
+
+/**
+ *	sep_make_header
+ *	@ta_ctx: pointer to struct this_task_ctx
+ *	@msg_offset: pointer to current offset (is updated)
+ *	@op_code: op code to put into message
+ *	Puts op code into message and updates offset
+ */
+static void sep_make_header(struct this_task_ctx *ta_ctx, u32 *msg_offset,
+			    u32 op_code)
+{
+	u32 *word_ptr;
+
+	*msg_offset = sep_start_msg(ta_ctx);
+	word_ptr = (u32 *)(ta_ctx->msgptr + *msg_offset);
+	*word_ptr = op_code;
+	*msg_offset += sizeof(u32);
+}
+
+
+
+/**
+ *	sep_read_msg -
+ *	@ta_ctx: pointer to struct this_task_ctx
+ *	@in_addr: pointer to start of parameter
+ *	@size: size of parameter to copy (in bytes)
+ *	@max_size: size to move up offset; SEP mesg is in word sizes
+ *	@msg_offset: pointer to current offset (is updated)
+ *	@byte_array: flag ti indicate wheter endian must be changed
+ *	Copies data out of the message area to caller
+ */
+static void sep_read_msg(struct this_task_ctx *ta_ctx, void *in_addr,
+	u32 size, u32 max_size, u32 *msg_offset, u32 byte_array)
+{
+	u32 *word_ptr;
+	void *void_ptr;
+	void_ptr = ta_ctx->msgptr + *msg_offset;
+	word_ptr = (u32 *)void_ptr;
+
+	/* Do we need to manipulate endian? */
+	if (byte_array) {
+		u32 i;
+		for (i = 0; i < ((size + 3) / 4); i += 1)
+			*(word_ptr + i) = CHG_ENDIAN(*(word_ptr + i));
+	}
+
+	memcpy(in_addr, void_ptr, size);
+	*msg_offset += max_size;
+}
+
+/**
+ *	sep_verify_op -
+ *	@ta_ctx: pointer to struct this_task_ctx
+ *	@op_code: expected op_code
+ *      @msg_offset: pointer to current offset (is updated)
+ *	@returns: 0 for success; error for failure
+ */
+static u32 sep_verify_op(struct this_task_ctx *ta_ctx, u32 op_code,
+			 u32 *msg_offset)
+{
+	u32 error;
+	u32 in_ary[2];
+
+	struct sep_device *sep = ta_ctx->sep_used;
+
+	dev_dbg(&sep->pdev->dev, "dumping return message\n");
+	error = sep_start_inbound_msg(ta_ctx, msg_offset);
+	if (error) {
+		dev_warn(&sep->pdev->dev,
+			"sep_start_inbound_msg error\n");
+		return error;
+	}
+
+	sep_read_msg(ta_ctx, in_ary, sizeof(u32) * 2, sizeof(u32) * 2,
+		msg_offset, 0);
+
+	if (in_ary[0] != op_code) {
+		dev_warn(&sep->pdev->dev,
+			"sep got back wrong opcode\n");
+		dev_warn(&sep->pdev->dev,
+			"got back %x; expected %x\n",
+			in_ary[0], op_code);
+		return SEP_WRONG_OPCODE;
+	}
+
+	if (in_ary[1] != SEP_OK) {
+		dev_warn(&sep->pdev->dev,
+			"sep execution error\n");
+		dev_warn(&sep->pdev->dev,
+			"got back %x; expected %x\n",
+			in_ary[1], SEP_OK);
+		return in_ary[0];
+	}
+
+return 0;
+}
+
+/**
+ * sep_read_context -
+ * @ta_ctx: pointer to struct this_task_ctx
+ * @msg_offset: point to current place in SEP msg; is updated
+ * @dst: pointer to place to put the context
+ * @len: size of the context structure (differs for crypro/hash)
+ * This function reads the context from the msg area
+ * There is a special way the vendor needs to have the maximum
+ * length calculated so that the msg_offset is updated properly;
+ * it skips over some words in the msg area depending on the size
+ * of the context
+ */
+static void sep_read_context(struct this_task_ctx *ta_ctx, u32 *msg_offset,
+	void *dst, u32 len)
+{
+	u32 max_length = ((len + 3) / sizeof(u32)) * sizeof(u32);
+	sep_read_msg(ta_ctx, dst, len, max_length, msg_offset, 0);
+}
+
+/**
+ * sep_write_context -
+ * @ta_ctx: pointer to struct this_task_ctx
+ * @msg_offset: point to current place in SEP msg; is updated
+ * @src: pointer to the current context
+ * @len: size of the context structure (differs for crypro/hash)
+ * This function writes the context to the msg area
+ * There is a special way the vendor needs to have the maximum
+ * length calculated so that the msg_offset is updated properly;
+ * it skips over some words in the msg area depending on the size
+ * of the context
+ */
+static void sep_write_context(struct this_task_ctx *ta_ctx, u32 *msg_offset,
+	void *src, u32 len)
+{
+	u32 max_length = ((len + 3) / sizeof(u32)) * sizeof(u32);
+	sep_write_msg(ta_ctx, src, len, max_length, msg_offset, 0);
+}
+
+/**
+ * sep_clear_out -
+ * @ta_ctx: pointer to struct this_task_ctx
+ * Clear out crypto related values in sep device structure
+ * to enable device to be used by anyone; either kernel
+ * crypto or userspace app via middleware
+ */
+static void sep_clear_out(struct this_task_ctx *ta_ctx)
+{
+	if (ta_ctx->src_sg_hold) {
+		sep_free_sg_buf(ta_ctx->src_sg_hold);
+		ta_ctx->src_sg_hold = NULL;
+	}
+
+	if (ta_ctx->dst_sg_hold) {
+		sep_free_sg_buf(ta_ctx->dst_sg_hold);
+		ta_ctx->dst_sg_hold = NULL;
+	}
+
+	ta_ctx->src_sg = NULL;
+	ta_ctx->dst_sg = NULL;
+
+	sep_free_dma_table_data_handler(ta_ctx->sep_used, &ta_ctx->dma_ctx);
+
+	if (ta_ctx->i_own_sep) {
+		/**
+		 * The following unlocks the sep and makes it available
+		 * to any other application
+		 * First, null out crypto entries in sep before relesing it
+		 */
+		ta_ctx->sep_used->current_hash_req = NULL;
+		ta_ctx->sep_used->current_cypher_req = NULL;
+		ta_ctx->sep_used->current_request = 0;
+		ta_ctx->sep_used->current_hash_stage = 0;
+		ta_ctx->sep_used->ta_ctx = NULL;
+		ta_ctx->sep_used->in_kernel = 0;
+
+		ta_ctx->call_status.status = 0;
+
+		/* Remove anything confidentail */
+		memset(ta_ctx->sep_used->shared_addr, 0,
+			SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES);
+
+		sep_queue_status_remove(ta_ctx->sep_used, &ta_ctx->queue_elem);
+
+#ifdef SEP_ENABLE_RUNTIME_PM
+		ta_ctx->sep_used->in_use = 0;
+		pm_runtime_mark_last_busy(&ta_ctx->sep_used->pdev->dev);
+		pm_runtime_put_autosuspend(&ta_ctx->sep_used->pdev->dev);
+#endif
+
+		clear_bit(SEP_WORKING_LOCK_BIT,
+			&ta_ctx->sep_used->in_use_flags);
+		ta_ctx->sep_used->pid_doing_transaction = 0;
+
+		dev_dbg(&ta_ctx->sep_used->pdev->dev,
+			"[PID%d] waking up next transaction\n",
+			current->pid);
+
+		clear_bit(SEP_TRANSACTION_STARTED_LOCK_BIT,
+			&ta_ctx->sep_used->in_use_flags);
+		wake_up(&ta_ctx->sep_used->event_transactions);
+
+		ta_ctx->i_own_sep = 0;
+	}
+}
+
+/**
+  * Release crypto infrastructure from EINPROGRESS and
+  * clear sep_dev so that SEP is available to anyone
+  */
+static void sep_crypto_release(struct sep_system_ctx *sctx,
+	struct this_task_ctx *ta_ctx, u32 error)
+{
+	struct ahash_request *hash_req = ta_ctx->current_hash_req;
+	struct ablkcipher_request *cypher_req =
+		ta_ctx->current_cypher_req;
+	struct sep_device *sep = ta_ctx->sep_used;
+
+	sep_clear_out(ta_ctx);
+
+	/**
+	 * This may not yet exist depending when we
+	 * chose to bail out. If it does exist, set
+	 * it to 1
+	 */
+	if (ta_ctx->are_we_done_yet != NULL)
+		*ta_ctx->are_we_done_yet = 1;
+
+	if (cypher_req != NULL) {
+		if ((sctx->key_sent == 1) ||
+			((error != 0) && (error != -EINPROGRESS))) {
+			if (cypher_req->base.complete == NULL) {
+				dev_dbg(&sep->pdev->dev,
+					"release is null for cypher!");
+			} else {
+				cypher_req->base.complete(
+					&cypher_req->base, error);
+			}
+		}
+	}
+
+	if (hash_req != NULL) {
+		if (hash_req->base.complete == NULL) {
+			dev_dbg(&sep->pdev->dev,
+				"release is null for hash!");
+		} else {
+			hash_req->base.complete(
+				&hash_req->base, error);
+		}
+	}
+}
+
+/**
+ *	This is where we grab the sep itself and tell it to do something.
+ *	It will sleep if the sep is currently busy
+ *	and it will return 0 if sep is now ours; error value if there
+ *	were problems
+ */
+static int sep_crypto_take_sep(struct this_task_ctx *ta_ctx)
+{
+	struct sep_device *sep = ta_ctx->sep_used;
+	int result;
+	struct sep_msgarea_hdr *my_msg_header;
+
+	my_msg_header = (struct sep_msgarea_hdr *)ta_ctx->msg;
+
+	/* add to status queue */
+	ta_ctx->queue_elem = sep_queue_status_add(sep, my_msg_header->opcode,
+		ta_ctx->nbytes, current->pid,
+		current->comm, sizeof(current->comm));
+
+	if (!ta_ctx->queue_elem) {
+		dev_dbg(&sep->pdev->dev, "[PID%d] updating queue"
+			" status error\n", current->pid);
+		return -EINVAL;
+	}
+
+	/* get the device; this can sleep */
+	result = sep_wait_transaction(sep);
+	if (result)
+		return result;
+
+	if (sep_dev->power_save_setup == 1)
+		pm_runtime_get_sync(&sep_dev->pdev->dev);
+
+	/* Copy in the message */
+	memcpy(sep->shared_addr, ta_ctx->msg,
+		SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES);
+
+	/* Copy in the dcb information if there is any */
+	if (ta_ctx->dcb_region) {
+		result = sep_activate_dcb_dmatables_context(sep,
+			&ta_ctx->dcb_region, &ta_ctx->dmatables_region,
+			ta_ctx->dma_ctx);
+		if (result)
+			return result;
+	}
+
+	/* Mark the device so we know how to finish the job in the tasklet */
+	if (ta_ctx->current_hash_req)
+		sep->current_hash_req = ta_ctx->current_hash_req;
+	else
+		sep->current_cypher_req = ta_ctx->current_cypher_req;
+
+	sep->current_request = ta_ctx->current_request;
+	sep->current_hash_stage = ta_ctx->current_hash_stage;
+	sep->ta_ctx = ta_ctx;
+	sep->in_kernel = 1;
+	ta_ctx->i_own_sep = 1;
+
+	/* need to set bit first to avoid race condition with interrupt */
+	set_bit(SEP_LEGACY_SENDMSG_DONE_OFFSET, &ta_ctx->call_status.status);
+
+	result = sep_send_command_handler(sep);
+
+	dev_dbg(&sep->pdev->dev, "[PID%d]: sending command to the sep\n",
+		current->pid);
+
+	if (!result)
+		dev_dbg(&sep->pdev->dev, "[PID%d]: command sent okay\n",
+			current->pid);
+	else {
+		dev_dbg(&sep->pdev->dev, "[PID%d]: cant send command\n",
+			current->pid);
+		clear_bit(SEP_LEGACY_SENDMSG_DONE_OFFSET,
+			&ta_ctx->call_status.status);
+	}
+
+	return result;
+}
+
+/**
+ * This function sets things up for a crypto data block process
+ * This does all preparation, but does not try to grab the
+ * sep
+ * @req: pointer to struct ablkcipher_request
+ * returns: 0 if all went well, non zero if error
+ */
+static int sep_crypto_block_data(struct ablkcipher_request *req)
+{
+
+	int int_error;
+	u32 msg_offset;
+	static u32 msg[10];
+	void *src_ptr;
+	void *dst_ptr;
+
+	static char small_buf[100];
+	ssize_t copy_result;
+	int result;
+
+	struct scatterlist *new_sg;
+	struct this_task_ctx *ta_ctx;
+	struct crypto_ablkcipher *tfm;
+	struct sep_system_ctx *sctx;
+
+	struct sep_des_internal_context *des_internal;
+	struct sep_aes_internal_context *aes_internal;
+
+	ta_ctx = ablkcipher_request_ctx(req);
+	tfm = crypto_ablkcipher_reqtfm(req);
+	sctx = crypto_ablkcipher_ctx(tfm);
+
+	/* start the walk on scatterlists */
+	ablkcipher_walk_init(&ta_ctx->walk, req->src, req->dst, req->nbytes);
+	dev_dbg(&ta_ctx->sep_used->pdev->dev, "sep crypto block data size of %x\n",
+		req->nbytes);
+
+	int_error = ablkcipher_walk_phys(req, &ta_ctx->walk);
+	if (int_error) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev, "walk phys error %x\n",
+			int_error);
+		return -ENOMEM;
+	}
+
+	dev_dbg(&ta_ctx->sep_used->pdev->dev,
+		"crypto block: src is %lx dst is %lx\n",
+		(unsigned long)req->src, (unsigned long)req->dst);
+
+	/* Make sure all pages are even block */
+	int_error = sep_oddball_pages(ta_ctx->sep_used, req->src,
+		req->nbytes, ta_ctx->walk.blocksize, &new_sg, 1);
+
+	if (int_error < 0) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev, "oddball page eerror\n");
+		return -ENOMEM;
+	} else if (int_error == 1) {
+		ta_ctx->src_sg = new_sg;
+		ta_ctx->src_sg_hold = new_sg;
+	} else {
+		ta_ctx->src_sg = req->src;
+		ta_ctx->src_sg_hold = NULL;
+	}
+
+	int_error = sep_oddball_pages(ta_ctx->sep_used, req->dst,
+		req->nbytes, ta_ctx->walk.blocksize, &new_sg, 0);
+
+	if (int_error < 0) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev, "walk phys error %x\n",
+			int_error);
+		return -ENOMEM;
+	} else if (int_error == 1) {
+		ta_ctx->dst_sg = new_sg;
+		ta_ctx->dst_sg_hold = new_sg;
+	} else {
+		ta_ctx->dst_sg = req->dst;
+		ta_ctx->dst_sg_hold = NULL;
+	}
+
+	/* set nbytes for queue status */
+	ta_ctx->nbytes = req->nbytes;
+
+	/* Key already done; this is for data */
+	dev_dbg(&ta_ctx->sep_used->pdev->dev, "sending data\n");
+
+	sep_dump_sg(ta_ctx->sep_used,
+		"block sg in", ta_ctx->src_sg);
+
+	/* check for valid data and proper spacing */
+	src_ptr = sg_virt(ta_ctx->src_sg);
+	dst_ptr = sg_virt(ta_ctx->dst_sg);
+
+	if (!src_ptr || !dst_ptr ||
+		(ta_ctx->current_cypher_req->nbytes %
+		crypto_ablkcipher_blocksize(tfm))) {
+
+		dev_warn(&ta_ctx->sep_used->pdev->dev,
+			"cipher block size odd\n");
+		dev_warn(&ta_ctx->sep_used->pdev->dev,
+			"cipher block size is %x\n",
+			crypto_ablkcipher_blocksize(tfm));
+		dev_warn(&ta_ctx->sep_used->pdev->dev,
+			"cipher data size is %x\n",
+			ta_ctx->current_cypher_req->nbytes);
+		return -EINVAL;
+	}
+
+	if (partial_overlap(src_ptr, dst_ptr,
+		ta_ctx->current_cypher_req->nbytes)) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev,
+			"block partial overlap\n");
+		return -EINVAL;
+	}
+
+	/* Put together the message */
+	sep_make_header(ta_ctx, &msg_offset, ta_ctx->block_opcode);
+
+	/* If des, and size is 1 block, put directly in msg */
+	if ((ta_ctx->block_opcode == SEP_DES_BLOCK_OPCODE) &&
+		(req->nbytes == crypto_ablkcipher_blocksize(tfm))) {
+
+		dev_dbg(&ta_ctx->sep_used->pdev->dev,
+			"writing out one block des\n");
+
+		copy_result = sg_copy_to_buffer(
+			ta_ctx->src_sg, sep_sg_nents(ta_ctx->src_sg),
+			small_buf, crypto_ablkcipher_blocksize(tfm));
+
+		if (copy_result != crypto_ablkcipher_blocksize(tfm)) {
+			dev_warn(&ta_ctx->sep_used->pdev->dev,
+				"des block copy faild\n");
+			return -ENOMEM;
+		}
+
+		/* Put data into message */
+		sep_write_msg(ta_ctx, small_buf,
+			crypto_ablkcipher_blocksize(tfm),
+			crypto_ablkcipher_blocksize(tfm) * 2,
+			&msg_offset, 1);
+
+		/* Put size into message */
+		sep_write_msg(ta_ctx, &req->nbytes,
+			sizeof(u32), sizeof(u32), &msg_offset, 0);
+	} else {
+		/* Otherwise, fill out dma tables */
+		ta_ctx->dcb_input_data.app_in_address = src_ptr;
+		ta_ctx->dcb_input_data.data_in_size = req->nbytes;
+		ta_ctx->dcb_input_data.app_out_address = dst_ptr;
+		ta_ctx->dcb_input_data.block_size =
+			crypto_ablkcipher_blocksize(tfm);
+		ta_ctx->dcb_input_data.tail_block_size = 0;
+		ta_ctx->dcb_input_data.is_applet = 0;
+		ta_ctx->dcb_input_data.src_sg = ta_ctx->src_sg;
+		ta_ctx->dcb_input_data.dst_sg = ta_ctx->dst_sg;
+
+		result = sep_create_dcb_dmatables_context_kernel(
+			ta_ctx->sep_used,
+			&ta_ctx->dcb_region,
+			&ta_ctx->dmatables_region,
+			&ta_ctx->dma_ctx,
+			&ta_ctx->dcb_input_data,
+			1);
+		if (result) {
+			dev_warn(&ta_ctx->sep_used->pdev->dev,
+				"crypto dma table create failed\n");
+			return -EINVAL;
+		}
+
+		/* Portion of msg is nulled (no data) */
+		msg[0] = (u32)0;
+		msg[1] = (u32)0;
+		msg[2] = (u32)0;
+		msg[3] = (u32)0;
+		msg[4] = (u32)0;
+		sep_write_msg(ta_ctx, (void *)msg, sizeof(u32) * 5,
+			sizeof(u32) * 5, &msg_offset, 0);
+		}
+
+	/**
+	 * Before we write the message, we need to overwrite the
+	 * vendor's IV with the one from our own ablkcipher walk
+	 * iv because this is needed for dm-crypt
+	 */
+	sep_dump_ivs(req, "sending data block to sep\n");
+	if ((ta_ctx->current_request == DES_CBC) &&
+		(ta_ctx->des_opmode == SEP_DES_CBC)) {
+
+		dev_dbg(&ta_ctx->sep_used->pdev->dev,
+			"overwrite vendor iv on DES\n");
+		des_internal = (struct sep_des_internal_context *)
+			sctx->des_private_ctx.ctx_buf;
+		memcpy((void *)des_internal->iv_context,
+			ta_ctx->walk.iv, crypto_ablkcipher_ivsize(tfm));
+	} else if ((ta_ctx->current_request == AES_CBC) &&
+		(ta_ctx->aes_opmode == SEP_AES_CBC)) {
+
+		dev_dbg(&ta_ctx->sep_used->pdev->dev,
+			"overwrite vendor iv on AES\n");
+		aes_internal = (struct sep_aes_internal_context *)
+			sctx->aes_private_ctx.cbuff;
+		memcpy((void *)aes_internal->aes_ctx_iv,
+			ta_ctx->walk.iv, crypto_ablkcipher_ivsize(tfm));
+	}
+
+	/* Write context into message */
+	if (ta_ctx->block_opcode == SEP_DES_BLOCK_OPCODE) {
+		sep_write_context(ta_ctx, &msg_offset,
+			&sctx->des_private_ctx,
+			sizeof(struct sep_des_private_context));
+		sep_dump(ta_ctx->sep_used, "ctx to block des",
+			&sctx->des_private_ctx, 40);
+	} else {
+		sep_write_context(ta_ctx, &msg_offset,
+			&sctx->aes_private_ctx,
+			sizeof(struct sep_aes_private_context));
+		sep_dump(ta_ctx->sep_used, "ctx to block aes",
+			&sctx->aes_private_ctx, 20);
+	}
+
+	/* conclude message */
+	sep_end_msg(ta_ctx, msg_offset);
+
+	/* Parent (caller) is now ready to tell the sep to do ahead */
+	return 0;
+}
+
+
+/**
+ * This function sets things up for a crypto key submit process
+ * This does all preparation, but does not try to grab the
+ * sep
+ * @req: pointer to struct ablkcipher_request
+ * returns: 0 if all went well, non zero if error
+ */
+static int sep_crypto_send_key(struct ablkcipher_request *req)
+{
+
+	int int_error;
+	u32 msg_offset;
+	static u32 msg[10];
+
+	u32 max_length;
+	struct this_task_ctx *ta_ctx;
+	struct crypto_ablkcipher *tfm;
+	struct sep_system_ctx *sctx;
+
+	ta_ctx = ablkcipher_request_ctx(req);
+	tfm = crypto_ablkcipher_reqtfm(req);
+	sctx = crypto_ablkcipher_ctx(tfm);
+
+	dev_dbg(&ta_ctx->sep_used->pdev->dev, "sending key\n");
+
+	/* start the walk on scatterlists */
+	ablkcipher_walk_init(&ta_ctx->walk, req->src, req->dst, req->nbytes);
+	dev_dbg(&ta_ctx->sep_used->pdev->dev,
+		"sep crypto block data size of %x\n", req->nbytes);
+
+	int_error = ablkcipher_walk_phys(req, &ta_ctx->walk);
+	if (int_error) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev, "walk phys error %x\n",
+			int_error);
+		return -ENOMEM;
+	}
+
+	/* check iv */
+	if ((ta_ctx->current_request == DES_CBC) &&
+		(ta_ctx->des_opmode == SEP_DES_CBC)) {
+		if (!ta_ctx->walk.iv) {
+			dev_warn(&ta_ctx->sep_used->pdev->dev, "no iv found\n");
+			return -EINVAL;
+		}
+
+		memcpy(ta_ctx->iv, ta_ctx->walk.iv, SEP_DES_IV_SIZE_BYTES);
+		sep_dump(ta_ctx->sep_used, "iv",
+			ta_ctx->iv, SEP_DES_IV_SIZE_BYTES);
+	}
+
+	if ((ta_ctx->current_request == AES_CBC) &&
+		(ta_ctx->aes_opmode == SEP_AES_CBC)) {
+		if (!ta_ctx->walk.iv) {
+			dev_warn(&ta_ctx->sep_used->pdev->dev, "no iv found\n");
+			return -EINVAL;
+		}
+
+		memcpy(ta_ctx->iv, ta_ctx->walk.iv, SEP_AES_IV_SIZE_BYTES);
+		sep_dump(ta_ctx->sep_used, "iv",
+			ta_ctx->iv, SEP_AES_IV_SIZE_BYTES);
+	}
+
+	/* put together message to SEP */
+	/* Start with op code */
+	sep_make_header(ta_ctx, &msg_offset, ta_ctx->init_opcode);
+
+	/* now deal with IV */
+	if (ta_ctx->init_opcode == SEP_DES_INIT_OPCODE) {
+		if (ta_ctx->des_opmode == SEP_DES_CBC) {
+			sep_write_msg(ta_ctx, ta_ctx->iv,
+				SEP_DES_IV_SIZE_BYTES, sizeof(u32) * 4,
+				&msg_offset, 1);
+			sep_dump(ta_ctx->sep_used, "initial IV",
+				ta_ctx->walk.iv, SEP_DES_IV_SIZE_BYTES);
+		} else {
+			/* Skip if ECB */
+			msg_offset += 4 * sizeof(u32);
+		}
+	} else {
+		max_length = ((SEP_AES_IV_SIZE_BYTES + 3) /
+			sizeof(u32)) * sizeof(u32);
+		if (ta_ctx->aes_opmode == SEP_AES_CBC) {
+			sep_write_msg(ta_ctx, ta_ctx->iv,
+				SEP_AES_IV_SIZE_BYTES, max_length,
+				&msg_offset, 1);
+			sep_dump(ta_ctx->sep_used, "initial IV",
+				ta_ctx->walk.iv, SEP_AES_IV_SIZE_BYTES);
+		} else {
+				/* Skip if ECB */
+				msg_offset += max_length;
+			}
+		}
+
+	/* load the key */
+	if (ta_ctx->init_opcode == SEP_DES_INIT_OPCODE) {
+		sep_write_msg(ta_ctx, (void *)&sctx->key.des.key1,
+			sizeof(u32) * 8, sizeof(u32) * 8,
+			&msg_offset, 1);
+
+		msg[0] = (u32)sctx->des_nbr_keys;
+		msg[1] = (u32)ta_ctx->des_encmode;
+		msg[2] = (u32)ta_ctx->des_opmode;
+
+		sep_write_msg(ta_ctx, (void *)msg,
+			sizeof(u32) * 3, sizeof(u32) * 3,
+			&msg_offset, 0);
+	} else {
+		sep_write_msg(ta_ctx, (void *)&sctx->key.aes,
+			sctx->keylen,
+			SEP_AES_MAX_KEY_SIZE_BYTES,
+			&msg_offset, 1);
+
+		msg[0] = (u32)sctx->aes_key_size;
+		msg[1] = (u32)ta_ctx->aes_encmode;
+		msg[2] = (u32)ta_ctx->aes_opmode;
+		msg[3] = (u32)0; /* Secret key is not used */
+		sep_write_msg(ta_ctx, (void *)msg,
+			sizeof(u32) * 4, sizeof(u32) * 4,
+			&msg_offset, 0);
+	}
+
+	/* conclude message */
+	sep_end_msg(ta_ctx, msg_offset);
+
+	/* Parent (caller) is now ready to tell the sep to do ahead */
+	return 0;
+}
+
+
+/* This needs to be run as a work queue as it can be put asleep */
+static void sep_crypto_block(void *data)
+{
+	unsigned long end_time;
+
+	int result;
+
+	struct ablkcipher_request *req;
+	struct this_task_ctx *ta_ctx;
+	struct crypto_ablkcipher *tfm;
+	struct sep_system_ctx *sctx;
+	int are_we_done_yet;
+
+	req = (struct ablkcipher_request *)data;
+	ta_ctx = ablkcipher_request_ctx(req);
+	tfm = crypto_ablkcipher_reqtfm(req);
+	sctx = crypto_ablkcipher_ctx(tfm);
+
+	ta_ctx->are_we_done_yet = &are_we_done_yet;
+
+	pr_debug("sep_crypto_block\n");
+	pr_debug("tfm is %p sctx is %p ta_ctx is %p\n",
+		tfm, sctx, ta_ctx);
+	pr_debug("key_sent is %d\n", sctx->key_sent);
+
+	/* do we need to send the key */
+	if (sctx->key_sent == 0) {
+		are_we_done_yet = 0;
+		result = sep_crypto_send_key(req); /* prep to send key */
+		if (result != 0) {
+			dev_dbg(&ta_ctx->sep_used->pdev->dev,
+				"could not prep key %x\n", result);
+			sep_crypto_release(sctx, ta_ctx, result);
+			return;
+		}
+
+		result = sep_crypto_take_sep(ta_ctx);
+		if (result) {
+			dev_warn(&ta_ctx->sep_used->pdev->dev,
+				"sep_crypto_take_sep for key send failed\n");
+			sep_crypto_release(sctx, ta_ctx, result);
+			return;
+		}
+
+		/* now we sit and wait up to a fixed time for completion */
+		end_time = jiffies + (WAIT_TIME * HZ);
+		while ((time_before(jiffies, end_time)) &&
+			(are_we_done_yet == 0))
+			schedule();
+
+		/* Done waiting; still not done yet? */
+		if (are_we_done_yet == 0) {
+			dev_dbg(&ta_ctx->sep_used->pdev->dev,
+				"Send key job never got done\n");
+			sep_crypto_release(sctx, ta_ctx, -EINVAL);
+			return;
+		}
+
+		/* Set the key sent variable so this can be skipped later */
+		sctx->key_sent = 1;
+	}
+
+	/* Key sent (or maybe not if we did not have to), now send block */
+	are_we_done_yet = 0;
+
+	result = sep_crypto_block_data(req);
+
+	if (result != 0) {
+		dev_dbg(&ta_ctx->sep_used->pdev->dev,
+			"could prep not send block %x\n", result);
+		sep_crypto_release(sctx, ta_ctx, result);
+		return;
+	}
+
+	result = sep_crypto_take_sep(ta_ctx);
+	if (result) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev,
+			"sep_crypto_take_sep for block send failed\n");
+		sep_crypto_release(sctx, ta_ctx, result);
+		return;
+	}
+
+	/* now we sit and wait up to a fixed time for completion */
+	end_time = jiffies + (WAIT_TIME * HZ);
+	while ((time_before(jiffies, end_time)) && (are_we_done_yet == 0))
+		schedule();
+
+	/* Done waiting; still not done yet? */
+	if (are_we_done_yet == 0) {
+		dev_dbg(&ta_ctx->sep_used->pdev->dev,
+			"Send block job never got done\n");
+		sep_crypto_release(sctx, ta_ctx, -EINVAL);
+		return;
+	}
+
+	/* That's it; entire thing done, get out of queue */
+
+	pr_debug("crypto_block leaving\n");
+	pr_debug("tfm is %p sctx is %p ta_ctx is %p\n", tfm, sctx, ta_ctx);
+}
+
+/**
+ * Post operation (after interrupt) for crypto block
+ */
+static u32 crypto_post_op(struct sep_device *sep)
+{
+	/* HERE */
+	u32 u32_error;
+	u32 msg_offset;
+
+	ssize_t copy_result;
+	static char small_buf[100];
+
+	struct ablkcipher_request *req;
+	struct this_task_ctx *ta_ctx;
+	struct sep_system_ctx *sctx;
+	struct crypto_ablkcipher *tfm;
+
+	struct sep_des_internal_context *des_internal;
+	struct sep_aes_internal_context *aes_internal;
+
+	if (!sep->current_cypher_req)
+		return -EINVAL;
+
+	/* hold req since we need to submit work after clearing sep */
+	req = sep->current_cypher_req;
+
+	ta_ctx = ablkcipher_request_ctx(sep->current_cypher_req);
+	tfm = crypto_ablkcipher_reqtfm(sep->current_cypher_req);
+	sctx = crypto_ablkcipher_ctx(tfm);
+
+	pr_debug("crypto_post op\n");
+	pr_debug("key_sent is %d tfm is %p sctx is %p ta_ctx is %p\n",
+		sctx->key_sent, tfm, sctx, ta_ctx);
+
+	dev_dbg(&ta_ctx->sep_used->pdev->dev, "crypto post_op\n");
+	dev_dbg(&ta_ctx->sep_used->pdev->dev, "crypto post_op message dump\n");
+	crypto_sep_dump_message(ta_ctx->sep_used, ta_ctx->msg);
+
+	/* first bring msg from shared area to local area */
+	memcpy(ta_ctx->msg, sep->shared_addr,
+		SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES);
+
+	/* Is this the result of performing init (key to SEP */
+	if (sctx->key_sent == 0) {
+
+		/* Did SEP do it okay */
+		u32_error = sep_verify_op(ta_ctx, ta_ctx->init_opcode,
+			&msg_offset);
+		if (u32_error) {
+			dev_warn(&ta_ctx->sep_used->pdev->dev,
+				"aes init error %x\n", u32_error);
+			sep_crypto_release(sctx, ta_ctx, u32_error);
+			return u32_error;
+			}
+
+		/* Read Context */
+		if (ta_ctx->init_opcode == SEP_DES_INIT_OPCODE) {
+			sep_read_context(ta_ctx, &msg_offset,
+			&sctx->des_private_ctx,
+			sizeof(struct sep_des_private_context));
+
+			sep_dump(ta_ctx->sep_used, "ctx init des",
+				&sctx->des_private_ctx, 40);
+		} else {
+			sep_read_context(ta_ctx, &msg_offset,
+			&sctx->aes_private_ctx,
+			sizeof(struct sep_aes_private_context));
+
+			sep_dump(ta_ctx->sep_used, "ctx init aes",
+				&sctx->aes_private_ctx, 20);
+		}
+
+		sep_dump_ivs(req, "after sending key to sep\n");
+
+		/* key sent went okay; release sep, and set are_we_done_yet */
+		sctx->key_sent = 1;
+		sep_crypto_release(sctx, ta_ctx, -EINPROGRESS);
+
+	} else {
+
+		/**
+		 * This is the result of a block request
+		 */
+		dev_dbg(&ta_ctx->sep_used->pdev->dev,
+			"crypto_post_op block response\n");
+
+		u32_error = sep_verify_op(ta_ctx, ta_ctx->block_opcode,
+			&msg_offset);
+
+		if (u32_error) {
+			dev_warn(&ta_ctx->sep_used->pdev->dev,
+				"sep block error %x\n", u32_error);
+			sep_crypto_release(sctx, ta_ctx, u32_error);
+			return -EINVAL;
+			}
+
+		if (ta_ctx->block_opcode == SEP_DES_BLOCK_OPCODE) {
+
+			dev_dbg(&ta_ctx->sep_used->pdev->dev,
+				"post op for DES\n");
+
+			/* special case for 1 block des */
+			if (sep->current_cypher_req->nbytes ==
+				crypto_ablkcipher_blocksize(tfm)) {
+
+				sep_read_msg(ta_ctx, small_buf,
+					crypto_ablkcipher_blocksize(tfm),
+					crypto_ablkcipher_blocksize(tfm) * 2,
+					&msg_offset, 1);
+
+				dev_dbg(&ta_ctx->sep_used->pdev->dev,
+					"reading in block des\n");
+
+				copy_result = sg_copy_from_buffer(
+					ta_ctx->dst_sg,
+					sep_sg_nents(ta_ctx->dst_sg),
+					small_buf,
+					crypto_ablkcipher_blocksize(tfm));
+
+				if (copy_result !=
+					crypto_ablkcipher_blocksize(tfm)) {
+
+					dev_warn(&ta_ctx->sep_used->pdev->dev,
+						"des block copy faild\n");
+					sep_crypto_release(sctx, ta_ctx,
+						-ENOMEM);
+					return -ENOMEM;
+				}
+			}
+
+			/* Read Context */
+			sep_read_context(ta_ctx, &msg_offset,
+				&sctx->des_private_ctx,
+				sizeof(struct sep_des_private_context));
+		} else {
+
+			dev_dbg(&ta_ctx->sep_used->pdev->dev,
+				"post op for AES\n");
+
+			/* Skip the MAC Output */
+			msg_offset += (sizeof(u32) * 4);
+
+			/* Read Context */
+			sep_read_context(ta_ctx, &msg_offset,
+				&sctx->aes_private_ctx,
+				sizeof(struct sep_aes_private_context));
+		}
+
+		sep_dump_sg(ta_ctx->sep_used,
+			"block sg out", ta_ctx->dst_sg);
+
+		/* Copy to correct sg if this block had oddball pages */
+		if (ta_ctx->dst_sg_hold)
+			sep_copy_sg(ta_ctx->sep_used,
+				ta_ctx->dst_sg,
+				ta_ctx->current_cypher_req->dst,
+				ta_ctx->current_cypher_req->nbytes);
+
+		/**
+		 * Copy the iv's back to the walk.iv
+		 * This is required for dm_crypt
+		 */
+		sep_dump_ivs(req, "got data block from sep\n");
+		if ((ta_ctx->current_request == DES_CBC) &&
+			(ta_ctx->des_opmode == SEP_DES_CBC)) {
+
+			dev_dbg(&ta_ctx->sep_used->pdev->dev,
+				"returning result iv to walk on DES\n");
+			des_internal = (struct sep_des_internal_context *)
+				sctx->des_private_ctx.ctx_buf;
+			memcpy(ta_ctx->walk.iv,
+				(void *)des_internal->iv_context,
+				crypto_ablkcipher_ivsize(tfm));
+		} else if ((ta_ctx->current_request == AES_CBC) &&
+			(ta_ctx->aes_opmode == SEP_AES_CBC)) {
+
+			dev_dbg(&ta_ctx->sep_used->pdev->dev,
+				"returning result iv to walk on AES\n");
+			aes_internal = (struct sep_aes_internal_context *)
+				sctx->aes_private_ctx.cbuff;
+			memcpy(ta_ctx->walk.iv,
+				(void *)aes_internal->aes_ctx_iv,
+				crypto_ablkcipher_ivsize(tfm));
+		}
+
+		/* finished, release everything */
+		sep_crypto_release(sctx, ta_ctx, 0);
+	}
+	pr_debug("crypto_post_op done\n");
+	pr_debug("key_sent is %d tfm is %p sctx is %p ta_ctx is %p\n",
+		sctx->key_sent, tfm, sctx, ta_ctx);
+
+	return 0;
+}
+
+static u32 hash_init_post_op(struct sep_device *sep)
+{
+	u32 u32_error;
+	u32 msg_offset;
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(sep->current_hash_req);
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(sep->current_hash_req);
+	struct sep_system_ctx *sctx = crypto_ahash_ctx(tfm);
+	dev_dbg(&ta_ctx->sep_used->pdev->dev,
+		"hash init post op\n");
+
+	/* first bring msg from shared area to local area */
+	memcpy(ta_ctx->msg, sep->shared_addr,
+		SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES);
+
+	u32_error = sep_verify_op(ta_ctx, SEP_HASH_INIT_OPCODE,
+		&msg_offset);
+
+	if (u32_error) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev, "hash init error %x\n",
+			u32_error);
+		sep_crypto_release(sctx, ta_ctx, u32_error);
+		return u32_error;
+		}
+
+	/* Read Context */
+	sep_read_context(ta_ctx, &msg_offset,
+		&sctx->hash_private_ctx,
+		sizeof(struct sep_hash_private_context));
+
+	/* Signal to crypto infrastructure and clear out */
+	dev_dbg(&ta_ctx->sep_used->pdev->dev, "hash init post op done\n");
+	sep_crypto_release(sctx, ta_ctx, 0);
+	return 0;
+}
+
+static u32 hash_update_post_op(struct sep_device *sep)
+{
+	u32 u32_error;
+	u32 msg_offset;
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(sep->current_hash_req);
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(sep->current_hash_req);
+	struct sep_system_ctx *sctx = crypto_ahash_ctx(tfm);
+	dev_dbg(&ta_ctx->sep_used->pdev->dev,
+		"hash update post op\n");
+
+	/* first bring msg from shared area to local area */
+	memcpy(ta_ctx->msg, sep->shared_addr,
+		SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES);
+
+	u32_error = sep_verify_op(ta_ctx, SEP_HASH_UPDATE_OPCODE,
+		&msg_offset);
+
+	if (u32_error) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev, "hash init error %x\n",
+			u32_error);
+		sep_crypto_release(sctx, ta_ctx, u32_error);
+		return u32_error;
+		}
+
+	/* Read Context */
+	sep_read_context(ta_ctx, &msg_offset,
+		&sctx->hash_private_ctx,
+		sizeof(struct sep_hash_private_context));
+
+	/**
+	 * Following is only for finup; if we just completd the
+	 * data portion of finup, we now need to kick off the
+	 * finish portion of finup.
+	 */
+
+	if (ta_ctx->sep_used->current_hash_stage == HASH_FINUP_DATA) {
+
+		/* first reset stage to HASH_FINUP_FINISH */
+		ta_ctx->sep_used->current_hash_stage = HASH_FINUP_FINISH;
+
+		/* now enqueue the finish operation */
+		spin_lock_irq(&queue_lock);
+		u32_error = crypto_enqueue_request(&sep_queue,
+			&ta_ctx->sep_used->current_hash_req->base);
+		spin_unlock_irq(&queue_lock);
+
+		if ((u32_error != 0) && (u32_error != -EINPROGRESS)) {
+			dev_warn(&ta_ctx->sep_used->pdev->dev,
+				"spe cypher post op cant queue\n");
+			sep_crypto_release(sctx, ta_ctx, u32_error);
+			return u32_error;
+		}
+
+		/* schedule the data send */
+		u32_error = sep_submit_work(ta_ctx->sep_used->workqueue,
+			sep_dequeuer, (void *)&sep_queue);
+
+		if (u32_error) {
+			dev_warn(&ta_ctx->sep_used->pdev->dev,
+				"cant submit work sep_crypto_block\n");
+			sep_crypto_release(sctx, ta_ctx, -EINVAL);
+			return -EINVAL;
+		}
+	}
+
+	/* Signal to crypto infrastructure and clear out */
+	dev_dbg(&ta_ctx->sep_used->pdev->dev, "hash update post op done\n");
+	sep_crypto_release(sctx, ta_ctx, 0);
+	return 0;
+}
+
+static u32 hash_final_post_op(struct sep_device *sep)
+{
+	int max_length;
+	u32 u32_error;
+	u32 msg_offset;
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(sep->current_hash_req);
+	struct sep_system_ctx *sctx = crypto_ahash_ctx(tfm);
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(sep->current_hash_req);
+	dev_dbg(&ta_ctx->sep_used->pdev->dev,
+		"hash final post op\n");
+
+	/* first bring msg from shared area to local area */
+	memcpy(ta_ctx->msg, sep->shared_addr,
+		SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES);
+
+	u32_error = sep_verify_op(ta_ctx, SEP_HASH_FINISH_OPCODE,
+		&msg_offset);
+
+	if (u32_error) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev, "hash finish error %x\n",
+			u32_error);
+		sep_crypto_release(sctx, ta_ctx, u32_error);
+		return u32_error;
+		}
+
+	/* Grab the result */
+	if (ta_ctx->current_hash_req->result == NULL) {
+		/* Oops, null buffer; error out here */
+		dev_warn(&ta_ctx->sep_used->pdev->dev,
+			"hash finish null buffer\n");
+		sep_crypto_release(sctx, ta_ctx, (u32)-ENOMEM);
+		return -ENOMEM;
+		}
+
+	max_length = (((SEP_HASH_RESULT_SIZE_WORDS * sizeof(u32)) + 3) /
+		sizeof(u32)) * sizeof(u32);
+
+	sep_read_msg(ta_ctx,
+		ta_ctx->current_hash_req->result,
+		crypto_ahash_digestsize(tfm), max_length,
+		&msg_offset, 0);
+
+	/* Signal to crypto infrastructure and clear out */
+	dev_dbg(&ta_ctx->sep_used->pdev->dev, "hash finish post op done\n");
+	sep_crypto_release(sctx, ta_ctx, 0);
+	return 0;
+}
+
+static u32 hash_digest_post_op(struct sep_device *sep)
+{
+	int max_length;
+	u32 u32_error;
+	u32 msg_offset;
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(sep->current_hash_req);
+	struct sep_system_ctx *sctx = crypto_ahash_ctx(tfm);
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(sep->current_hash_req);
+	dev_dbg(&ta_ctx->sep_used->pdev->dev,
+		"hash digest post op\n");
+
+	/* first bring msg from shared area to local area */
+	memcpy(ta_ctx->msg, sep->shared_addr,
+		SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES);
+
+	u32_error = sep_verify_op(ta_ctx, SEP_HASH_SINGLE_OPCODE,
+		&msg_offset);
+
+	if (u32_error) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev,
+			"hash digest finish error %x\n", u32_error);
+
+		sep_crypto_release(sctx, ta_ctx, u32_error);
+		return u32_error;
+		}
+
+	/* Grab the result */
+	if (ta_ctx->current_hash_req->result == NULL) {
+		/* Oops, null buffer; error out here */
+		dev_warn(&ta_ctx->sep_used->pdev->dev,
+			"hash digest finish null buffer\n");
+		sep_crypto_release(sctx, ta_ctx, (u32)-ENOMEM);
+		return -ENOMEM;
+		}
+
+	max_length = (((SEP_HASH_RESULT_SIZE_WORDS * sizeof(u32)) + 3) /
+		sizeof(u32)) * sizeof(u32);
+
+	sep_read_msg(ta_ctx,
+		ta_ctx->current_hash_req->result,
+		crypto_ahash_digestsize(tfm), max_length,
+		&msg_offset, 0);
+
+	/* Signal to crypto infrastructure and clear out */
+	dev_dbg(&ta_ctx->sep_used->pdev->dev,
+		"hash digest finish post op done\n");
+
+	sep_crypto_release(sctx, ta_ctx, 0);
+	return 0;
+}
+
+/**
+ * The sep_finish function is the function that is schedule (via tasket)
+ * by the interrupt service routine when the SEP sends and interrupt
+ * This is only called by the interrupt handler as a tasklet.
+ */
+static void sep_finish(unsigned long data)
+{
+	struct sep_device *sep_dev;
+	int res;
+
+	res = 0;
+
+	if (data == 0) {
+		pr_debug("sep_finish called with null data\n");
+		return;
+	}
+
+	sep_dev = (struct sep_device *)data;
+	if (sep_dev == NULL) {
+		pr_debug("sep_finish; sep_dev is NULL\n");
+		return;
+	}
+
+	if (sep_dev->in_kernel == (u32)0) {
+		dev_warn(&sep_dev->pdev->dev,
+			"sep_finish; not in kernel operation\n");
+		return;
+	}
+
+	/* Did we really do a sep command prior to this? */
+	if (0 == test_bit(SEP_LEGACY_SENDMSG_DONE_OFFSET,
+		&sep_dev->ta_ctx->call_status.status)) {
+
+		dev_warn(&sep_dev->pdev->dev, "[PID%d] sendmsg not called\n",
+			current->pid);
+		return;
+	}
+
+	if (sep_dev->send_ct != sep_dev->reply_ct) {
+		dev_warn(&sep_dev->pdev->dev,
+			"[PID%d] poll; no message came back\n",
+			current->pid);
+		return;
+	}
+
+	/* Check for error (In case time ran out) */
+	if ((res != 0x0) && (res != 0x8)) {
+		dev_warn(&sep_dev->pdev->dev,
+			"[PID%d] poll; poll error GPR3 is %x\n",
+			current->pid, res);
+		return;
+	}
+
+	/* What kind of interrupt from sep was this? */
+	res = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
+
+	dev_dbg(&sep_dev->pdev->dev, "[PID%d] GPR2 at crypto finish is %x\n",
+		current->pid, res);
+
+	/* Print request? */
+	if ((res >> 30) & 0x1) {
+		dev_dbg(&sep_dev->pdev->dev, "[PID%d] sep print req\n",
+			current->pid);
+		dev_dbg(&sep_dev->pdev->dev, "[PID%d] contents: %s\n",
+			current->pid,
+			(char *)(sep_dev->shared_addr +
+			SEP_DRIVER_PRINTF_OFFSET_IN_BYTES));
+		return;
+	}
+
+	/* Request for daemon (not currently in POR)? */
+	if (res >> 31) {
+		dev_dbg(&sep_dev->pdev->dev,
+			"[PID%d] sep request; ignoring\n",
+			current->pid);
+		return;
+	}
+
+	/* If we got here, then we have a replay to a sep command */
+
+	dev_dbg(&sep_dev->pdev->dev,
+		"[PID%d] sep reply to command; processing request: %x\n",
+		current->pid, sep_dev->current_request);
+
+	switch (sep_dev->current_request) {
+	case AES_CBC:
+	case AES_ECB:
+	case DES_CBC:
+	case DES_ECB:
+		res = crypto_post_op(sep_dev);
+		break;
+	case SHA1:
+	case MD5:
+	case SHA224:
+	case SHA256:
+		switch (sep_dev->current_hash_stage) {
+		case HASH_INIT:
+			res = hash_init_post_op(sep_dev);
+			break;
+		case HASH_UPDATE:
+		case HASH_FINUP_DATA:
+			res = hash_update_post_op(sep_dev);
+			break;
+		case HASH_FINUP_FINISH:
+		case HASH_FINISH:
+			res = hash_final_post_op(sep_dev);
+			break;
+		case HASH_DIGEST:
+			res = hash_digest_post_op(sep_dev);
+			break;
+		default:
+			pr_debug("sep - invalid stage for hash finish\n");
+		}
+		break;
+	default:
+		pr_debug("sep - invalid request for finish\n");
+	}
+
+	if (res)
+		pr_debug("sep - finish returned error %x\n", res);
+}
+
+static int sep_hash_cra_init(struct crypto_tfm *tfm)
+	{
+	const char *alg_name = crypto_tfm_alg_name(tfm);
+
+	pr_debug("sep_hash_cra_init name is %s\n", alg_name);
+
+	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+		sizeof(struct this_task_ctx));
+	return 0;
+	}
+
+static void sep_hash_cra_exit(struct crypto_tfm *tfm)
+{
+	pr_debug("sep_hash_cra_exit\n");
+}
+
+static void sep_hash_init(void *data)
+{
+	u32 msg_offset;
+	int result;
+	struct ahash_request *req;
+	struct crypto_ahash *tfm;
+	struct this_task_ctx *ta_ctx;
+	struct sep_system_ctx *sctx;
+	unsigned long end_time;
+	int are_we_done_yet;
+
+	req = (struct ahash_request *)data;
+	tfm = crypto_ahash_reqtfm(req);
+	sctx = crypto_ahash_ctx(tfm);
+	ta_ctx = ahash_request_ctx(req);
+	ta_ctx->sep_used = sep_dev;
+
+	ta_ctx->are_we_done_yet = &are_we_done_yet;
+
+	dev_dbg(&ta_ctx->sep_used->pdev->dev,
+		"sep_hash_init\n");
+	ta_ctx->current_hash_stage = HASH_INIT;
+	/* opcode and mode */
+	sep_make_header(ta_ctx, &msg_offset, SEP_HASH_INIT_OPCODE);
+	sep_write_msg(ta_ctx, &ta_ctx->hash_opmode,
+		sizeof(u32), sizeof(u32), &msg_offset, 0);
+	sep_end_msg(ta_ctx, msg_offset);
+
+	are_we_done_yet = 0;
+	result = sep_crypto_take_sep(ta_ctx);
+	if (result) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev,
+			"sep_hash_init take sep failed\n");
+		sep_crypto_release(sctx, ta_ctx, -EINVAL);
+	}
+
+	/* now we sit and wait up to a fixed time for completion */
+	end_time = jiffies + (WAIT_TIME * HZ);
+	while ((time_before(jiffies, end_time)) && (are_we_done_yet == 0))
+		schedule();
+
+	/* Done waiting; still not done yet? */
+	if (are_we_done_yet == 0) {
+		dev_dbg(&ta_ctx->sep_used->pdev->dev,
+			"hash init never got done\n");
+		sep_crypto_release(sctx, ta_ctx, -EINVAL);
+		return;
+	}
+
+}
+
+static void sep_hash_update(void *data)
+{
+	int int_error;
+	u32 msg_offset;
+	u32 len;
+	struct sep_hash_internal_context *int_ctx;
+	u32 block_size;
+	u32 head_len;
+	u32 tail_len;
+	int are_we_done_yet;
+
+	static u32 msg[10];
+	static char small_buf[100];
+	void *src_ptr;
+	struct scatterlist *new_sg;
+	ssize_t copy_result;
+	struct ahash_request *req;
+	struct crypto_ahash *tfm;
+	struct this_task_ctx *ta_ctx;
+	struct sep_system_ctx *sctx;
+	unsigned long end_time;
+
+	req = (struct ahash_request *)data;
+	tfm = crypto_ahash_reqtfm(req);
+	sctx = crypto_ahash_ctx(tfm);
+	ta_ctx = ahash_request_ctx(req);
+	ta_ctx->sep_used = sep_dev;
+
+	ta_ctx->are_we_done_yet = &are_we_done_yet;
+
+	/* length for queue status */
+	ta_ctx->nbytes = req->nbytes;
+
+	dev_dbg(&ta_ctx->sep_used->pdev->dev,
+		"sep_hash_update\n");
+	ta_ctx->current_hash_stage = HASH_UPDATE;
+	len = req->nbytes;
+
+	block_size = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
+	tail_len = req->nbytes % block_size;
+	dev_dbg(&ta_ctx->sep_used->pdev->dev, "length is %x\n", len);
+	dev_dbg(&ta_ctx->sep_used->pdev->dev, "block_size is %x\n", block_size);
+	dev_dbg(&ta_ctx->sep_used->pdev->dev, "tail len is %x\n", tail_len);
+
+	/* Compute header/tail sizes */
+	int_ctx = (struct sep_hash_internal_context *)&sctx->
+		hash_private_ctx.internal_context;
+	head_len = (block_size - int_ctx->prev_update_bytes) % block_size;
+	tail_len = (req->nbytes - head_len) % block_size;
+
+	/* Make sure all pages are even block */
+	int_error = sep_oddball_pages(ta_ctx->sep_used, req->src,
+		req->nbytes,
+		block_size, &new_sg, 1);
+
+	if (int_error < 0) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev,
+			"oddball pages error in crash update\n");
+		sep_crypto_release(sctx, ta_ctx, -ENOMEM);
+		return;
+	} else if (int_error == 1) {
+		ta_ctx->src_sg = new_sg;
+		ta_ctx->src_sg_hold = new_sg;
+	} else {
+		ta_ctx->src_sg = req->src;
+		ta_ctx->src_sg_hold = NULL;
+	}
+
+	src_ptr = sg_virt(ta_ctx->src_sg);
+
+	if ((!req->nbytes) || (!ta_ctx->src_sg)) {
+		/* null data */
+		src_ptr = NULL;
+	}
+
+	sep_dump_sg(ta_ctx->sep_used, "hash block sg in", ta_ctx->src_sg);
+
+	ta_ctx->dcb_input_data.app_in_address = src_ptr;
+	ta_ctx->dcb_input_data.data_in_size =
+		req->nbytes - (head_len + tail_len);
+	ta_ctx->dcb_input_data.app_out_address = NULL;
+	ta_ctx->dcb_input_data.block_size = block_size;
+	ta_ctx->dcb_input_data.tail_block_size = 0;
+	ta_ctx->dcb_input_data.is_applet = 0;
+	ta_ctx->dcb_input_data.src_sg = ta_ctx->src_sg;
+	ta_ctx->dcb_input_data.dst_sg = NULL;
+
+	int_error = sep_create_dcb_dmatables_context_kernel(
+		ta_ctx->sep_used,
+		&ta_ctx->dcb_region,
+		&ta_ctx->dmatables_region,
+		&ta_ctx->dma_ctx,
+		&ta_ctx->dcb_input_data,
+		1);
+	if (int_error) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev,
+			"hash update dma table create failed\n");
+		sep_crypto_release(sctx, ta_ctx, -EINVAL);
+		return;
+	}
+
+	/* Construct message to SEP */
+	sep_make_header(ta_ctx, &msg_offset, SEP_HASH_UPDATE_OPCODE);
+
+	msg[0] = (u32)0;
+	msg[1] = (u32)0;
+	msg[2] = (u32)0;
+
+	sep_write_msg(ta_ctx, msg, sizeof(u32) * 3, sizeof(u32) * 3,
+		&msg_offset, 0);
+
+	/* Handle remainders */
+
+	/* Head */
+	sep_write_msg(ta_ctx, &head_len, sizeof(u32),
+		sizeof(u32), &msg_offset, 0);
+
+	if (head_len) {
+		copy_result = sg_copy_to_buffer(
+			req->src,
+			sep_sg_nents(ta_ctx->src_sg),
+			small_buf, head_len);
+
+		if (copy_result != head_len) {
+			dev_warn(&ta_ctx->sep_used->pdev->dev,
+				"sg head copy failure in hash block\n");
+			sep_crypto_release(sctx, ta_ctx, -ENOMEM);
+			return;
+		}
+
+		sep_write_msg(ta_ctx, small_buf, head_len,
+			sizeof(u32) * 32, &msg_offset, 1);
+	} else {
+		msg_offset += sizeof(u32) * 32;
+	}
+
+	/* Tail */
+	sep_write_msg(ta_ctx, &tail_len, sizeof(u32),
+		sizeof(u32), &msg_offset, 0);
+
+	if (tail_len) {
+		copy_result = sep_copy_offset_sg(
+			ta_ctx->sep_used,
+			ta_ctx->src_sg,
+			req->nbytes - tail_len,
+			small_buf, tail_len);
+
+		if (copy_result != tail_len) {
+			dev_warn(&ta_ctx->sep_used->pdev->dev,
+				"sg tail copy failure in hash block\n");
+			sep_crypto_release(sctx, ta_ctx, -ENOMEM);
+			return;
+		}
+
+		sep_write_msg(ta_ctx, small_buf, tail_len,
+			sizeof(u32) * 32, &msg_offset, 1);
+	} else {
+		msg_offset += sizeof(u32) * 32;
+	}
+
+	/* Context */
+	sep_write_context(ta_ctx, &msg_offset, &sctx->hash_private_ctx,
+		sizeof(struct sep_hash_private_context));
+
+	sep_end_msg(ta_ctx, msg_offset);
+	are_we_done_yet = 0;
+	int_error = sep_crypto_take_sep(ta_ctx);
+	if (int_error) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev,
+			"sep_hash_update take sep failed\n");
+		sep_crypto_release(sctx, ta_ctx, -EINVAL);
+	}
+
+	/* now we sit and wait up to a fixed time for completion */
+	end_time = jiffies + (WAIT_TIME * HZ);
+	while ((time_before(jiffies, end_time)) && (are_we_done_yet == 0))
+		schedule();
+
+	/* Done waiting; still not done yet? */
+	if (are_we_done_yet == 0) {
+		dev_dbg(&ta_ctx->sep_used->pdev->dev,
+			"hash update never got done\n");
+		sep_crypto_release(sctx, ta_ctx, -EINVAL);
+		return;
+	}
+
+}
+
+static void sep_hash_final(void *data)
+{
+	u32 msg_offset;
+	struct ahash_request *req;
+	struct crypto_ahash *tfm;
+	struct this_task_ctx *ta_ctx;
+	struct sep_system_ctx *sctx;
+	int result;
+	unsigned long end_time;
+	int are_we_done_yet;
+
+	req = (struct ahash_request *)data;
+	tfm = crypto_ahash_reqtfm(req);
+	sctx = crypto_ahash_ctx(tfm);
+	ta_ctx = ahash_request_ctx(req);
+	ta_ctx->sep_used = sep_dev;
+
+	dev_dbg(&ta_ctx->sep_used->pdev->dev,
+		"sep_hash_final\n");
+	ta_ctx->current_hash_stage = HASH_FINISH;
+
+	ta_ctx->are_we_done_yet = &are_we_done_yet;
+
+	/* opcode and mode */
+	sep_make_header(ta_ctx, &msg_offset, SEP_HASH_FINISH_OPCODE);
+
+	/* Context */
+	sep_write_context(ta_ctx, &msg_offset, &sctx->hash_private_ctx,
+		sizeof(struct sep_hash_private_context));
+
+	sep_end_msg(ta_ctx, msg_offset);
+	are_we_done_yet = 0;
+	result = sep_crypto_take_sep(ta_ctx);
+	if (result) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev,
+			"sep_hash_final take sep failed\n");
+		sep_crypto_release(sctx, ta_ctx, -EINVAL);
+	}
+
+	/* now we sit and wait up to a fixed time for completion */
+	end_time = jiffies + (WAIT_TIME * HZ);
+	while ((time_before(jiffies, end_time)) && (are_we_done_yet == 0))
+		schedule();
+
+	/* Done waiting; still not done yet? */
+	if (are_we_done_yet == 0) {
+		dev_dbg(&ta_ctx->sep_used->pdev->dev,
+			"hash final job never got done\n");
+		sep_crypto_release(sctx, ta_ctx, -EINVAL);
+		return;
+	}
+
+}
+
+static void sep_hash_digest(void *data)
+{
+	int int_error;
+	u32 msg_offset;
+	u32 block_size;
+	u32 msg[10];
+	size_t copy_result;
+	int result;
+	int are_we_done_yet;
+	u32 tail_len;
+	static char small_buf[100];
+	struct scatterlist *new_sg;
+	void *src_ptr;
+
+	struct ahash_request *req;
+	struct crypto_ahash *tfm;
+	struct this_task_ctx *ta_ctx;
+	struct sep_system_ctx *sctx;
+	unsigned long end_time;
+
+	req = (struct ahash_request *)data;
+	tfm = crypto_ahash_reqtfm(req);
+	sctx = crypto_ahash_ctx(tfm);
+	ta_ctx = ahash_request_ctx(req);
+	ta_ctx->sep_used = sep_dev;
+
+	dev_dbg(&ta_ctx->sep_used->pdev->dev,
+		"sep_hash_digest\n");
+	ta_ctx->current_hash_stage = HASH_DIGEST;
+
+	ta_ctx->are_we_done_yet = &are_we_done_yet;
+
+	/* length for queue status */
+	ta_ctx->nbytes = req->nbytes;
+
+	block_size = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
+	tail_len = req->nbytes % block_size;
+	dev_dbg(&ta_ctx->sep_used->pdev->dev, "length is %x\n", req->nbytes);
+	dev_dbg(&ta_ctx->sep_used->pdev->dev, "block_size is %x\n", block_size);
+	dev_dbg(&ta_ctx->sep_used->pdev->dev, "tail len is %x\n", tail_len);
+
+	/* Make sure all pages are even block */
+	int_error = sep_oddball_pages(ta_ctx->sep_used, req->src,
+		req->nbytes,
+		block_size, &new_sg, 1);
+
+	if (int_error < 0) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev,
+			"oddball pages error in crash update\n");
+		sep_crypto_release(sctx, ta_ctx, -ENOMEM);
+		return;
+	} else if (int_error == 1) {
+		ta_ctx->src_sg = new_sg;
+		ta_ctx->src_sg_hold = new_sg;
+	} else {
+		ta_ctx->src_sg = req->src;
+		ta_ctx->src_sg_hold = NULL;
+	}
+
+	src_ptr = sg_virt(ta_ctx->src_sg);
+
+	if ((!req->nbytes) || (!ta_ctx->src_sg)) {
+		/* null data */
+		src_ptr = NULL;
+	}
+
+	sep_dump_sg(ta_ctx->sep_used, "hash block sg in", ta_ctx->src_sg);
+
+	ta_ctx->dcb_input_data.app_in_address = src_ptr;
+	ta_ctx->dcb_input_data.data_in_size = req->nbytes - tail_len;
+	ta_ctx->dcb_input_data.app_out_address = NULL;
+	ta_ctx->dcb_input_data.block_size = block_size;
+	ta_ctx->dcb_input_data.tail_block_size = 0;
+	ta_ctx->dcb_input_data.is_applet = 0;
+	ta_ctx->dcb_input_data.src_sg = ta_ctx->src_sg;
+	ta_ctx->dcb_input_data.dst_sg = NULL;
+
+	int_error = sep_create_dcb_dmatables_context_kernel(
+		ta_ctx->sep_used,
+		&ta_ctx->dcb_region,
+		&ta_ctx->dmatables_region,
+		&ta_ctx->dma_ctx,
+		&ta_ctx->dcb_input_data,
+		1);
+	if (int_error) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev,
+			"hash update dma table create failed\n");
+		sep_crypto_release(sctx, ta_ctx, -EINVAL);
+		return;
+	}
+
+	/* Construct message to SEP */
+	sep_make_header(ta_ctx, &msg_offset, SEP_HASH_SINGLE_OPCODE);
+	sep_write_msg(ta_ctx, &ta_ctx->hash_opmode,
+		sizeof(u32), sizeof(u32), &msg_offset, 0);
+
+	msg[0] = (u32)0;
+	msg[1] = (u32)0;
+	msg[2] = (u32)0;
+
+	sep_write_msg(ta_ctx, msg, sizeof(u32) * 3, sizeof(u32) * 3,
+		&msg_offset, 0);
+
+	/* Tail */
+	sep_write_msg(ta_ctx, &tail_len, sizeof(u32),
+		sizeof(u32), &msg_offset, 0);
+
+	if (tail_len) {
+		copy_result = sep_copy_offset_sg(
+			ta_ctx->sep_used,
+			ta_ctx->src_sg,
+			req->nbytes - tail_len,
+			small_buf, tail_len);
+
+		if (copy_result != tail_len) {
+			dev_warn(&ta_ctx->sep_used->pdev->dev,
+				"sg tail copy failure in hash block\n");
+			sep_crypto_release(sctx, ta_ctx, -ENOMEM);
+			return;
+		}
+
+		sep_write_msg(ta_ctx, small_buf, tail_len,
+			sizeof(u32) * 32, &msg_offset, 1);
+	} else {
+		msg_offset += sizeof(u32) * 32;
+	}
+
+	sep_end_msg(ta_ctx, msg_offset);
+
+	are_we_done_yet = 0;
+	result = sep_crypto_take_sep(ta_ctx);
+	if (result) {
+		dev_warn(&ta_ctx->sep_used->pdev->dev,
+			"sep_hash_digest take sep failed\n");
+		sep_crypto_release(sctx, ta_ctx, -EINVAL);
+	}
+
+	/* now we sit and wait up to a fixed time for completion */
+	end_time = jiffies + (WAIT_TIME * HZ);
+	while ((time_before(jiffies, end_time)) && (are_we_done_yet == 0))
+		schedule();
+
+	/* Done waiting; still not done yet? */
+	if (are_we_done_yet == 0) {
+		dev_dbg(&ta_ctx->sep_used->pdev->dev,
+			"hash digest job never got done\n");
+		sep_crypto_release(sctx, ta_ctx, -EINVAL);
+		return;
+	}
+
+}
+
+/**
+ * This is what is called by each of the API's provided
+ * in the kernel crypto descriptors. It is run in a process
+ * context using the kernel workqueues. Therefore it can
+ * be put to sleep.
+ */
+static void sep_dequeuer(void *data)
+{
+	struct crypto_queue *this_queue;
+	struct crypto_async_request *async_req;
+	struct crypto_async_request *backlog;
+	struct ablkcipher_request *cypher_req;
+	struct ahash_request *hash_req;
+	struct sep_system_ctx *sctx;
+	struct crypto_ahash *hash_tfm;
+	struct this_task_ctx *ta_ctx;
+
+
+	this_queue = (struct crypto_queue *)data;
+
+	spin_lock_irq(&queue_lock);
+	backlog = crypto_get_backlog(this_queue);
+	async_req = crypto_dequeue_request(this_queue);
+	spin_unlock_irq(&queue_lock);
+
+	if (!async_req) {
+		pr_debug("sep crypto queue is empty\n");
+		return;
+	}
+
+	if (backlog) {
+		pr_debug("sep crypto backlog set\n");
+		if (backlog->complete)
+			backlog->complete(backlog, -EINPROGRESS);
+		backlog = NULL;
+	}
+
+	if (!async_req->tfm) {
+		pr_debug("sep crypto queue null tfm\n");
+		return;
+	}
+
+	if (!async_req->tfm->__crt_alg) {
+		pr_debug("sep crypto queue null __crt_alg\n");
+		return;
+	}
+
+	if (!async_req->tfm->__crt_alg->cra_type) {
+		pr_debug("sep crypto queue null cra_type\n");
+		return;
+	}
+
+	/* we have stuff in the queue */
+	if (async_req->tfm->__crt_alg->cra_type !=
+		&crypto_ahash_type) {
+		/* This is for a cypher */
+		pr_debug("sep crypto queue doing cipher\n");
+		cypher_req = container_of(async_req,
+			struct ablkcipher_request,
+			base);
+		if (!cypher_req) {
+			pr_debug("sep crypto queue null cypher_req\n");
+			return;
+		}
+
+		sep_crypto_block((void *)cypher_req);
+		return;
+	} else {
+		/* This is a hash */
+		pr_debug("sep crypto queue doing hash\n");
+		/**
+		 * This is a bit more complex than cipher; we
+		 * need to figure out what type of operation
+		 */
+		hash_req = ahash_request_cast(async_req);
+		if (!hash_req) {
+			pr_debug("sep crypto queue null hash_req\n");
+			return;
+		}
+
+		hash_tfm = crypto_ahash_reqtfm(hash_req);
+		if (!hash_tfm) {
+			pr_debug("sep crypto queue null hash_tfm\n");
+			return;
+		}
+
+
+		sctx = crypto_ahash_ctx(hash_tfm);
+		if (!sctx) {
+			pr_debug("sep crypto queue null sctx\n");
+			return;
+		}
+
+		ta_ctx = ahash_request_ctx(hash_req);
+
+		if (ta_ctx->current_hash_stage == HASH_INIT) {
+			pr_debug("sep crypto queue hash init\n");
+			sep_hash_init((void *)hash_req);
+			return;
+		} else if (ta_ctx->current_hash_stage == HASH_UPDATE) {
+			pr_debug("sep crypto queue hash update\n");
+			sep_hash_update((void *)hash_req);
+			return;
+		} else if (ta_ctx->current_hash_stage == HASH_FINISH) {
+			pr_debug("sep crypto queue hash final\n");
+			sep_hash_final((void *)hash_req);
+			return;
+		} else if (ta_ctx->current_hash_stage == HASH_DIGEST) {
+			pr_debug("sep crypto queue hash digest\n");
+			sep_hash_digest((void *)hash_req);
+			return;
+		} else if (ta_ctx->current_hash_stage == HASH_FINUP_DATA) {
+			pr_debug("sep crypto queue hash digest\n");
+			sep_hash_update((void *)hash_req);
+			return;
+		} else if (ta_ctx->current_hash_stage == HASH_FINUP_FINISH) {
+			pr_debug("sep crypto queue hash digest\n");
+			sep_hash_final((void *)hash_req);
+			return;
+		} else {
+			pr_debug("sep crypto queue hash oops nothing\n");
+			return;
+		}
+	}
+}
+
+static int sep_sha1_init(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+
+	pr_debug("sep - doing sha1 init\n");
+
+	/* Clear out task context */
+	memset(ta_ctx, 0, sizeof(struct this_task_ctx));
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = SHA1;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_SHA1;
+	ta_ctx->current_hash_stage = HASH_INIT;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_sha1_update(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+
+	pr_debug("sep - doing sha1 update\n");
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = SHA1;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_SHA1;
+	ta_ctx->current_hash_stage = HASH_UPDATE;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_sha1_final(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+	pr_debug("sep - doing sha1 final\n");
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = SHA1;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_SHA1;
+	ta_ctx->current_hash_stage = HASH_FINISH;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_sha1_digest(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+	pr_debug("sep - doing sha1 digest\n");
+
+	/* Clear out task context */
+	memset(ta_ctx, 0, sizeof(struct this_task_ctx));
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = SHA1;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_SHA1;
+	ta_ctx->current_hash_stage = HASH_DIGEST;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_sha1_finup(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+	pr_debug("sep - doing sha1 finup\n");
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = SHA1;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_SHA1;
+	ta_ctx->current_hash_stage = HASH_FINUP_DATA;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_md5_init(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+	pr_debug("sep - doing md5 init\n");
+
+	/* Clear out task context */
+	memset(ta_ctx, 0, sizeof(struct this_task_ctx));
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = MD5;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_MD5;
+	ta_ctx->current_hash_stage = HASH_INIT;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_md5_update(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+	pr_debug("sep - doing md5 update\n");
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = MD5;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_MD5;
+	ta_ctx->current_hash_stage = HASH_UPDATE;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_md5_final(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+	pr_debug("sep - doing md5 final\n");
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = MD5;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_MD5;
+	ta_ctx->current_hash_stage = HASH_FINISH;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_md5_digest(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+
+	pr_debug("sep - doing md5 digest\n");
+
+	/* Clear out task context */
+	memset(ta_ctx, 0, sizeof(struct this_task_ctx));
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = MD5;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_MD5;
+	ta_ctx->current_hash_stage = HASH_DIGEST;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_md5_finup(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+
+	pr_debug("sep - doing md5 finup\n");
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = MD5;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_MD5;
+	ta_ctx->current_hash_stage = HASH_FINUP_DATA;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_sha224_init(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+	pr_debug("sep - doing sha224 init\n");
+
+	/* Clear out task context */
+	memset(ta_ctx, 0, sizeof(struct this_task_ctx));
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = SHA224;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_SHA224;
+	ta_ctx->current_hash_stage = HASH_INIT;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_sha224_update(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+	pr_debug("sep - doing sha224 update\n");
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = SHA224;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_SHA224;
+	ta_ctx->current_hash_stage = HASH_UPDATE;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_sha224_final(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+	pr_debug("sep - doing sha224 final\n");
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = SHA224;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_SHA224;
+	ta_ctx->current_hash_stage = HASH_FINISH;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_sha224_digest(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+
+	pr_debug("sep - doing sha224 digest\n");
+
+	/* Clear out task context */
+	memset(ta_ctx, 0, sizeof(struct this_task_ctx));
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = SHA224;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_SHA224;
+	ta_ctx->current_hash_stage = HASH_DIGEST;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_sha224_finup(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+
+	pr_debug("sep - doing sha224 finup\n");
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = SHA224;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_SHA224;
+	ta_ctx->current_hash_stage = HASH_FINUP_DATA;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_sha256_init(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+	pr_debug("sep - doing sha256 init\n");
+
+	/* Clear out task context */
+	memset(ta_ctx, 0, sizeof(struct this_task_ctx));
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = SHA256;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_SHA256;
+	ta_ctx->current_hash_stage = HASH_INIT;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_sha256_update(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+	pr_debug("sep - doing sha256 update\n");
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = SHA256;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_SHA256;
+	ta_ctx->current_hash_stage = HASH_UPDATE;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_sha256_final(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+	pr_debug("sep - doing sha256 final\n");
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = SHA256;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_SHA256;
+	ta_ctx->current_hash_stage = HASH_FINISH;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_sha256_digest(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+
+	pr_debug("sep - doing sha256 digest\n");
+
+	/* Clear out task context */
+	memset(ta_ctx, 0, sizeof(struct this_task_ctx));
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = SHA256;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_SHA256;
+	ta_ctx->current_hash_stage = HASH_DIGEST;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_sha256_finup(struct ahash_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ahash_request_ctx(req);
+
+	pr_debug("sep - doing sha256 finup\n");
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = SHA256;
+	ta_ctx->current_hash_req = req;
+	ta_ctx->current_cypher_req = NULL;
+	ta_ctx->hash_opmode = SEP_HASH_SHA256;
+	ta_ctx->current_hash_stage = HASH_FINUP_DATA;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_crypto_init(struct crypto_tfm *tfm)
+{
+	const char *alg_name = crypto_tfm_alg_name(tfm);
+
+	if (alg_name == NULL)
+		pr_debug("sep_crypto_init alg is NULL\n");
+	else
+		pr_debug("sep_crypto_init alg is %s\n", alg_name);
+
+	tfm->crt_ablkcipher.reqsize = sizeof(struct this_task_ctx);
+	return 0;
+}
+
+static void sep_crypto_exit(struct crypto_tfm *tfm)
+{
+	pr_debug("sep_crypto_exit\n");
+}
+
+static int sep_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+	unsigned int keylen)
+{
+	struct sep_system_ctx *sctx = crypto_ablkcipher_ctx(tfm);
+
+	pr_debug("sep aes setkey\n");
+
+	pr_debug("tfm is %p sctx is %p\n", tfm, sctx);
+	switch (keylen) {
+	case SEP_AES_KEY_128_SIZE:
+		sctx->aes_key_size = AES_128;
+		break;
+	case SEP_AES_KEY_192_SIZE:
+		sctx->aes_key_size = AES_192;
+		break;
+	case SEP_AES_KEY_256_SIZE:
+		sctx->aes_key_size = AES_256;
+		break;
+	case SEP_AES_KEY_512_SIZE:
+		sctx->aes_key_size = AES_512;
+		break;
+	default:
+		pr_debug("invalid sep aes key size %x\n",
+			keylen);
+		return -EINVAL;
+	}
+
+	memset(&sctx->key.aes, 0, sizeof(u32) *
+		SEP_AES_MAX_KEY_SIZE_WORDS);
+	memcpy(&sctx->key.aes, key, keylen);
+	sctx->keylen = keylen;
+	/* Indicate to encrypt/decrypt function to send key to SEP */
+	sctx->key_sent = 0;
+
+	return 0;
+}
+
+static int sep_aes_ecb_encrypt(struct ablkcipher_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ablkcipher_request_ctx(req);
+
+	pr_debug("sep - doing aes ecb encrypt\n");
+
+	/* Clear out task context */
+	memset(ta_ctx, 0, sizeof(struct this_task_ctx));
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = AES_ECB;
+	ta_ctx->current_hash_req = NULL;
+	ta_ctx->current_cypher_req = req;
+	ta_ctx->aes_encmode = SEP_AES_ENCRYPT;
+	ta_ctx->aes_opmode = SEP_AES_ECB;
+	ta_ctx->init_opcode = SEP_AES_INIT_OPCODE;
+	ta_ctx->block_opcode = SEP_AES_BLOCK_OPCODE;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_aes_ecb_decrypt(struct ablkcipher_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ablkcipher_request_ctx(req);
+
+	pr_debug("sep - doing aes ecb decrypt\n");
+
+	/* Clear out task context */
+	memset(ta_ctx, 0, sizeof(struct this_task_ctx));
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = AES_ECB;
+	ta_ctx->current_hash_req = NULL;
+	ta_ctx->current_cypher_req = req;
+	ta_ctx->aes_encmode = SEP_AES_DECRYPT;
+	ta_ctx->aes_opmode = SEP_AES_ECB;
+	ta_ctx->init_opcode = SEP_AES_INIT_OPCODE;
+	ta_ctx->block_opcode = SEP_AES_BLOCK_OPCODE;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_aes_cbc_encrypt(struct ablkcipher_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ablkcipher_request_ctx(req);
+	struct sep_system_ctx *sctx = crypto_ablkcipher_ctx(
+		crypto_ablkcipher_reqtfm(req));
+
+	pr_debug("sep - doing aes cbc encrypt\n");
+
+	/* Clear out task context */
+	memset(ta_ctx, 0, sizeof(struct this_task_ctx));
+
+	pr_debug("tfm is %p sctx is %p and ta_ctx is %p\n",
+		crypto_ablkcipher_reqtfm(req), sctx, ta_ctx);
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = AES_CBC;
+	ta_ctx->current_hash_req = NULL;
+	ta_ctx->current_cypher_req = req;
+	ta_ctx->aes_encmode = SEP_AES_ENCRYPT;
+	ta_ctx->aes_opmode = SEP_AES_CBC;
+	ta_ctx->init_opcode = SEP_AES_INIT_OPCODE;
+	ta_ctx->block_opcode = SEP_AES_BLOCK_OPCODE;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_aes_cbc_decrypt(struct ablkcipher_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ablkcipher_request_ctx(req);
+	struct sep_system_ctx *sctx = crypto_ablkcipher_ctx(
+		crypto_ablkcipher_reqtfm(req));
+
+	pr_debug("sep - doing aes cbc decrypt\n");
+
+	pr_debug("tfm is %p sctx is %p and ta_ctx is %p\n",
+		crypto_ablkcipher_reqtfm(req), sctx, ta_ctx);
+
+	/* Clear out task context */
+	memset(ta_ctx, 0, sizeof(struct this_task_ctx));
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = AES_CBC;
+	ta_ctx->current_hash_req = NULL;
+	ta_ctx->current_cypher_req = req;
+	ta_ctx->aes_encmode = SEP_AES_DECRYPT;
+	ta_ctx->aes_opmode = SEP_AES_CBC;
+	ta_ctx->init_opcode = SEP_AES_INIT_OPCODE;
+	ta_ctx->block_opcode = SEP_AES_BLOCK_OPCODE;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+	unsigned int keylen)
+{
+	struct sep_system_ctx *sctx = crypto_ablkcipher_ctx(tfm);
+	struct crypto_tfm *ctfm = crypto_ablkcipher_tfm(tfm);
+	u32 *flags  = &ctfm->crt_flags;
+
+	pr_debug("sep des setkey\n");
+
+	switch (keylen) {
+	case DES_KEY_SIZE:
+		sctx->des_nbr_keys = DES_KEY_1;
+		break;
+	case DES_KEY_SIZE * 2:
+		sctx->des_nbr_keys = DES_KEY_2;
+		break;
+	case DES_KEY_SIZE * 3:
+		sctx->des_nbr_keys = DES_KEY_3;
+		break;
+	default:
+		pr_debug("invalid key size %x\n",
+			keylen);
+		return -EINVAL;
+	}
+
+	if ((*flags & CRYPTO_TFM_REQ_WEAK_KEY) &&
+		(sep_weak_key(key, keylen))) {
+
+		*flags |= CRYPTO_TFM_RES_WEAK_KEY;
+		pr_debug("weak key\n");
+		return -EINVAL;
+	}
+
+	memset(&sctx->key.des, 0, sizeof(struct sep_des_key));
+	memcpy(&sctx->key.des.key1, key, keylen);
+	sctx->keylen = keylen;
+	/* Indicate to encrypt/decrypt function to send key to SEP */
+	sctx->key_sent = 0;
+
+	return 0;
+}
+
+static int sep_des_ebc_encrypt(struct ablkcipher_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ablkcipher_request_ctx(req);
+
+	pr_debug("sep - doing des ecb encrypt\n");
+
+	/* Clear out task context */
+	memset(ta_ctx, 0, sizeof(struct this_task_ctx));
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = DES_ECB;
+	ta_ctx->current_hash_req = NULL;
+	ta_ctx->current_cypher_req = req;
+	ta_ctx->des_encmode = SEP_DES_ENCRYPT;
+	ta_ctx->des_opmode = SEP_DES_ECB;
+	ta_ctx->init_opcode = SEP_DES_INIT_OPCODE;
+	ta_ctx->block_opcode = SEP_DES_BLOCK_OPCODE;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_des_ebc_decrypt(struct ablkcipher_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ablkcipher_request_ctx(req);
+
+	pr_debug("sep - doing des ecb decrypt\n");
+
+	/* Clear out task context */
+	memset(ta_ctx, 0, sizeof(struct this_task_ctx));
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = DES_ECB;
+	ta_ctx->current_hash_req = NULL;
+	ta_ctx->current_cypher_req = req;
+	ta_ctx->des_encmode = SEP_DES_DECRYPT;
+	ta_ctx->des_opmode = SEP_DES_ECB;
+	ta_ctx->init_opcode = SEP_DES_INIT_OPCODE;
+	ta_ctx->block_opcode = SEP_DES_BLOCK_OPCODE;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_des_cbc_encrypt(struct ablkcipher_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ablkcipher_request_ctx(req);
+
+	pr_debug("sep - doing des cbc encrypt\n");
+
+	/* Clear out task context */
+	memset(ta_ctx, 0, sizeof(struct this_task_ctx));
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = DES_CBC;
+	ta_ctx->current_hash_req = NULL;
+	ta_ctx->current_cypher_req = req;
+	ta_ctx->des_encmode = SEP_DES_ENCRYPT;
+	ta_ctx->des_opmode = SEP_DES_CBC;
+	ta_ctx->init_opcode = SEP_DES_INIT_OPCODE;
+	ta_ctx->block_opcode = SEP_DES_BLOCK_OPCODE;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static int sep_des_cbc_decrypt(struct ablkcipher_request *req)
+{
+	int error;
+	int error1;
+	struct this_task_ctx *ta_ctx = ablkcipher_request_ctx(req);
+
+	pr_debug("sep - doing des ecb decrypt\n");
+
+	/* Clear out task context */
+	memset(ta_ctx, 0, sizeof(struct this_task_ctx));
+
+	ta_ctx->sep_used = sep_dev;
+	ta_ctx->current_request = DES_CBC;
+	ta_ctx->current_hash_req = NULL;
+	ta_ctx->current_cypher_req = req;
+	ta_ctx->des_encmode = SEP_DES_DECRYPT;
+	ta_ctx->des_opmode = SEP_DES_CBC;
+	ta_ctx->init_opcode = SEP_DES_INIT_OPCODE;
+	ta_ctx->block_opcode = SEP_DES_BLOCK_OPCODE;
+
+	/* lock necessary so that only one entity touches the queues */
+	spin_lock_irq(&queue_lock);
+	error = crypto_enqueue_request(&sep_queue, &req->base);
+
+	if ((error != 0) && (error != -EINPROGRESS))
+		pr_debug(" sep - crypto enqueue failed: %x\n",
+			error);
+	error1 = sep_submit_work(ta_ctx->sep_used->workqueue,
+		sep_dequeuer, (void *)&sep_queue);
+	if (error1)
+		pr_debug(" sep - workqueue submit failed: %x\n",
+			error1);
+	spin_unlock_irq(&queue_lock);
+	/* We return result of crypto enqueue */
+	return error;
+}
+
+static struct ahash_alg hash_algs[] = {
+{
+	.init		= sep_sha1_init,
+	.update		= sep_sha1_update,
+	.final		= sep_sha1_final,
+	.digest		= sep_sha1_digest,
+	.finup		= sep_sha1_finup,
+	.halg		= {
+		.digestsize	= SHA1_DIGEST_SIZE,
+		.base	= {
+		.cra_name		= "sha1",
+		.cra_driver_name	= "sha1-sep",
+		.cra_priority		= 100,
+		.cra_flags		= CRYPTO_ALG_TYPE_AHASH |
+						CRYPTO_ALG_ASYNC,
+		.cra_blocksize		= SHA1_BLOCK_SIZE,
+		.cra_ctxsize		= sizeof(struct sep_system_ctx),
+		.cra_alignmask		= 0,
+		.cra_module		= THIS_MODULE,
+		.cra_init		= sep_hash_cra_init,
+		.cra_exit		= sep_hash_cra_exit,
+		}
+	}
+},
+{
+	.init		= sep_md5_init,
+	.update		= sep_md5_update,
+	.final		= sep_md5_final,
+	.digest		= sep_md5_digest,
+	.finup		= sep_md5_finup,
+	.halg		= {
+		.digestsize	= MD5_DIGEST_SIZE,
+		.base	= {
+		.cra_name		= "md5",
+		.cra_driver_name	= "md5-sep",
+		.cra_priority		= 100,
+		.cra_flags		= CRYPTO_ALG_TYPE_AHASH |
+						CRYPTO_ALG_ASYNC,
+		.cra_blocksize		= SHA1_BLOCK_SIZE,
+		.cra_ctxsize		= sizeof(struct sep_system_ctx),
+		.cra_alignmask		= 0,
+		.cra_module		= THIS_MODULE,
+		.cra_init		= sep_hash_cra_init,
+		.cra_exit		= sep_hash_cra_exit,
+		}
+	}
+},
+{
+	.init		= sep_sha224_init,
+	.update		= sep_sha224_update,
+	.final		= sep_sha224_final,
+	.digest		= sep_sha224_digest,
+	.finup		= sep_sha224_finup,
+	.halg		= {
+		.digestsize	= SHA224_DIGEST_SIZE,
+		.base	= {
+		.cra_name		= "sha224",
+		.cra_driver_name	= "sha224-sep",
+		.cra_priority		= 100,
+		.cra_flags		= CRYPTO_ALG_TYPE_AHASH |
+						CRYPTO_ALG_ASYNC,
+		.cra_blocksize		= SHA224_BLOCK_SIZE,
+		.cra_ctxsize		= sizeof(struct sep_system_ctx),
+		.cra_alignmask		= 0,
+		.cra_module		= THIS_MODULE,
+		.cra_init		= sep_hash_cra_init,
+		.cra_exit		= sep_hash_cra_exit,
+		}
+	}
+},
+{
+	.init		= sep_sha256_init,
+	.update		= sep_sha256_update,
+	.final		= sep_sha256_final,
+	.digest		= sep_sha256_digest,
+	.finup		= sep_sha256_finup,
+	.halg		= {
+		.digestsize	= SHA256_DIGEST_SIZE,
+		.base	= {
+		.cra_name		= "sha256",
+		.cra_driver_name	= "sha256-sep",
+		.cra_priority		= 100,
+		.cra_flags		= CRYPTO_ALG_TYPE_AHASH |
+						CRYPTO_ALG_ASYNC,
+		.cra_blocksize		= SHA256_BLOCK_SIZE,
+		.cra_ctxsize		= sizeof(struct sep_system_ctx),
+		.cra_alignmask		= 0,
+		.cra_module		= THIS_MODULE,
+		.cra_init		= sep_hash_cra_init,
+		.cra_exit		= sep_hash_cra_exit,
+		}
+	}
+}
+};
+
+static struct crypto_alg crypto_algs[] = {
+{
+	.cra_name		= "ecb(aes)",
+	.cra_driver_name	= "ecb-aes-sep",
+	.cra_priority		= 100,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct sep_system_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= sep_crypto_init,
+	.cra_exit		= sep_crypto_exit,
+	.cra_u.ablkcipher = {
+		.min_keysize	= AES_MIN_KEY_SIZE,
+		.max_keysize	= AES_MAX_KEY_SIZE,
+		.setkey		= sep_aes_setkey,
+		.encrypt	= sep_aes_ecb_encrypt,
+		.decrypt	= sep_aes_ecb_decrypt,
+	}
+},
+{
+	.cra_name		= "cbc(aes)",
+	.cra_driver_name	= "cbc-aes-sep",
+	.cra_priority		= 100,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct sep_system_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= sep_crypto_init,
+	.cra_exit		= sep_crypto_exit,
+	.cra_u.ablkcipher = {
+		.min_keysize	= AES_MIN_KEY_SIZE,
+		.max_keysize	= AES_MAX_KEY_SIZE,
+		.setkey		= sep_aes_setkey,
+		.encrypt	= sep_aes_cbc_encrypt,
+		.ivsize		= AES_BLOCK_SIZE,
+		.decrypt	= sep_aes_cbc_decrypt,
+	}
+},
+{
+	.cra_name		= "ebc(des)",
+	.cra_driver_name	= "ebc-des-sep",
+	.cra_priority		= 100,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= DES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct sep_system_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= sep_crypto_init,
+	.cra_exit		= sep_crypto_exit,
+	.cra_u.ablkcipher = {
+		.min_keysize	= DES_KEY_SIZE,
+		.max_keysize	= DES_KEY_SIZE,
+		.setkey		= sep_des_setkey,
+		.encrypt	= sep_des_ebc_encrypt,
+		.decrypt	= sep_des_ebc_decrypt,
+	}
+},
+{
+	.cra_name		= "cbc(des)",
+	.cra_driver_name	= "cbc-des-sep",
+	.cra_priority		= 100,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= DES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct sep_system_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= sep_crypto_init,
+	.cra_exit		= sep_crypto_exit,
+	.cra_u.ablkcipher = {
+		.min_keysize	= DES_KEY_SIZE,
+		.max_keysize	= DES_KEY_SIZE,
+		.setkey		= sep_des_setkey,
+		.encrypt	= sep_des_cbc_encrypt,
+		.ivsize		= DES_BLOCK_SIZE,
+		.decrypt	= sep_des_cbc_decrypt,
+	}
+},
+{
+	.cra_name		= "ebc(des3-ede)",
+	.cra_driver_name	= "ebc-des3-ede-sep",
+	.cra_priority		= 100,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= DES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct sep_system_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= sep_crypto_init,
+	.cra_exit		= sep_crypto_exit,
+	.cra_u.ablkcipher = {
+		.min_keysize	= DES3_EDE_KEY_SIZE,
+		.max_keysize	= DES3_EDE_KEY_SIZE,
+		.setkey		= sep_des_setkey,
+		.encrypt	= sep_des_ebc_encrypt,
+		.decrypt	= sep_des_ebc_decrypt,
+	}
+},
+{
+	.cra_name		= "cbc(des3-ede)",
+	.cra_driver_name	= "cbc-des3--ede-sep",
+	.cra_priority		= 100,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= DES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct sep_system_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= sep_crypto_init,
+	.cra_exit		= sep_crypto_exit,
+	.cra_u.ablkcipher = {
+		.min_keysize	= DES3_EDE_KEY_SIZE,
+		.max_keysize	= DES3_EDE_KEY_SIZE,
+		.setkey		= sep_des_setkey,
+		.encrypt	= sep_des_cbc_encrypt,
+		.decrypt	= sep_des_cbc_decrypt,
+	}
+}
+};
+
+int sep_crypto_setup(void)
+{
+	int err, i, j, k;
+	tasklet_init(&sep_dev->finish_tasklet, sep_finish,
+		(unsigned long)sep_dev);
+
+	crypto_init_queue(&sep_queue, SEP_QUEUE_LENGTH);
+
+	sep_dev->workqueue = create_singlethread_workqueue(
+		"sep_crypto_workqueue");
+	if (!sep_dev->workqueue) {
+		dev_warn(&sep_dev->pdev->dev, "cant create workqueue\n");
+		return -ENOMEM;
+	}
+
+	i = 0;
+	j = 0;
+
+	spin_lock_init(&queue_lock);
+
+	err = 0;
+
+	for (i = 0; i < ARRAY_SIZE(hash_algs); i++) {
+		err = crypto_register_ahash(&hash_algs[i]);
+		if (err)
+			goto err_algs;
+	}
+
+	err = 0;
+	for (j = 0; j < ARRAY_SIZE(crypto_algs); j++) {
+		err = crypto_register_alg(&crypto_algs[j]);
+		if (err)
+			goto err_crypto_algs;
+	}
+
+	return err;
+
+err_algs:
+	for (k = 0; k < i; k++)
+		crypto_unregister_ahash(&hash_algs[k]);
+	return err;
+
+err_crypto_algs:
+	for (k = 0; k < j; k++)
+		crypto_unregister_alg(&crypto_algs[k]);
+	goto err_algs;
+}
+
+void sep_crypto_takedown(void)
+{
+
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hash_algs); i++)
+		crypto_unregister_ahash(&hash_algs[i]);
+	for (i = 0; i < ARRAY_SIZE(crypto_algs); i++)
+		crypto_unregister_alg(&crypto_algs[i]);
+
+	tasklet_kill(&sep_dev->finish_tasklet);
+}
+
+#endif
diff --git a/drivers/staging/sep/sep_crypto.h b/drivers/staging/sep/sep_crypto.h
new file mode 100644
index 0000000..155c3c9
--- /dev/null
+++ b/drivers/staging/sep/sep_crypto.h
@@ -0,0 +1,359 @@
+/*
+ *
+ *  sep_crypto.h - Crypto interface structures
+ *
+ *  Copyright(c) 2009-2011 Intel Corporation. All rights reserved.
+ *  Contributions(c) 2009-2010 Discretix. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; version 2 of the License.
+ *
+ *  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., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ *  CONTACTS:
+ *
+ *  Mark Allyn		mark.a.allyn@intel.com
+ *  Jayant Mangalampalli jayant.mangalampalli@intel.com
+ *
+ *  CHANGES:
+ *
+ *  2009.06.26	Initial publish
+ *  2011.02.22  Enable Kernel Crypto
+ *
+ */
+
+/* Constants for SEP (from vendor) */
+#define SEP_START_MSG_TOKEN	0x02558808
+
+#define SEP_DES_IV_SIZE_WORDS	2
+#define SEP_DES_IV_SIZE_BYTES	(SEP_DES_IV_SIZE_WORDS * \
+	sizeof(u32))
+#define SEP_DES_KEY_SIZE_WORDS	2
+#define SEP_DES_KEY_SIZE_BYTES	(SEP_DES_KEY_SIZE_WORDS * \
+	sizeof(u32))
+#define SEP_DES_BLOCK_SIZE	8
+#define SEP_DES_DUMMY_SIZE	16
+
+#define SEP_DES_INIT_OPCODE	0x10
+#define SEP_DES_BLOCK_OPCODE	0x11
+
+#define SEP_AES_BLOCK_SIZE_WORDS 4
+#define SEP_AES_BLOCK_SIZE_BYTES \
+	(SEP_AES_BLOCK_SIZE_WORDS * sizeof(u32))
+
+#define SEP_AES_DUMMY_BLOCK_SIZE 16
+#define SEP_AES_IV_SIZE_WORDS	SEP_AES_BLOCK_SIZE_WORDS
+#define SEP_AES_IV_SIZE_BYTES \
+	(SEP_AES_IV_SIZE_WORDS * sizeof(u32))
+
+#define SEP_AES_KEY_128_SIZE	16
+#define SEP_AES_KEY_192_SIZE	24
+#define SEP_AES_KEY_256_SIZE	32
+#define SEP_AES_KEY_512_SIZE	64
+#define SEP_AES_MAX_KEY_SIZE_WORDS	16
+#define SEP_AES_MAX_KEY_SIZE_BYTES \
+	(SEP_AES_MAX_KEY_SIZE_WORDS * sizeof(u32))
+
+#define SEP_AES_WRAP_MIN_SIZE	8
+#define SEP_AES_WRAP_MAX_SIZE	0x10000000
+
+#define SEP_AES_WRAP_BLOCK_SIZE_WORDS	2
+#define SEP_AES_WRAP_BLOCK_SIZE_BYTES \
+	(SEP_AES_WRAP_BLOCK_SIZE_WORDS * sizeof(u32))
+
+#define SEP_AES_SECRET_RKEK1		0x1
+#define SEP_AES_SECRET_RKEK2		0x2
+
+#define SEP_AES_INIT_OPCODE		0x2
+#define SEP_AES_BLOCK_OPCODE		0x3
+#define SEP_AES_FINISH_OPCODE		0x4
+#define SEP_AES_WRAP_OPCODE		0x6
+#define SEP_AES_UNWRAP_OPCODE		0x7
+#define SEP_AES_XTS_FINISH_OPCODE	0x8
+
+#define SEP_HASH_RESULT_SIZE_WORDS	16
+#define SEP_MD5_DIGEST_SIZE_WORDS	4
+#define SEP_MD5_DIGEST_SIZE_BYTES \
+	(SEP_MD5_DIGEST_SIZE_WORDS * sizeof(u32))
+#define SEP_SHA1_DIGEST_SIZE_WORDS	5
+#define SEP_SHA1_DIGEST_SIZE_BYTES \
+	(SEP_SHA1_DIGEST_SIZE_WORDS * sizeof(u32))
+#define SEP_SHA224_DIGEST_SIZE_WORDS	7
+#define SEP_SHA224_DIGEST_SIZE_BYTES \
+	(SEP_SHA224_DIGEST_SIZE_WORDS * sizeof(u32))
+#define SEP_SHA256_DIGEST_SIZE_WORDS	8
+#define SEP_SHA256_DIGEST_SIZE_BYTES \
+	(SEP_SHA256_DIGEST_SIZE_WORDS * sizeof(u32))
+#define SEP_SHA384_DIGEST_SIZE_WORDS	12
+#define SEP_SHA384_DIGEST_SIZE_BYTES \
+	(SEP_SHA384_DIGEST_SIZE_WORDS * sizeof(u32))
+#define SEP_SHA512_DIGEST_SIZE_WORDS	16
+#define SEP_SHA512_DIGEST_SIZE_BYTES \
+	(SEP_SHA512_DIGEST_SIZE_WORDS * sizeof(u32))
+#define SEP_HASH_BLOCK_SIZE_WORDS	16
+#define SEP_HASH_BLOCK_SIZE_BYTES \
+	(SEP_HASH_BLOCK_SIZE_WORDS * sizeof(u32))
+#define SEP_SHA2_BLOCK_SIZE_WORDS	32
+#define SEP_SHA2_BLOCK_SIZE_BYTES \
+	(SEP_SHA2_BLOCK_SIZE_WORDS * sizeof(u32))
+
+#define SEP_HASH_INIT_OPCODE		0x20
+#define SEP_HASH_UPDATE_OPCODE		0x21
+#define SEP_HASH_FINISH_OPCODE		0x22
+#define SEP_HASH_SINGLE_OPCODE		0x23
+
+#define SEP_HOST_ERROR		0x0b000000
+#define SEP_OK			0x0
+#define SEP_INVALID_START	(SEP_HOST_ERROR + 0x3)
+#define SEP_WRONG_OPCODE	(SEP_HOST_ERROR + 0x1)
+
+#define SEP_TRANSACTION_WAIT_TIME 5
+
+#define SEP_QUEUE_LENGTH	2
+/* Macros */
+#ifndef __LITTLE_ENDIAN
+#define CHG_ENDIAN(val) \
+	(((val) >> 24) | \
+	(((val) & 0x00FF0000) >> 8) | \
+	(((val) & 0x0000FF00) << 8) | \
+	(((val) & 0x000000FF) << 24))
+#else
+#define CHG_ENDIAN(val) val
+#endif
+/* Enums for SEP (from vendor) */
+enum des_numkey {
+	DES_KEY_1 = 1,
+	DES_KEY_2 = 2,
+	DES_KEY_3 = 3,
+	SEP_NUMKEY_OPTIONS,
+	SEP_NUMKEY_LAST = 0x7fffffff,
+};
+
+enum des_enc_mode {
+	SEP_DES_ENCRYPT = 0,
+	SEP_DES_DECRYPT = 1,
+	SEP_DES_ENC_OPTIONS,
+	SEP_DES_ENC_LAST = 0x7fffffff,
+};
+
+enum des_op_mode {
+	SEP_DES_ECB = 0,
+	SEP_DES_CBC = 1,
+	SEP_OP_OPTIONS,
+	SEP_OP_LAST = 0x7fffffff,
+};
+
+enum aes_keysize {
+	AES_128 = 0,
+	AES_192 = 1,
+	AES_256 = 2,
+	AES_512 = 3,
+	AES_SIZE_OPTIONS,
+	AEA_SIZE_LAST = 0x7FFFFFFF,
+};
+
+enum aes_enc_mode {
+	SEP_AES_ENCRYPT = 0,
+	SEP_AES_DECRYPT = 1,
+	SEP_AES_ENC_OPTIONS,
+	SEP_AES_ENC_LAST = 0x7FFFFFFF,
+};
+
+enum aes_op_mode {
+	SEP_AES_ECB = 0,
+	SEP_AES_CBC = 1,
+	SEP_AES_MAC = 2,
+	SEP_AES_CTR = 3,
+	SEP_AES_XCBC = 4,
+	SEP_AES_CMAC = 5,
+	SEP_AES_XTS = 6,
+	SEP_AES_OP_OPTIONS,
+	SEP_AES_OP_LAST = 0x7FFFFFFF,
+};
+
+enum hash_op_mode {
+	SEP_HASH_SHA1 = 0,
+	SEP_HASH_SHA224 = 1,
+	SEP_HASH_SHA256 = 2,
+	SEP_HASH_SHA384 = 3,
+	SEP_HASH_SHA512 = 4,
+	SEP_HASH_MD5 = 5,
+	SEP_HASH_OPTIONS,
+	SEP_HASH_LAST_MODE = 0x7FFFFFFF,
+};
+
+/* Structures for SEP (from vendor) */
+struct sep_des_internal_key {
+	u32 key1[SEP_DES_KEY_SIZE_WORDS];
+	u32 key2[SEP_DES_KEY_SIZE_WORDS];
+	u32 key3[SEP_DES_KEY_SIZE_WORDS];
+};
+
+struct sep_des_internal_context {
+	u32 iv_context[SEP_DES_IV_SIZE_WORDS];
+	struct sep_des_internal_key context_key;
+	enum des_numkey nbr_keys;
+	enum des_enc_mode encryption;
+	enum des_op_mode operation;
+	u8 dummy_block[SEP_DES_DUMMY_SIZE];
+};
+
+struct sep_des_private_context {
+	u32 valid_tag;
+	u32 iv;
+	u8 ctx_buf[sizeof(struct sep_des_internal_context)];
+};
+
+/* This is the structure passed to SEP via msg area */
+struct sep_des_key {
+	u32 key1[SEP_DES_KEY_SIZE_WORDS];
+	u32 key2[SEP_DES_KEY_SIZE_WORDS];
+	u32 key3[SEP_DES_KEY_SIZE_WORDS];
+	u32 pad[SEP_DES_KEY_SIZE_WORDS];
+};
+
+struct sep_aes_internal_context {
+	u32 aes_ctx_iv[SEP_AES_IV_SIZE_WORDS];
+	u32 aes_ctx_key[SEP_AES_MAX_KEY_SIZE_WORDS / 2];
+	enum aes_keysize keysize;
+	enum aes_enc_mode encmode;
+	enum aes_op_mode opmode;
+	u8 secret_key;
+	u32 no_add_blocks;
+	u32 last_block_size;
+	u32 last_block[SEP_AES_BLOCK_SIZE_WORDS];
+	u32 prev_iv[SEP_AES_BLOCK_SIZE_WORDS];
+	u32 remaining_size;
+	union {
+		struct {
+			u32 dkey1[SEP_AES_BLOCK_SIZE_WORDS];
+			u32 dkey2[SEP_AES_BLOCK_SIZE_WORDS];
+			u32 dkey3[SEP_AES_BLOCK_SIZE_WORDS];
+		} cmac_data;
+		struct {
+			u32 xts_key[SEP_AES_MAX_KEY_SIZE_WORDS / 2];
+			u32 temp1[SEP_AES_BLOCK_SIZE_WORDS];
+			u32 temp2[SEP_AES_BLOCK_SIZE_WORDS];
+		} xtx_data;
+	} s_data;
+	u8 dummy_block[SEP_AES_DUMMY_BLOCK_SIZE];
+};
+
+struct sep_aes_private_context {
+	u32 valid_tag;
+	u32 aes_iv;
+	u32 op_mode;
+	u8 cbuff[sizeof(struct sep_aes_internal_context)];
+};
+
+struct sep_hash_internal_context {
+	u32 hash_result[SEP_HASH_RESULT_SIZE_WORDS];
+	enum hash_op_mode hash_opmode;
+	u32 previous_data[SEP_SHA2_BLOCK_SIZE_WORDS];
+	u16 prev_update_bytes;
+	u32 total_proc_128bit[4];
+	u16 op_mode_block_size;
+	u8 dummy_aes_block[SEP_AES_DUMMY_BLOCK_SIZE];
+};
+
+struct sep_hash_private_context {
+	u32 valid_tag;
+	u32 iv;
+	u8 internal_context[sizeof(struct sep_hash_internal_context)];
+};
+
+union key_t {
+	struct sep_des_key des;
+	u32 aes[SEP_AES_MAX_KEY_SIZE_WORDS];
+};
+
+/* Context structures for crypto API */
+/**
+ * Structure for this current task context
+ * This same structure is used for both hash
+ * and crypt in order to reduce duplicate code
+ * for stuff that is done for both hash operations
+ * and crypto operations. We cannot trust that the
+ * system context is not pulled out from under
+ * us during operation to operation, so all
+ * critical stuff such as data pointers must
+ * be in in a context that is exclusive for this
+ * particular task at hand.
+ */
+struct this_task_ctx {
+	struct sep_device *sep_used;
+	u32 done;
+	unsigned char iv[100];
+	enum des_enc_mode des_encmode;
+	enum des_op_mode des_opmode;
+	enum aes_enc_mode aes_encmode;
+	enum aes_op_mode aes_opmode;
+	u32 init_opcode;
+	u32 block_opcode;
+	size_t data_length;
+	size_t ivlen;
+	struct ablkcipher_walk walk;
+	int i_own_sep; /* Do I have custody of the sep? */
+	struct sep_call_status call_status;
+	struct build_dcb_struct_kernel dcb_input_data;
+	struct sep_dma_context *dma_ctx;
+	void *dmatables_region;
+	size_t nbytes;
+	struct sep_dcblock *dcb_region;
+	struct sep_queue_info *queue_elem;
+	int msg_len_words;
+	unsigned char msg[SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES];
+	void *msgptr;
+	struct scatterlist *src_sg;
+	struct scatterlist *dst_sg;
+	struct scatterlist *src_sg_hold;
+	struct scatterlist *dst_sg_hold;
+	struct ahash_request *current_hash_req;
+	struct ablkcipher_request *current_cypher_req;
+	enum type_of_request current_request;
+	int digest_size_words;
+	int digest_size_bytes;
+	int block_size_words;
+	int block_size_bytes;
+	enum hash_op_mode hash_opmode;
+	enum hash_stage current_hash_stage;
+	/**
+	 * Not that this is a pointer. The are_we_done_yet variable is
+	 * allocated by the task function. This way, even if the kernel
+	 * crypto infrastructure has grabbed the task structure out from
+	 * under us, the task function can still see this variable.
+	 */
+	int *are_we_done_yet;
+	unsigned long end_time;
+	};
+
+struct sep_system_ctx {
+	union key_t key;
+	size_t keylen;
+	int key_sent;
+	enum des_numkey des_nbr_keys;
+	enum aes_keysize aes_key_size;
+	unsigned long end_time;
+	struct sep_des_private_context des_private_ctx;
+	struct sep_aes_private_context aes_private_ctx;
+	struct sep_hash_private_context hash_private_ctx;
+	};
+
+/* work queue structures */
+struct sep_work_struct {
+	struct work_struct work;
+	void (*callback)(void *);
+	void *data;
+	};
+
+/* Functions */
+int sep_crypto_setup(void);
+void sep_crypto_takedown(void);
diff --git a/drivers/staging/sep/sep_dev.h b/drivers/staging/sep/sep_dev.h
index 696ab0d..5f6a07f 100644
--- a/drivers/staging/sep/sep_dev.h
+++ b/drivers/staging/sep/sep_dev.h
@@ -5,8 +5,8 @@
  *
  *  sep_dev.h - Security Processor Device Structures
  *
- *  Copyright(c) 2009,2010 Intel Corporation. All rights reserved.
- *  Contributions(c) 2009,2010 Discretix. All rights reserved.
+ *  Copyright(c) 2009-2011 Intel Corporation. All rights reserved.
+ *  Contributions(c) 2009-2011 Discretix. All rights reserved.
  *
  *  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
@@ -28,6 +28,7 @@
  *
  *  CHANGES
  *  2010.09.14  upgrade to Medfield
+ *  2011.02.22  enable kernel crypto
  */
 
 struct sep_device {
@@ -36,33 +37,21 @@
 
 	/* character device file */
 	struct cdev sep_cdev;
-	struct cdev sep_daemon_cdev;
-	struct cdev sep_singleton_cdev;
 
 	/* devices (using misc dev) */
 	struct miscdevice miscdev_sep;
-	struct miscdevice miscdev_singleton;
-	struct miscdevice miscdev_daemon;
 
 	/* major / minor numbers of device */
 	dev_t sep_devno;
-	dev_t sep_daemon_devno;
-	dev_t sep_singleton_devno;
-
-	struct mutex sep_mutex;
-	struct mutex ioctl_mutex;
+	/* guards command sent counter */
 	spinlock_t snd_rply_lck;
+	/* guards driver memory usage in fastcall if */
+	struct semaphore sep_doublebuf;
 
 	/* flags to indicate use and lock status of sep */
 	u32 pid_doing_transaction;
 	unsigned long in_use_flags;
 
-	/* request daemon alread open */
-	unsigned long request_daemon_open;
-
-	/* 1 = Moorestown; 0 = Medfield */
-	int mrst;
-
 	/* address of the shared memory allocated during init for SEP driver
 	   (coherent alloc) */
 	dma_addr_t shared_bus;
@@ -74,36 +63,77 @@
 	dma_addr_t reg_physical_end;
 	void __iomem *reg_addr;
 
-	/* wait queue head (event) of the driver */
-	wait_queue_head_t event;
-	wait_queue_head_t event_request_daemon;
-	wait_queue_head_t event_mmap;
+	/* wait queue heads of the driver */
+	wait_queue_head_t event_interrupt;
+	wait_queue_head_t event_transactions;
 
-	struct sep_caller_id_entry
-		caller_id_table[SEP_CALLER_ID_TABLE_NUM_ENTRIES];
+	struct list_head sep_queue_status;
+	u32 sep_queue_num;
+	spinlock_t sep_queue_lock;
 
-	/* access flag for singleton device */
-	unsigned long singleton_access_flag;
+	/* Is this in use? */
+	u32 in_use;
+
+	/* indicates whether power save is set up */
+	u32 power_save_setup;
+
+	/* Power state */
+	u32 power_state;
 
 	/* transaction counter that coordinates the
 	   transactions between SEP and HOST */
 	unsigned long send_ct;
 	/* counter for the messages from sep */
 	unsigned long reply_ct;
-	/* counter for the number of bytes allocated in the pool for the
-	   current transaction */
-	long data_pool_bytes_allocated;
 
-	u32 num_of_data_allocations;
+	/* The following are used for kernel crypto client requests */
+	u32 in_kernel; /* Set for kernel client request */
+	struct tasklet_struct	finish_tasklet;
+	enum type_of_request current_request;
+	enum hash_stage	current_hash_stage;
+	struct ahash_request	*current_hash_req;
+	struct ablkcipher_request *current_cypher_req;
+	struct this_task_ctx *ta_ctx;
+	struct workqueue_struct	*workqueue;
+};
 
-	/* number of the lli tables created in the current transaction */
-	u32     num_lli_tables_created;
+extern struct sep_device *sep_dev;
 
-	/* number of data control blocks */
-	u32 nr_dcb_creat;
+/**
+ * SEP message header for a transaction
+ * @reserved: reserved memory (two words)
+ * @token: SEP message token
+ * @msg_len: message length
+ * @opcpde: message opcode
+ */
+struct sep_msgarea_hdr {
+	u32 reserved[2];
+	u32 token;
+	u32 msg_len;
+	u32 opcode;
+};
 
-	struct sep_dma_resource dma_res_arr[SEP_MAX_NUM_SYNC_DMA_OPS];
+/**
+ * sep_queue_data - data to be maintained in status queue for a transaction
+ * @opcode : transaction opcode
+ * @size : message size
+ * @pid: owner process
+ * @name: owner process name
+ */
+struct sep_queue_data {
+	u32 opcode;
+	u32 size;
+	s32 pid;
+	u8 name[TASK_COMM_LEN];
+};
 
+/** sep_queue_info - maintains status info of all transactions
+ * @list: head of list
+ * @sep_queue_data : data for transaction
+ */
+struct sep_queue_info {
+	struct list_head list;
+	struct sep_queue_data data;
 };
 
 static inline void sep_write_reg(struct sep_device *dev, int reg, u32 value)
diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c
deleted file mode 100644
index 6b3d156..0000000
--- a/drivers/staging/sep/sep_driver.c
+++ /dev/null
@@ -1,2932 +0,0 @@
-/*
- *
- *  sep_driver.c - Security Processor Driver main group of functions
- *
- *  Copyright(c) 2009,2010 Intel Corporation. All rights reserved.
- *  Contributions(c) 2009,2010 Discretix. All rights reserved.
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the Free
- *  Software Foundation; version 2 of the License.
- *
- *  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., 59
- *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- *  CONTACTS:
- *
- *  Mark Allyn		mark.a.allyn@intel.com
- *  Jayant Mangalampalli jayant.mangalampalli@intel.com
- *
- *  CHANGES:
- *
- *  2009.06.26	Initial publish
- *  2010.09.14  Upgrade to Medfield
- *
- */
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/miscdevice.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/kdev_t.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/poll.h>
-#include <linux/wait.h>
-#include <linux/pci.h>
-#include <linux/firmware.h>
-#include <linux/slab.h>
-#include <linux/ioctl.h>
-#include <asm/current.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/pagemap.h>
-#include <asm/cacheflush.h>
-#include <linux/delay.h>
-#include <linux/jiffies.h>
-#include <linux/rar_register.h>
-
-#include "sep_driver_hw_defs.h"
-#include "sep_driver_config.h"
-#include "sep_driver_api.h"
-#include "sep_dev.h"
-
-/*----------------------------------------
-	DEFINES
------------------------------------------*/
-
-#define SEP_RAR_IO_MEM_REGION_SIZE 0x40000
-
-/*--------------------------------------------
-	GLOBAL variables
---------------------------------------------*/
-
-/* Keep this a single static object for now to keep the conversion easy */
-
-static struct sep_device *sep_dev;
-
-/**
- *	sep_dump_message - dump the message that is pending
- *	@sep: SEP device
- */
-static void sep_dump_message(struct sep_device *sep)
-{
-	int count;
-	u32 *p = sep->shared_addr;
-	for (count = 0; count < 12 * 4; count += 4)
-		dev_dbg(&sep->pdev->dev, "Word %d of the message is %x\n",
-								count, *p++);
-}
-
-/**
- *	sep_map_and_alloc_shared_area -	allocate shared block
- *	@sep: security processor
- *	@size: size of shared area
- */
-static int sep_map_and_alloc_shared_area(struct sep_device *sep)
-{
-	sep->shared_addr = dma_alloc_coherent(&sep->pdev->dev,
-		sep->shared_size,
-		&sep->shared_bus, GFP_KERNEL);
-
-	if (!sep->shared_addr) {
-		dev_warn(&sep->pdev->dev,
-			"shared memory dma_alloc_coherent failed\n");
-		return -ENOMEM;
-	}
-	dev_dbg(&sep->pdev->dev,
-		"shared_addr %zx bytes @%p (bus %llx)\n",
-				sep->shared_size, sep->shared_addr,
-				(unsigned long long)sep->shared_bus);
-	return 0;
-}
-
-/**
- *	sep_unmap_and_free_shared_area - free shared block
- *	@sep: security processor
- */
-static void sep_unmap_and_free_shared_area(struct sep_device *sep)
-{
-	dma_free_coherent(&sep->pdev->dev, sep->shared_size,
-				sep->shared_addr, sep->shared_bus);
-}
-
-/**
- *	sep_shared_bus_to_virt - convert bus/virt addresses
- *	@sep: pointer to struct sep_device
- *	@bus_address: address to convert
- *
- *	Returns virtual address inside the shared area according
- *	to the bus address.
- */
-static void *sep_shared_bus_to_virt(struct sep_device *sep,
-						dma_addr_t bus_address)
-{
-	return sep->shared_addr + (bus_address - sep->shared_bus);
-}
-
-/**
- *	open function for the singleton driver
- *	@inode_ptr struct inode *
- *	@file_ptr struct file *
- *
- *	Called when the user opens the singleton device interface
- */
-static int sep_singleton_open(struct inode *inode_ptr, struct file *file_ptr)
-{
-	struct sep_device *sep;
-
-	/*
-	 * Get the SEP device structure and use it for the
-	 * private_data field in filp for other methods
-	 */
-	sep = sep_dev;
-
-	file_ptr->private_data = sep;
-
-	if (test_and_set_bit(0, &sep->singleton_access_flag))
-		return -EBUSY;
-	return 0;
-}
-
-/**
- *	sep_open - device open method
- *	@inode: inode of SEP device
- *	@filp: file handle to SEP device
- *
- *	Open method for the SEP device. Called when userspace opens
- *	the SEP device node.
- *
- *	Returns zero on success otherwise an error code.
- */
-static int sep_open(struct inode *inode, struct file *filp)
-{
-	struct sep_device *sep;
-
-	/*
-	 * Get the SEP device structure and use it for the
-	 * private_data field in filp for other methods
-	 */
-	sep = sep_dev;
-	filp->private_data = sep;
-
-	/* Anyone can open; locking takes place at transaction level */
-	return 0;
-}
-
-/**
- *	sep_singleton_release - close a SEP singleton device
- *	@inode: inode of SEP device
- *	@filp: file handle being closed
- *
- *	Called on the final close of a SEP device. As the open protects against
- *	multiple simultaenous opens that means this method is called when the
- *	final reference to the open handle is dropped.
- */
-static int sep_singleton_release(struct inode *inode, struct file *filp)
-{
-	struct sep_device *sep = filp->private_data;
-
-	clear_bit(0, &sep->singleton_access_flag);
-	return 0;
-}
-
-/**
- *	sep_request_daemon_open - request daemon open method
- *	@inode: inode of SEP device
- *	@filp: file handle to SEP device
- *
- *	Open method for the SEP request daemon. Called when
- *	request daemon in userspace opens the SEP device node.
- *
- *	Returns zero on success otherwise an error code.
- */
-static int sep_request_daemon_open(struct inode *inode, struct file *filp)
-{
-	struct sep_device *sep = sep_dev;
-	int error = 0;
-
-	filp->private_data = sep;
-
-	/* There is supposed to be only one request daemon */
-	if (test_and_set_bit(0, &sep->request_daemon_open))
-		error = -EBUSY;
-	return error;
-}
-
-/**
- *	sep_request_daemon_release - close a SEP daemon
- *	@inode: inode of SEP device
- *	@filp: file handle being closed
- *
- *	Called on the final close of a SEP daemon.
- */
-static int sep_request_daemon_release(struct inode *inode, struct file *filp)
-{
-	struct sep_device *sep = filp->private_data;
-
-	dev_dbg(&sep->pdev->dev, "Request daemon release for pid %d\n",
-		current->pid);
-
-	/* Clear the request_daemon_open flag */
-	clear_bit(0, &sep->request_daemon_open);
-	return 0;
-}
-
-/**
- *	sep_req_daemon_send_reply_command_handler - poke the SEP
- *	@sep: struct sep_device *
- *
- *	This function raises interrupt to SEPm that signals that is has a
- *	new command from HOST
- */
-static int sep_req_daemon_send_reply_command_handler(struct sep_device *sep)
-{
-	unsigned long lck_flags;
-
-	sep_dump_message(sep);
-
-	/* Counters are lockable region */
-	spin_lock_irqsave(&sep->snd_rply_lck, lck_flags);
-	sep->send_ct++;
-	sep->reply_ct++;
-
-	/* Send the interrupt to SEP */
-	sep_write_reg(sep, HW_HOST_HOST_SEP_GPR2_REG_ADDR, sep->send_ct);
-	sep->send_ct++;
-
-	spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags);
-
-	dev_dbg(&sep->pdev->dev,
-		"sep_req_daemon_send_reply send_ct %lx reply_ct %lx\n",
-		sep->send_ct, sep->reply_ct);
-
-	return 0;
-}
-
-
-/**
- *	sep_free_dma_table_data_handler - free DMA table
- *	@sep: pointere to struct sep_device
- *
- *	Handles the request to  free DMA table for synchronic actions
- */
-static int sep_free_dma_table_data_handler(struct sep_device *sep)
-{
-	int count;
-	int dcb_counter;
-	/* Pointer to the current dma_resource struct */
-	struct sep_dma_resource *dma;
-
-	for (dcb_counter = 0; dcb_counter < sep->nr_dcb_creat; dcb_counter++) {
-		dma = &sep->dma_res_arr[dcb_counter];
-
-		/* Unmap and free input map array */
-		if (dma->in_map_array) {
-			for (count = 0; count < dma->in_num_pages; count++) {
-				dma_unmap_page(&sep->pdev->dev,
-					dma->in_map_array[count].dma_addr,
-					dma->in_map_array[count].size,
-					DMA_TO_DEVICE);
-			}
-			kfree(dma->in_map_array);
-		}
-
-		/* Unmap output map array, DON'T free it yet */
-		if (dma->out_map_array) {
-			for (count = 0; count < dma->out_num_pages; count++) {
-				dma_unmap_page(&sep->pdev->dev,
-					dma->out_map_array[count].dma_addr,
-					dma->out_map_array[count].size,
-					DMA_FROM_DEVICE);
-			}
-			kfree(dma->out_map_array);
-		}
-
-		/* Free page cache for output */
-		if (dma->in_page_array) {
-			for (count = 0; count < dma->in_num_pages; count++) {
-				flush_dcache_page(dma->in_page_array[count]);
-				page_cache_release(dma->in_page_array[count]);
-			}
-			kfree(dma->in_page_array);
-		}
-
-		if (dma->out_page_array) {
-			for (count = 0; count < dma->out_num_pages; count++) {
-				if (!PageReserved(dma->out_page_array[count]))
-					SetPageDirty(dma->out_page_array[count]);
-				flush_dcache_page(dma->out_page_array[count]);
-				page_cache_release(dma->out_page_array[count]);
-			}
-			kfree(dma->out_page_array);
-		}
-
-		/* Reset all the values */
-		dma->in_page_array = NULL;
-		dma->out_page_array = NULL;
-		dma->in_num_pages = 0;
-		dma->out_num_pages = 0;
-		dma->in_map_array = NULL;
-		dma->out_map_array = NULL;
-		dma->in_map_num_entries = 0;
-		dma->out_map_num_entries = 0;
-	}
-
-	sep->nr_dcb_creat = 0;
-	sep->num_lli_tables_created = 0;
-
-	return 0;
-}
-
-/**
- *	sep_request_daemon_mmap - maps the shared area to user space
- *	@filp: pointer to struct file
- *	@vma: pointer to vm_area_struct
- *
- *	Called by the kernel when the daemon attempts an mmap() syscall
- *	using our handle.
- */
-static int sep_request_daemon_mmap(struct file  *filp,
-	struct vm_area_struct  *vma)
-{
-	struct sep_device *sep = filp->private_data;
-	dma_addr_t bus_address;
-	int error = 0;
-
-	if ((vma->vm_end - vma->vm_start) > SEP_DRIVER_MMMAP_AREA_SIZE) {
-		error = -EINVAL;
-		goto end_function;
-	}
-
-	/* Get physical address */
-	bus_address = sep->shared_bus;
-
-	if (remap_pfn_range(vma, vma->vm_start, bus_address >> PAGE_SHIFT,
-		vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
-
-		dev_warn(&sep->pdev->dev, "remap_page_range failed\n");
-		error = -EAGAIN;
-		goto end_function;
-	}
-
-end_function:
-	return error;
-}
-
-/**
- *	sep_request_daemon_poll - poll implementation
- *	@sep: struct sep_device * for current SEP device
- *	@filp: struct file * for open file
- *	@wait: poll_table * for poll
- *
- *	Called when our device is part of a poll() or select() syscall
- */
-static unsigned int sep_request_daemon_poll(struct file *filp,
-	poll_table  *wait)
-{
-	u32	mask = 0;
-	/* GPR2 register */
-	u32	retval2;
-	unsigned long lck_flags;
-	struct sep_device *sep = filp->private_data;
-
-	poll_wait(filp, &sep->event_request_daemon, wait);
-
-	dev_dbg(&sep->pdev->dev, "daemon poll: send_ct is %lx reply ct is %lx\n",
-						sep->send_ct, sep->reply_ct);
-
-	spin_lock_irqsave(&sep->snd_rply_lck, lck_flags);
-	/* Check if the data is ready */
-	if (sep->send_ct == sep->reply_ct) {
-		spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags);
-
-		retval2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
-		dev_dbg(&sep->pdev->dev,
-			"daemon poll: data check (GPR2) is %x\n", retval2);
-
-		/* Check if PRINT request */
-		if ((retval2 >> 30) & 0x1) {
-			dev_dbg(&sep->pdev->dev, "daemon poll: PRINTF request in\n");
-			mask |= POLLIN;
-			goto end_function;
-		}
-		/* Check if NVS request */
-		if (retval2 >> 31) {
-			dev_dbg(&sep->pdev->dev, "daemon poll: NVS request in\n");
-			mask |= POLLPRI | POLLWRNORM;
-		}
-	} else {
-		spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags);
-		dev_dbg(&sep->pdev->dev,
-			"daemon poll: no reply received; returning 0\n");
-		mask = 0;
-	}
-end_function:
-	return mask;
-}
-
-/**
- *	sep_release - close a SEP device
- *	@inode: inode of SEP device
- *	@filp: file handle being closed
- *
- *	Called on the final close of a SEP device.
- */
-static int sep_release(struct inode *inode, struct file *filp)
-{
-	struct sep_device *sep = filp->private_data;
-
-	dev_dbg(&sep->pdev->dev, "Release for pid %d\n", current->pid);
-
-	mutex_lock(&sep->sep_mutex);
-	/* Is this the process that has a transaction open?
-	 * If so, lets reset pid_doing_transaction to 0 and
-	 * clear the in use flags, and then wake up sep_event
-	 * so that other processes can do transactions
-	 */
-	if (sep->pid_doing_transaction == current->pid) {
-		clear_bit(SEP_MMAP_LOCK_BIT, &sep->in_use_flags);
-		clear_bit(SEP_SEND_MSG_LOCK_BIT, &sep->in_use_flags);
-		sep_free_dma_table_data_handler(sep);
-		wake_up(&sep->event);
-		sep->pid_doing_transaction = 0;
-	}
-
-	mutex_unlock(&sep->sep_mutex);
-	return 0;
-}
-
-/**
- *	sep_mmap -  maps the shared area to user space
- *	@filp: pointer to struct file
- *	@vma: pointer to vm_area_struct
- *
- *	Called on an mmap of our space via the normal SEP device
- */
-static int sep_mmap(struct file *filp, struct vm_area_struct *vma)
-{
-	dma_addr_t bus_addr;
-	struct sep_device *sep = filp->private_data;
-	unsigned long error = 0;
-
-	/* Set the transaction busy (own the device) */
-	wait_event_interruptible(sep->event,
-		test_and_set_bit(SEP_MMAP_LOCK_BIT,
-		&sep->in_use_flags) == 0);
-
-	if (signal_pending(current)) {
-		error = -EINTR;
-		goto end_function_with_error;
-	}
-	/*
-	 * The pid_doing_transaction indicates that this process
-	 * now owns the facilities to performa a transaction with
-	 * the SEP. While this process is performing a transaction,
-	 * no other process who has the SEP device open can perform
-	 * any transactions. This method allows more than one process
-	 * to have the device open at any given time, which provides
-	 * finer granularity for device utilization by multiple
-	 * processes.
-	 */
-	mutex_lock(&sep->sep_mutex);
-	sep->pid_doing_transaction = current->pid;
-	mutex_unlock(&sep->sep_mutex);
-
-	/* Zero the pools and the number of data pool alocation pointers */
-	sep->data_pool_bytes_allocated = 0;
-	sep->num_of_data_allocations = 0;
-
-	/*
-	 * Check that the size of the mapped range is as the size of the message
-	 * shared area
-	 */
-	if ((vma->vm_end - vma->vm_start) > SEP_DRIVER_MMMAP_AREA_SIZE) {
-		error = -EINVAL;
-		goto end_function_with_error;
-	}
-
-	dev_dbg(&sep->pdev->dev, "shared_addr is %p\n", sep->shared_addr);
-
-	/* Get bus address */
-	bus_addr = sep->shared_bus;
-
-	if (remap_pfn_range(vma, vma->vm_start, bus_addr >> PAGE_SHIFT,
-		vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
-		dev_warn(&sep->pdev->dev, "remap_page_range failed\n");
-		error = -EAGAIN;
-		goto end_function_with_error;
-	}
-	goto end_function;
-
-end_function_with_error:
-	/* Clear the bit */
-	clear_bit(SEP_MMAP_LOCK_BIT, &sep->in_use_flags);
-	mutex_lock(&sep->sep_mutex);
-	sep->pid_doing_transaction = 0;
-	mutex_unlock(&sep->sep_mutex);
-
-	/* Raise event for stuck contextes */
-
-	wake_up(&sep->event);
-
-end_function:
-	return error;
-}
-
-/**
- *	sep_poll - poll handler
- *	@filp: pointer to struct file
- *	@wait: pointer to poll_table
- *
- *	Called by the OS when the kernel is asked to do a poll on
- *	a SEP file handle.
- */
-static unsigned int sep_poll(struct file *filp, poll_table *wait)
-{
-	u32 mask = 0;
-	u32 retval = 0;
-	u32 retval2 = 0;
-	unsigned long lck_flags;
-
-	struct sep_device *sep = filp->private_data;
-
-	/* Am I the process that owns the transaction? */
-	mutex_lock(&sep->sep_mutex);
-	if (current->pid != sep->pid_doing_transaction) {
-		dev_dbg(&sep->pdev->dev, "poll; wrong pid\n");
-		mask = POLLERR;
-		mutex_unlock(&sep->sep_mutex);
-		goto end_function;
-	}
-	mutex_unlock(&sep->sep_mutex);
-
-	/* Check if send command or send_reply were activated previously */
-	if (!test_bit(SEP_SEND_MSG_LOCK_BIT, &sep->in_use_flags)) {
-		mask = POLLERR;
-		goto end_function;
-	}
-
-	/* Add the event to the polling wait table */
-	dev_dbg(&sep->pdev->dev, "poll: calling wait sep_event\n");
-
-	poll_wait(filp, &sep->event, wait);
-
-	dev_dbg(&sep->pdev->dev, "poll: send_ct is %lx reply ct is %lx\n",
-		sep->send_ct, sep->reply_ct);
-
-	/* Check if error occurred during poll */
-	retval2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
-	if (retval2 != 0x0) {
-		dev_warn(&sep->pdev->dev, "poll; poll error %x\n", retval2);
-		mask |= POLLERR;
-		goto end_function;
-	}
-
-	spin_lock_irqsave(&sep->snd_rply_lck, lck_flags);
-
-	if (sep->send_ct == sep->reply_ct) {
-		spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags);
-		retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
-		dev_dbg(&sep->pdev->dev, "poll: data ready check (GPR2)  %x\n",
-			retval);
-
-		/* Check if printf request  */
-		if ((retval >> 30) & 0x1) {
-			dev_dbg(&sep->pdev->dev, "poll: SEP printf request\n");
-			wake_up(&sep->event_request_daemon);
-			goto end_function;
-		}
-
-		/* Check if the this is SEP reply or request */
-		if (retval >> 31) {
-			dev_dbg(&sep->pdev->dev, "poll: SEP request\n");
-			wake_up(&sep->event_request_daemon);
-		} else {
-			dev_dbg(&sep->pdev->dev, "poll: normal return\n");
-			/* In case it is again by send_reply_comand */
-			clear_bit(SEP_SEND_MSG_LOCK_BIT, &sep->in_use_flags);
-			sep_dump_message(sep);
-			dev_dbg(&sep->pdev->dev,
-				"poll; SEP reply POLLIN | POLLRDNORM\n");
-			mask |= POLLIN | POLLRDNORM;
-		}
-	} else {
-		spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags);
-		dev_dbg(&sep->pdev->dev,
-			"poll; no reply received; returning mask of 0\n");
-		mask = 0;
-	}
-
-end_function:
-	return mask;
-}
-
-/**
- *	sep_time_address - address in SEP memory of time
- *	@sep: SEP device we want the address from
- *
- *	Return the address of the two dwords in memory used for time
- *	setting.
- */
-static u32 *sep_time_address(struct sep_device *sep)
-{
-	return sep->shared_addr + SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES;
-}
-
-/**
- *	sep_set_time - set the SEP time
- *	@sep: the SEP we are setting the time for
- *
- *	Calculates time and sets it at the predefined address.
- *	Called with the SEP mutex held.
- */
-static unsigned long sep_set_time(struct sep_device *sep)
-{
-	struct timeval time;
-	u32 *time_addr;	/* Address of time as seen by the kernel */
-
-
-	do_gettimeofday(&time);
-
-	/* Set value in the SYSTEM MEMORY offset */
-	time_addr = sep_time_address(sep);
-
-	time_addr[0] = SEP_TIME_VAL_TOKEN;
-	time_addr[1] = time.tv_sec;
-
-	dev_dbg(&sep->pdev->dev, "time.tv_sec is %lu\n", time.tv_sec);
-	dev_dbg(&sep->pdev->dev, "time_addr is %p\n", time_addr);
-	dev_dbg(&sep->pdev->dev, "sep->shared_addr is %p\n", sep->shared_addr);
-
-	return time.tv_sec;
-}
-
-/**
- *	sep_set_caller_id_handler - insert caller id entry
- *	@sep: SEP device
- *	@arg: pointer to struct caller_id_struct
- *
- *	Inserts the data into the caller id table. Note that this function
- *	falls under the ioctl lock
- */
-static int sep_set_caller_id_handler(struct sep_device *sep, unsigned long arg)
-{
-	void __user *hash;
-	int   error = 0;
-	int   i;
-	struct caller_id_struct command_args;
-
-	for (i = 0; i < SEP_CALLER_ID_TABLE_NUM_ENTRIES; i++) {
-		if (sep->caller_id_table[i].pid == 0)
-			break;
-	}
-
-	if (i == SEP_CALLER_ID_TABLE_NUM_ENTRIES) {
-		dev_dbg(&sep->pdev->dev, "no more caller id entries left\n");
-		dev_dbg(&sep->pdev->dev, "maximum number is %d\n",
-					SEP_CALLER_ID_TABLE_NUM_ENTRIES);
-		error = -EUSERS;
-		goto end_function;
-	}
-
-	/* Copy the data */
-	if (copy_from_user(&command_args, (void __user *)arg,
-		sizeof(command_args))) {
-		error = -EFAULT;
-		goto end_function;
-	}
-
-	hash = (void __user *)(unsigned long)command_args.callerIdAddress;
-
-	if (!command_args.pid || !command_args.callerIdSizeInBytes) {
-		error = -EINVAL;
-		goto end_function;
-	}
-
-	dev_dbg(&sep->pdev->dev, "pid is %x\n", command_args.pid);
-	dev_dbg(&sep->pdev->dev, "callerIdSizeInBytes is %x\n",
-		command_args.callerIdSizeInBytes);
-
-	if (command_args.callerIdSizeInBytes >
-					SEP_CALLER_ID_HASH_SIZE_IN_BYTES) {
-		error = -EMSGSIZE;
-		goto end_function;
-	}
-
-	sep->caller_id_table[i].pid = command_args.pid;
-
-	if (copy_from_user(sep->caller_id_table[i].callerIdHash,
-		hash, command_args.callerIdSizeInBytes))
-		error = -EFAULT;
-end_function:
-	return error;
-}
-
-/**
- *	sep_set_current_caller_id - set the caller id
- *	@sep: pointer to struct_sep_device
- *
- *	Set the caller ID (if it exists) to the SEP. Note that this
- *	function falls under the ioctl lock
- */
-static int sep_set_current_caller_id(struct sep_device *sep)
-{
-	int i;
-	u32 *hash_buf_ptr;
-
-	/* Zero the previous value */
-	memset(sep->shared_addr + SEP_CALLER_ID_OFFSET_BYTES,
-					0, SEP_CALLER_ID_HASH_SIZE_IN_BYTES);
-
-	for (i = 0; i < SEP_CALLER_ID_TABLE_NUM_ENTRIES; i++) {
-		if (sep->caller_id_table[i].pid == current->pid) {
-			dev_dbg(&sep->pdev->dev, "Caller Id found\n");
-
-			memcpy(sep->shared_addr + SEP_CALLER_ID_OFFSET_BYTES,
-				(void *)(sep->caller_id_table[i].callerIdHash),
-				SEP_CALLER_ID_HASH_SIZE_IN_BYTES);
-			break;
-		}
-	}
-	/* Ensure data is in little endian */
-	hash_buf_ptr = (u32 *)sep->shared_addr +
-		SEP_CALLER_ID_OFFSET_BYTES;
-
-	for (i = 0; i < SEP_CALLER_ID_HASH_SIZE_IN_WORDS; i++)
-		hash_buf_ptr[i] = cpu_to_le32(hash_buf_ptr[i]);
-
-	return 0;
-}
-
-/**
- *	sep_send_command_handler - kick off a command
- *	@sep: SEP being signalled
- *
- *	This function raises interrupt to SEP that signals that is has a new
- *	command from the host
- *
- *      Note that this function does fall under the ioctl lock
- */
-static int sep_send_command_handler(struct sep_device *sep)
-{
-	unsigned long lck_flags;
-	int error = 0;
-
-	if (test_and_set_bit(SEP_SEND_MSG_LOCK_BIT, &sep->in_use_flags)) {
-		error = -EPROTO;
-		goto end_function;
-	}
-	sep_set_time(sep);
-
-	sep_set_current_caller_id(sep);
-
-	sep_dump_message(sep);
-
-	/* Update counter */
-	spin_lock_irqsave(&sep->snd_rply_lck, lck_flags);
-	sep->send_ct++;
-	spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags);
-
-	dev_dbg(&sep->pdev->dev,
-		"sep_send_command_handler send_ct %lx reply_ct %lx\n",
-						sep->send_ct, sep->reply_ct);
-
-	/* Send interrupt to SEP */
-	sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2);
-
-end_function:
-	return error;
-}
-
-/**
- *	sep_allocate_data_pool_memory_handler -allocate pool memory
- *	@sep: pointer to struct sep_device
- *	@arg: pointer to struct alloc_struct
- *
- *	This function handles the allocate data pool memory request
- *	This function returns calculates the bus address of the
- *	allocated memory, and the offset of this area from the mapped address.
- *	Therefore, the FVOs in user space can calculate the exact virtual
- *	address of this allocated memory
- */
-static int sep_allocate_data_pool_memory_handler(struct sep_device *sep,
-	unsigned long arg)
-{
-	int error = 0;
-	struct alloc_struct command_args;
-
-	/* Holds the allocated buffer address in the system memory pool */
-	u32 *token_addr;
-
-	if (copy_from_user(&command_args, (void __user *)arg,
-					sizeof(struct alloc_struct))) {
-		error = -EFAULT;
-		goto end_function;
-	}
-
-	/* Allocate memory */
-	if ((sep->data_pool_bytes_allocated + command_args.num_bytes) >
-		SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) {
-		error = -ENOMEM;
-		goto end_function;
-	}
-
-	dev_dbg(&sep->pdev->dev,
-		"data pool bytes_allocated: %x\n", (int)sep->data_pool_bytes_allocated);
-	dev_dbg(&sep->pdev->dev,
-		"offset: %x\n", SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES);
-	/* Set the virtual and bus address */
-	command_args.offset = SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES +
-		sep->data_pool_bytes_allocated;
-
-	/* Place in the shared area that is known by the SEP */
-	token_addr = (u32 *)(sep->shared_addr +
-		SEP_DRIVER_DATA_POOL_ALLOCATION_OFFSET_IN_BYTES +
-		(sep->num_of_data_allocations)*2*sizeof(u32));
-
-	token_addr[0] = SEP_DATA_POOL_POINTERS_VAL_TOKEN;
-	token_addr[1] = (u32)sep->shared_bus +
-		SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES +
-		sep->data_pool_bytes_allocated;
-
-	/* Write the memory back to the user space */
-	error = copy_to_user((void *)arg, (void *)&command_args,
-		sizeof(struct alloc_struct));
-	if (error) {
-		error = -EFAULT;
-		goto end_function;
-	}
-
-	/* Update the allocation */
-	sep->data_pool_bytes_allocated += command_args.num_bytes;
-	sep->num_of_data_allocations += 1;
-
-end_function:
-	return error;
-}
-
-/**
- *	sep_lock_kernel_pages - map kernel pages for DMA
- *	@sep: pointer to struct sep_device
- *	@kernel_virt_addr: address of data buffer in kernel
- *	@data_size: size of data
- *	@lli_array_ptr: lli array
- *	@in_out_flag: input into device or output from device
- *
- *	This function locks all the physical pages of the kernel virtual buffer
- *	and construct a basic lli  array, where each entry holds the physical
- *	page address and the size that application data holds in this page
- *	This function is used only during kernel crypto mod calls from within
- *	the kernel (when ioctl is not used)
- */
-static int sep_lock_kernel_pages(struct sep_device *sep,
-	unsigned long kernel_virt_addr,
-	u32 data_size,
-	struct sep_lli_entry **lli_array_ptr,
-	int in_out_flag)
-
-{
-	int error = 0;
-	/* Array of lli */
-	struct sep_lli_entry *lli_array;
-	/* Map array */
-	struct sep_dma_map *map_array;
-
-	dev_dbg(&sep->pdev->dev, "lock kernel pages kernel_virt_addr is %08lx\n",
-				(unsigned long)kernel_virt_addr);
-	dev_dbg(&sep->pdev->dev, "data_size is %x\n", data_size);
-
-	lli_array = kmalloc(sizeof(struct sep_lli_entry), GFP_ATOMIC);
-	if (!lli_array) {
-		error = -ENOMEM;
-		goto end_function;
-	}
-	map_array = kmalloc(sizeof(struct sep_dma_map), GFP_ATOMIC);
-	if (!map_array) {
-		error = -ENOMEM;
-		goto end_function_with_error;
-	}
-
-	map_array[0].dma_addr =
-		dma_map_single(&sep->pdev->dev, (void *)kernel_virt_addr,
-		data_size, DMA_BIDIRECTIONAL);
-	map_array[0].size = data_size;
-
-
-	/*
-	 * Set the start address of the first page - app data may start not at
-	 * the beginning of the page
-	 */
-	lli_array[0].bus_address = (u32)map_array[0].dma_addr;
-	lli_array[0].block_size = map_array[0].size;
-
-	dev_dbg(&sep->pdev->dev,
-	"lli_array[0].bus_address is %08lx, lli_array[0].block_size is %x\n",
-		(unsigned long)lli_array[0].bus_address,
-		lli_array[0].block_size);
-
-	/* Set the output parameters */
-	if (in_out_flag == SEP_DRIVER_IN_FLAG) {
-		*lli_array_ptr = lli_array;
-		sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = 1;
-		sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = NULL;
-		sep->dma_res_arr[sep->nr_dcb_creat].in_map_array = map_array;
-		sep->dma_res_arr[sep->nr_dcb_creat].in_map_num_entries = 1;
-	} else {
-		*lli_array_ptr = lli_array;
-		sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages = 1;
-		sep->dma_res_arr[sep->nr_dcb_creat].out_page_array = NULL;
-		sep->dma_res_arr[sep->nr_dcb_creat].out_map_array = map_array;
-		sep->dma_res_arr[sep->nr_dcb_creat].out_map_num_entries = 1;
-	}
-	goto end_function;
-
-end_function_with_error:
-	kfree(lli_array);
-
-end_function:
-	return error;
-}
-
-/**
- *	sep_lock_user_pages - lock and map user pages for DMA
- *	@sep: pointer to struct sep_device
- *	@app_virt_addr: user memory data buffer
- *	@data_size: size of data buffer
- *	@lli_array_ptr: lli array
- *	@in_out_flag: input or output to device
- *
- *	This function locks all the physical pages of the application
- *	virtual buffer and construct a basic lli  array, where each entry
- *	holds the physical page address and the size that application
- *	data holds in this physical pages
- */
-static int sep_lock_user_pages(struct sep_device *sep,
-	u32 app_virt_addr,
-	u32 data_size,
-	struct sep_lli_entry **lli_array_ptr,
-	int in_out_flag)
-
-{
-	int error = 0;
-	u32 count;
-	int result;
-	/* The the page of the end address of the user space buffer */
-	u32 end_page;
-	/* The page of the start address of the user space buffer */
-	u32 start_page;
-	/* The range in pages */
-	u32 num_pages;
-	/* Array of pointers to page */
-	struct page **page_array;
-	/* Array of lli */
-	struct sep_lli_entry *lli_array;
-	/* Map array */
-	struct sep_dma_map *map_array;
-	/* Direction of the DMA mapping for locked pages */
-	enum dma_data_direction	dir;
-
-	/* Set start and end pages  and num pages */
-	end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT;
-	start_page = app_virt_addr >> PAGE_SHIFT;
-	num_pages = end_page - start_page + 1;
-
-	dev_dbg(&sep->pdev->dev, "lock user pages app_virt_addr is %x\n", app_virt_addr);
-	dev_dbg(&sep->pdev->dev, "data_size is %x\n", data_size);
-	dev_dbg(&sep->pdev->dev, "start_page is %x\n", start_page);
-	dev_dbg(&sep->pdev->dev, "end_page is %x\n", end_page);
-	dev_dbg(&sep->pdev->dev, "num_pages is %x\n", num_pages);
-
-	/* Allocate array of pages structure pointers */
-	page_array = kmalloc(sizeof(struct page *) * num_pages, GFP_ATOMIC);
-	if (!page_array) {
-		error = -ENOMEM;
-		goto end_function;
-	}
-	map_array = kmalloc(sizeof(struct sep_dma_map) * num_pages, GFP_ATOMIC);
-	if (!map_array) {
-		dev_warn(&sep->pdev->dev, "kmalloc for map_array failed\n");
-		error = -ENOMEM;
-		goto end_function_with_error1;
-	}
-
-	lli_array = kmalloc(sizeof(struct sep_lli_entry) * num_pages,
-		GFP_ATOMIC);
-
-	if (!lli_array) {
-		dev_warn(&sep->pdev->dev, "kmalloc for lli_array failed\n");
-		error = -ENOMEM;
-		goto end_function_with_error2;
-	}
-
-	/* Convert the application virtual address into a set of physical */
-	down_read(&current->mm->mmap_sem);
-	result = get_user_pages(current, current->mm, app_virt_addr,
-		num_pages,
-		((in_out_flag == SEP_DRIVER_IN_FLAG) ? 0 : 1),
-		0, page_array, NULL);
-
-	up_read(&current->mm->mmap_sem);
-
-	/* Check the number of pages locked - if not all then exit with error */
-	if (result != num_pages) {
-		dev_warn(&sep->pdev->dev,
-			"not all pages locked by get_user_pages\n");
-		error = -ENOMEM;
-		goto end_function_with_error3;
-	}
-
-	dev_dbg(&sep->pdev->dev, "get_user_pages succeeded\n");
-
-	/* Set direction */
-	if (in_out_flag == SEP_DRIVER_IN_FLAG)
-		dir = DMA_TO_DEVICE;
-	else
-		dir = DMA_FROM_DEVICE;
-
-	/*
-	 * Fill the array using page array data and
-	 * map the pages - this action will also flush the cache as needed
-	 */
-	for (count = 0; count < num_pages; count++) {
-		/* Fill the map array */
-		map_array[count].dma_addr =
-			dma_map_page(&sep->pdev->dev, page_array[count],
-			0, PAGE_SIZE, /*dir*/DMA_BIDIRECTIONAL);
-
-		map_array[count].size = PAGE_SIZE;
-
-		/* Fill the lli array entry */
-		lli_array[count].bus_address = (u32)map_array[count].dma_addr;
-		lli_array[count].block_size = PAGE_SIZE;
-
-		dev_warn(&sep->pdev->dev, "lli_array[%x].bus_address is %08lx, lli_array[%x].block_size is %x\n",
-			count, (unsigned long)lli_array[count].bus_address,
-			count, lli_array[count].block_size);
-	}
-
-	/* Check the offset for the first page */
-	lli_array[0].bus_address =
-		lli_array[0].bus_address + (app_virt_addr & (~PAGE_MASK));
-
-	/* Check that not all the data is in the first page only */
-	if ((PAGE_SIZE - (app_virt_addr & (~PAGE_MASK))) >= data_size)
-		lli_array[0].block_size = data_size;
-	else
-		lli_array[0].block_size =
-			PAGE_SIZE - (app_virt_addr & (~PAGE_MASK));
-
-	dev_dbg(&sep->pdev->dev,
-		"lli_array[0].bus_address is %08lx, lli_array[0].block_size is %x\n",
-		(unsigned long)lli_array[count].bus_address,
-		lli_array[count].block_size);
-
-	/* Check the size of the last page */
-	if (num_pages > 1) {
-		lli_array[num_pages - 1].block_size =
-			(app_virt_addr + data_size) & (~PAGE_MASK);
-		if (lli_array[num_pages - 1].block_size == 0)
-			lli_array[num_pages - 1].block_size = PAGE_SIZE;
-
-		dev_warn(&sep->pdev->dev,
-			"lli_array[%x].bus_address is "
-			"%08lx, lli_array[%x].block_size is %x\n",
-			num_pages - 1,
-			(unsigned long)lli_array[num_pages - 1].bus_address,
-			num_pages - 1,
-			lli_array[num_pages - 1].block_size);
-	}
-
-	/* Set output params according to the in_out flag */
-	if (in_out_flag == SEP_DRIVER_IN_FLAG) {
-		*lli_array_ptr = lli_array;
-		sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = num_pages;
-		sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = page_array;
-		sep->dma_res_arr[sep->nr_dcb_creat].in_map_array = map_array;
-		sep->dma_res_arr[sep->nr_dcb_creat].in_map_num_entries =
-								num_pages;
-	} else {
-		*lli_array_ptr = lli_array;
-		sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages = num_pages;
-		sep->dma_res_arr[sep->nr_dcb_creat].out_page_array =
-								page_array;
-		sep->dma_res_arr[sep->nr_dcb_creat].out_map_array = map_array;
-		sep->dma_res_arr[sep->nr_dcb_creat].out_map_num_entries =
-								num_pages;
-	}
-	goto end_function;
-
-end_function_with_error3:
-	/* Free lli array */
-	kfree(lli_array);
-
-end_function_with_error2:
-	kfree(map_array);
-
-end_function_with_error1:
-	/* Free page array */
-	kfree(page_array);
-
-end_function:
-	return error;
-}
-
-/**
- *	u32 sep_calculate_lli_table_max_size - size the LLI table
- *	@sep: pointer to struct sep_device
- *	@lli_in_array_ptr
- *	@num_array_entries
- *	@last_table_flag
- *
- *	This function calculates the size of data that can be inserted into
- *	the lli table from this array, such that either the table is full
- *	(all entries are entered), or there are no more entries in the
- *	lli array
- */
-static u32 sep_calculate_lli_table_max_size(struct sep_device *sep,
-	struct sep_lli_entry *lli_in_array_ptr,
-	u32 num_array_entries,
-	u32 *last_table_flag)
-{
-	u32 counter;
-	/* Table data size */
-	u32 table_data_size = 0;
-	/* Data size for the next table */
-	u32 next_table_data_size;
-
-	*last_table_flag = 0;
-
-	/*
-	 * Calculate the data in the out lli table till we fill the whole
-	 * table or till the data has ended
-	 */
-	for (counter = 0;
-		(counter < (SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP - 1)) &&
-			(counter < num_array_entries); counter++)
-		table_data_size += lli_in_array_ptr[counter].block_size;
-
-	/*
-	 * Check if we reached the last entry,
-	 * meaning this ia the last table to build,
-	 * and no need to check the block alignment
-	 */
-	if (counter == num_array_entries) {
-		/* Set the last table flag */
-		*last_table_flag = 1;
-		goto end_function;
-	}
-
-	/*
-	 * Calculate the data size of the next table.
-	 * Stop if no entries left or if data size is more the DMA restriction
-	 */
-	next_table_data_size = 0;
-	for (; counter < num_array_entries; counter++) {
-		next_table_data_size += lli_in_array_ptr[counter].block_size;
-		if (next_table_data_size >= SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE)
-			break;
-	}
-
-	/*
-	 * Check if the next table data size is less then DMA rstriction.
-	 * if it is - recalculate the current table size, so that the next
-	 * table data size will be adaquete for DMA
-	 */
-	if (next_table_data_size &&
-		next_table_data_size < SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE)
-
-		table_data_size -= (SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE -
-			next_table_data_size);
-
-end_function:
-	return table_data_size;
-}
-
-/**
- *	sep_build_lli_table - build an lli array for the given table
- *	@sep: pointer to struct sep_device
- *	@lli_array_ptr: pointer to lli array
- *	@lli_table_ptr: pointer to lli table
- *	@num_processed_entries_ptr: pointer to number of entries
- *	@num_table_entries_ptr: pointer to number of tables
- *	@table_data_size: total data size
- *
- *	Builds ant lli table from the lli_array according to
- *	the given size of data
- */
-static void sep_build_lli_table(struct sep_device *sep,
-	struct sep_lli_entry	*lli_array_ptr,
-	struct sep_lli_entry	*lli_table_ptr,
-	u32 *num_processed_entries_ptr,
-	u32 *num_table_entries_ptr,
-	u32 table_data_size)
-{
-	/* Current table data size */
-	u32 curr_table_data_size;
-	/* Counter of lli array entry */
-	u32 array_counter;
-
-	/* Init current table data size and lli array entry counter */
-	curr_table_data_size = 0;
-	array_counter = 0;
-	*num_table_entries_ptr = 1;
-
-	dev_dbg(&sep->pdev->dev, "build lli table table_data_size is %x\n", table_data_size);
-
-	/* Fill the table till table size reaches the needed amount */
-	while (curr_table_data_size < table_data_size) {
-		/* Update the number of entries in table */
-		(*num_table_entries_ptr)++;
-
-		lli_table_ptr->bus_address =
-			cpu_to_le32(lli_array_ptr[array_counter].bus_address);
-
-		lli_table_ptr->block_size =
-			cpu_to_le32(lli_array_ptr[array_counter].block_size);
-
-		curr_table_data_size += lli_array_ptr[array_counter].block_size;
-
-		dev_dbg(&sep->pdev->dev, "lli_table_ptr is %p\n",
-								lli_table_ptr);
-		dev_dbg(&sep->pdev->dev, "lli_table_ptr->bus_address is %08lx\n",
-				(unsigned long)lli_table_ptr->bus_address);
-		dev_dbg(&sep->pdev->dev, "lli_table_ptr->block_size is %x\n",
-			lli_table_ptr->block_size);
-
-		/* Check for overflow of the table data */
-		if (curr_table_data_size > table_data_size) {
-			dev_dbg(&sep->pdev->dev,
-				"curr_table_data_size too large\n");
-
-			/* Update the size of block in the table */
-			lli_table_ptr->block_size -=
-			cpu_to_le32((curr_table_data_size - table_data_size));
-
-			/* Update the physical address in the lli array */
-			lli_array_ptr[array_counter].bus_address +=
-			cpu_to_le32(lli_table_ptr->block_size);
-
-			/* Update the block size left in the lli array */
-			lli_array_ptr[array_counter].block_size =
-				(curr_table_data_size - table_data_size);
-		} else
-			/* Advance to the next entry in the lli_array */
-			array_counter++;
-
-		dev_dbg(&sep->pdev->dev,
-			"lli_table_ptr->bus_address is %08lx\n",
-				(unsigned long)lli_table_ptr->bus_address);
-		dev_dbg(&sep->pdev->dev,
-			"lli_table_ptr->block_size is %x\n",
-			lli_table_ptr->block_size);
-
-		/* Move to the next entry in table */
-		lli_table_ptr++;
-	}
-
-	/* Set the info entry to default */
-	lli_table_ptr->bus_address = 0xffffffff;
-	lli_table_ptr->block_size = 0;
-
-	/* Set the output parameter */
-	*num_processed_entries_ptr += array_counter;
-
-}
-
-/**
- *	sep_shared_area_virt_to_bus - map shared area to bus address
- *	@sep: pointer to struct sep_device
- *	@virt_address: virtual address to convert
- *
- *	This functions returns the physical address inside shared area according
- *	to the virtual address. It can be either on the externa RAM device
- *	(ioremapped), or on the system RAM
- *	This implementation is for the external RAM
- */
-static dma_addr_t sep_shared_area_virt_to_bus(struct sep_device *sep,
-	void *virt_address)
-{
-	dev_dbg(&sep->pdev->dev, "sh virt to phys v %p\n", virt_address);
-	dev_dbg(&sep->pdev->dev, "sh virt to phys p %08lx\n",
-		(unsigned long)
-		sep->shared_bus + (virt_address - sep->shared_addr));
-
-	return sep->shared_bus + (size_t)(virt_address - sep->shared_addr);
-}
-
-/**
- *	sep_shared_area_bus_to_virt - map shared area bus address to kernel
- *	@sep: pointer to struct sep_device
- *	@bus_address: bus address to convert
- *
- *	This functions returns the virtual address inside shared area
- *	according to the physical address. It can be either on the
- *	externa RAM device (ioremapped), or on the system RAM
- *	This implementation is for the external RAM
- */
-static void *sep_shared_area_bus_to_virt(struct sep_device *sep,
-	dma_addr_t bus_address)
-{
-	dev_dbg(&sep->pdev->dev, "shared bus to virt b=%lx v=%lx\n",
-		(unsigned long)bus_address, (unsigned long)(sep->shared_addr +
-			(size_t)(bus_address - sep->shared_bus)));
-
-	return sep->shared_addr	+ (size_t)(bus_address - sep->shared_bus);
-}
-
-/**
- *	sep_debug_print_lli_tables - dump LLI table
- *	@sep: pointer to struct sep_device
- *	@lli_table_ptr: pointer to sep_lli_entry
- *	@num_table_entries: number of entries
- *	@table_data_size: total data size
- *
- *	Walk the the list of the print created tables and print all the data
- */
-static void sep_debug_print_lli_tables(struct sep_device *sep,
-	struct sep_lli_entry *lli_table_ptr,
-	unsigned long num_table_entries,
-	unsigned long table_data_size)
-{
-	unsigned long table_count = 1;
-	unsigned long entries_count = 0;
-
-	dev_dbg(&sep->pdev->dev, "sep_debug_print_lli_tables start\n");
-
-	while ((unsigned long) lli_table_ptr->bus_address != 0xffffffff) {
-		dev_dbg(&sep->pdev->dev,
-			"lli table %08lx, table_data_size is %lu\n",
-			table_count, table_data_size);
-		dev_dbg(&sep->pdev->dev, "num_table_entries is %lu\n",
-							num_table_entries);
-
-		/* Print entries of the table (without info entry) */
-		for (entries_count = 0; entries_count < num_table_entries;
-			entries_count++, lli_table_ptr++) {
-
-			dev_dbg(&sep->pdev->dev,
-				"lli_table_ptr address is %08lx\n",
-				(unsigned long) lli_table_ptr);
-
-			dev_dbg(&sep->pdev->dev,
-				"phys address is %08lx block size is %x\n",
-				(unsigned long)lli_table_ptr->bus_address,
-				lli_table_ptr->block_size);
-		}
-		/* Point to the info entry */
-		lli_table_ptr--;
-
-		dev_dbg(&sep->pdev->dev,
-			"phys lli_table_ptr->block_size is %x\n",
-			lli_table_ptr->block_size);
-
-		dev_dbg(&sep->pdev->dev,
-			"phys lli_table_ptr->physical_address is %08lu\n",
-			(unsigned long)lli_table_ptr->bus_address);
-
-
-		table_data_size = lli_table_ptr->block_size & 0xffffff;
-		num_table_entries = (lli_table_ptr->block_size >> 24) & 0xff;
-
-		dev_dbg(&sep->pdev->dev,
-			"phys table_data_size is %lu num_table_entries is"
-			" %lu bus_address is%lu\n", table_data_size,
-			num_table_entries, (unsigned long)lli_table_ptr->bus_address);
-
-		if ((unsigned long)lli_table_ptr->bus_address != 0xffffffff)
-			lli_table_ptr = (struct sep_lli_entry *)
-				sep_shared_bus_to_virt(sep,
-				(unsigned long)lli_table_ptr->bus_address);
-
-		table_count++;
-	}
-	dev_dbg(&sep->pdev->dev, "sep_debug_print_lli_tables end\n");
-}
-
-
-/**
- *	sep_prepare_empty_lli_table - create a blank LLI table
- *	@sep: pointer to struct sep_device
- *	@lli_table_addr_ptr: pointer to lli table
- *	@num_entries_ptr: pointer to number of entries
- *	@table_data_size_ptr: point to table data size
- *
- *	This function creates empty lli tables when there is no data
- */
-static void sep_prepare_empty_lli_table(struct sep_device *sep,
-		dma_addr_t *lli_table_addr_ptr,
-		u32 *num_entries_ptr,
-		u32 *table_data_size_ptr)
-{
-	struct sep_lli_entry *lli_table_ptr;
-
-	/* Find the area for new table */
-	lli_table_ptr =
-		(struct sep_lli_entry *)(sep->shared_addr +
-		SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
-		sep->num_lli_tables_created * sizeof(struct sep_lli_entry) *
-			SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP);
-
-	lli_table_ptr->bus_address = 0;
-	lli_table_ptr->block_size = 0;
-
-	lli_table_ptr++;
-	lli_table_ptr->bus_address = 0xFFFFFFFF;
-	lli_table_ptr->block_size = 0;
-
-	/* Set the output parameter value */
-	*lli_table_addr_ptr = sep->shared_bus +
-		SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
-		sep->num_lli_tables_created *
-		sizeof(struct sep_lli_entry) *
-		SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
-
-	/* Set the num of entries and table data size for empty table */
-	*num_entries_ptr = 2;
-	*table_data_size_ptr = 0;
-
-	/* Update the number of created tables */
-	sep->num_lli_tables_created++;
-}
-
-/**
- *	sep_prepare_input_dma_table - prepare input DMA mappings
- *	@sep: pointer to struct sep_device
- *	@data_size:
- *	@block_size:
- *	@lli_table_ptr:
- *	@num_entries_ptr:
- *	@table_data_size_ptr:
- *	@is_kva: set for kernel data (kernel cryptio call)
- *
- *	This function prepares only input DMA table for synhronic symmetric
- *	operations (HASH)
- *	Note that all bus addresses that are passed to the SEP
- *	are in 32 bit format; the SEP is a 32 bit device
- */
-static int sep_prepare_input_dma_table(struct sep_device *sep,
-	unsigned long app_virt_addr,
-	u32 data_size,
-	u32 block_size,
-	dma_addr_t *lli_table_ptr,
-	u32 *num_entries_ptr,
-	u32 *table_data_size_ptr,
-	bool is_kva)
-{
-	int error = 0;
-	/* Pointer to the info entry of the table - the last entry */
-	struct sep_lli_entry *info_entry_ptr;
-	/* Array of pointers to page */
-	struct sep_lli_entry *lli_array_ptr;
-	/* Points to the first entry to be processed in the lli_in_array */
-	u32 current_entry = 0;
-	/* Num entries in the virtual buffer */
-	u32 sep_lli_entries = 0;
-	/* Lli table pointer */
-	struct sep_lli_entry *in_lli_table_ptr;
-	/* The total data in one table */
-	u32 table_data_size = 0;
-	/* Flag for last table */
-	u32 last_table_flag = 0;
-	/* Number of entries in lli table */
-	u32 num_entries_in_table = 0;
-	/* Next table address */
-	void *lli_table_alloc_addr = 0;
-
-	dev_dbg(&sep->pdev->dev, "prepare intput dma table data_size is %x\n", data_size);
-	dev_dbg(&sep->pdev->dev, "block_size is %x\n", block_size);
-
-	/* Initialize the pages pointers */
-	sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = NULL;
-	sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = 0;
-
-	/* Set the kernel address for first table to be allocated */
-	lli_table_alloc_addr = (void *)(sep->shared_addr +
-		SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
-		sep->num_lli_tables_created * sizeof(struct sep_lli_entry) *
-		SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP);
-
-	if (data_size == 0) {
-		/* Special case  - create meptu table - 2 entries, zero data */
-		sep_prepare_empty_lli_table(sep, lli_table_ptr,
-				num_entries_ptr, table_data_size_ptr);
-		goto update_dcb_counter;
-	}
-
-	/* Check if the pages are in Kernel Virtual Address layout */
-	if (is_kva == true)
-		/* Lock the pages in the kernel */
-		error = sep_lock_kernel_pages(sep, app_virt_addr,
-			data_size, &lli_array_ptr, SEP_DRIVER_IN_FLAG);
-	else
-		/*
-		 * Lock the pages of the user buffer
-		 * and translate them to pages
-		 */
-		error = sep_lock_user_pages(sep, app_virt_addr,
-			data_size, &lli_array_ptr, SEP_DRIVER_IN_FLAG);
-
-	if (error)
-		goto end_function;
-
-	dev_dbg(&sep->pdev->dev, "output sep_in_num_pages is %x\n",
-		sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages);
-
-	current_entry = 0;
-	info_entry_ptr = NULL;
-
-	sep_lli_entries = sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages;
-
-	/* Loop till all the entries in in array are not processed */
-	while (current_entry < sep_lli_entries) {
-
-		/* Set the new input and output tables */
-		in_lli_table_ptr =
-			(struct sep_lli_entry *)lli_table_alloc_addr;
-
-		lli_table_alloc_addr += sizeof(struct sep_lli_entry) *
-			SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
-
-		if (lli_table_alloc_addr >
-			((void *)sep->shared_addr +
-			SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
-			SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES)) {
-
-			error = -ENOMEM;
-			goto end_function_error;
-
-		}
-
-		/* Update the number of created tables */
-		sep->num_lli_tables_created++;
-
-		/* Calculate the maximum size of data for input table */
-		table_data_size = sep_calculate_lli_table_max_size(sep,
-			&lli_array_ptr[current_entry],
-			(sep_lli_entries - current_entry),
-			&last_table_flag);
-
-		/*
-		 * If this is not the last table -
-		 * then align it to the block size
-		 */
-		if (!last_table_flag)
-			table_data_size =
-				(table_data_size / block_size) * block_size;
-
-		dev_dbg(&sep->pdev->dev, "output table_data_size is %x\n",
-							table_data_size);
-
-		/* Construct input lli table */
-		sep_build_lli_table(sep, &lli_array_ptr[current_entry],
-			in_lli_table_ptr,
-			&current_entry, &num_entries_in_table, table_data_size);
-
-		if (info_entry_ptr == NULL) {
-
-			/* Set the output parameters to physical addresses */
-			*lli_table_ptr = sep_shared_area_virt_to_bus(sep,
-				in_lli_table_ptr);
-			*num_entries_ptr = num_entries_in_table;
-			*table_data_size_ptr = table_data_size;
-
-			dev_dbg(&sep->pdev->dev,
-				"output lli_table_in_ptr is %08lx\n",
-				(unsigned long)*lli_table_ptr);
-
-		} else {
-			/* Update the info entry of the previous in table */
-			info_entry_ptr->bus_address =
-				sep_shared_area_virt_to_bus(sep,
-							in_lli_table_ptr);
-			info_entry_ptr->block_size =
-				((num_entries_in_table) << 24) |
-				(table_data_size);
-		}
-		/* Save the pointer to the info entry of the current tables */
-		info_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1;
-	}
-	/* Print input tables */
-	sep_debug_print_lli_tables(sep, (struct sep_lli_entry *)
-		sep_shared_area_bus_to_virt(sep, *lli_table_ptr),
-		*num_entries_ptr, *table_data_size_ptr);
-	/* The array of the pages */
-	kfree(lli_array_ptr);
-
-update_dcb_counter:
-	/* Update DCB counter */
-	sep->nr_dcb_creat++;
-	goto end_function;
-
-end_function_error:
-	/* Free all the allocated resources */
-	kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_map_array);
-	kfree(lli_array_ptr);
-	kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_page_array);
-
-end_function:
-	return error;
-
-}
-/**
- *	sep_construct_dma_tables_from_lli - prepare AES/DES mappings
- *	@sep: pointer to struct sep_device
- *	@lli_in_array:
- *	@sep_in_lli_entries:
- *	@lli_out_array:
- *	@sep_out_lli_entries
- *	@block_size
- *	@lli_table_in_ptr
- *	@lli_table_out_ptr
- *	@in_num_entries_ptr
- *	@out_num_entries_ptr
- *	@table_data_size_ptr
- *
- *	This function creates the input and output DMA tables for
- *	symmetric operations (AES/DES) according to the block
- *	size from LLI arays
- *	Note that all bus addresses that are passed to the SEP
- *	are in 32 bit format; the SEP is a 32 bit device
- */
-static int sep_construct_dma_tables_from_lli(
-	struct sep_device *sep,
-	struct sep_lli_entry *lli_in_array,
-	u32	sep_in_lli_entries,
-	struct sep_lli_entry *lli_out_array,
-	u32	sep_out_lli_entries,
-	u32	block_size,
-	dma_addr_t *lli_table_in_ptr,
-	dma_addr_t *lli_table_out_ptr,
-	u32	*in_num_entries_ptr,
-	u32	*out_num_entries_ptr,
-	u32	*table_data_size_ptr)
-{
-	/* Points to the area where next lli table can be allocated */
-	void *lli_table_alloc_addr = 0;
-	/* Input lli table */
-	struct sep_lli_entry *in_lli_table_ptr = NULL;
-	/* Output lli table */
-	struct sep_lli_entry *out_lli_table_ptr = NULL;
-	/* Pointer to the info entry of the table - the last entry */
-	struct sep_lli_entry *info_in_entry_ptr = NULL;
-	/* Pointer to the info entry of the table - the last entry */
-	struct sep_lli_entry *info_out_entry_ptr = NULL;
-	/* Points to the first entry to be processed in the lli_in_array */
-	u32 current_in_entry = 0;
-	/* Points to the first entry to be processed in the lli_out_array */
-	u32 current_out_entry = 0;
-	/* Max size of the input table */
-	u32 in_table_data_size = 0;
-	/* Max size of the output table */
-	u32 out_table_data_size = 0;
-	/* Flag te signifies if this is the last tables build */
-	u32 last_table_flag = 0;
-	/* The data size that should be in table */
-	u32 table_data_size = 0;
-	/* Number of etnries in the input table */
-	u32 num_entries_in_table = 0;
-	/* Number of etnries in the output table */
-	u32 num_entries_out_table = 0;
-
-	/* Initiate to point after the message area */
-	lli_table_alloc_addr = (void *)(sep->shared_addr +
-		SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
-		(sep->num_lli_tables_created *
-		(sizeof(struct sep_lli_entry) *
-		SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP)));
-
-	/* Loop till all the entries in in array are not processed */
-	while (current_in_entry < sep_in_lli_entries) {
-		/* Set the new input and output tables */
-		in_lli_table_ptr =
-			(struct sep_lli_entry *)lli_table_alloc_addr;
-
-		lli_table_alloc_addr += sizeof(struct sep_lli_entry) *
-			SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
-
-		/* Set the first output tables */
-		out_lli_table_ptr =
-			(struct sep_lli_entry *)lli_table_alloc_addr;
-
-		/* Check if the DMA table area limit was overrun */
-		if ((lli_table_alloc_addr + sizeof(struct sep_lli_entry) *
-			SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP) >
-			((void *)sep->shared_addr +
-			SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
-			SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES)) {
-
-			dev_warn(&sep->pdev->dev, "dma table limit overrun\n");
-			return -ENOMEM;
-		}
-
-		/* Update the number of the lli tables created */
-		sep->num_lli_tables_created += 2;
-
-		lli_table_alloc_addr += sizeof(struct sep_lli_entry) *
-			SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
-
-		/* Calculate the maximum size of data for input table */
-		in_table_data_size =
-			sep_calculate_lli_table_max_size(sep,
-			&lli_in_array[current_in_entry],
-			(sep_in_lli_entries - current_in_entry),
-			&last_table_flag);
-
-		/* Calculate the maximum size of data for output table */
-		out_table_data_size =
-			sep_calculate_lli_table_max_size(sep,
-			&lli_out_array[current_out_entry],
-			(sep_out_lli_entries - current_out_entry),
-			&last_table_flag);
-
-		dev_dbg(&sep->pdev->dev,
-			"construct tables from lli in_table_data_size is %x\n",
-			in_table_data_size);
-
-		dev_dbg(&sep->pdev->dev,
-			"construct tables from lli out_table_data_size is %x\n",
-			out_table_data_size);
-
-		table_data_size = in_table_data_size;
-
-		if (!last_table_flag) {
-			/*
-			 * If this is not the last table,
-			 * then must check where the data is smallest
-			 * and then align it to the block size
-			 */
-			if (table_data_size > out_table_data_size)
-				table_data_size = out_table_data_size;
-
-			/*
-			 * Now calculate the table size so that
-			 * it will be module block size
-			 */
-			table_data_size = (table_data_size / block_size) *
-				block_size;
-		}
-
-		/* Construct input lli table */
-		sep_build_lli_table(sep, &lli_in_array[current_in_entry],
-			in_lli_table_ptr,
-			&current_in_entry,
-			&num_entries_in_table,
-			table_data_size);
-
-		/* Construct output lli table */
-		sep_build_lli_table(sep, &lli_out_array[current_out_entry],
-			out_lli_table_ptr,
-			&current_out_entry,
-			&num_entries_out_table,
-			table_data_size);
-
-		/* If info entry is null - this is the first table built */
-		if (info_in_entry_ptr == NULL) {
-			/* Set the output parameters to physical addresses */
-			*lli_table_in_ptr =
-			sep_shared_area_virt_to_bus(sep, in_lli_table_ptr);
-
-			*in_num_entries_ptr = num_entries_in_table;
-
-			*lli_table_out_ptr =
-				sep_shared_area_virt_to_bus(sep,
-				out_lli_table_ptr);
-
-			*out_num_entries_ptr = num_entries_out_table;
-			*table_data_size_ptr = table_data_size;
-
-			dev_dbg(&sep->pdev->dev,
-			"output lli_table_in_ptr is %08lx\n",
-				(unsigned long)*lli_table_in_ptr);
-			dev_dbg(&sep->pdev->dev,
-			"output lli_table_out_ptr is %08lx\n",
-				(unsigned long)*lli_table_out_ptr);
-		} else {
-			/* Update the info entry of the previous in table */
-			info_in_entry_ptr->bus_address =
-				sep_shared_area_virt_to_bus(sep,
-				in_lli_table_ptr);
-
-			info_in_entry_ptr->block_size =
-				((num_entries_in_table) << 24) |
-				(table_data_size);
-
-			/* Update the info entry of the previous in table */
-			info_out_entry_ptr->bus_address =
-				sep_shared_area_virt_to_bus(sep,
-				out_lli_table_ptr);
-
-			info_out_entry_ptr->block_size =
-				((num_entries_out_table) << 24) |
-				(table_data_size);
-
-			dev_dbg(&sep->pdev->dev,
-				"output lli_table_in_ptr:%08lx %08x\n",
-				(unsigned long)info_in_entry_ptr->bus_address,
-				info_in_entry_ptr->block_size);
-
-			dev_dbg(&sep->pdev->dev,
-				"output lli_table_out_ptr:%08lx  %08x\n",
-				(unsigned long)info_out_entry_ptr->bus_address,
-				info_out_entry_ptr->block_size);
-		}
-
-		/* Save the pointer to the info entry of the current tables */
-		info_in_entry_ptr = in_lli_table_ptr +
-			num_entries_in_table - 1;
-		info_out_entry_ptr = out_lli_table_ptr +
-			num_entries_out_table - 1;
-
-		dev_dbg(&sep->pdev->dev,
-			"output num_entries_out_table is %x\n",
-			(u32)num_entries_out_table);
-		dev_dbg(&sep->pdev->dev,
-			"output info_in_entry_ptr is %lx\n",
-			(unsigned long)info_in_entry_ptr);
-		dev_dbg(&sep->pdev->dev,
-			"output info_out_entry_ptr is %lx\n",
-			(unsigned long)info_out_entry_ptr);
-	}
-
-	/* Print input tables */
-	sep_debug_print_lli_tables(sep,
-	(struct sep_lli_entry *)
-	sep_shared_area_bus_to_virt(sep, *lli_table_in_ptr),
-	*in_num_entries_ptr,
-	*table_data_size_ptr);
-
-	/* Print output tables */
-	sep_debug_print_lli_tables(sep,
-	(struct sep_lli_entry *)
-	sep_shared_area_bus_to_virt(sep, *lli_table_out_ptr),
-	*out_num_entries_ptr,
-	*table_data_size_ptr);
-
-	return 0;
-}
-
-/**
- *	sep_prepare_input_output_dma_table - prepare DMA I/O table
- *	@app_virt_in_addr:
- *	@app_virt_out_addr:
- *	@data_size:
- *	@block_size:
- *	@lli_table_in_ptr:
- *	@lli_table_out_ptr:
- *	@in_num_entries_ptr:
- *	@out_num_entries_ptr:
- *	@table_data_size_ptr:
- *	@is_kva: set for kernel data; used only for kernel crypto module
- *
- *	This function builds input and output DMA tables for synhronic
- *	symmetric operations (AES, DES, HASH). It also checks that each table
- *	is of the modular block size
- *	Note that all bus addresses that are passed to the SEP
- *	are in 32 bit format; the SEP is a 32 bit device
- */
-static int sep_prepare_input_output_dma_table(struct sep_device *sep,
-	unsigned long app_virt_in_addr,
-	unsigned long app_virt_out_addr,
-	u32 data_size,
-	u32 block_size,
-	dma_addr_t *lli_table_in_ptr,
-	dma_addr_t *lli_table_out_ptr,
-	u32 *in_num_entries_ptr,
-	u32 *out_num_entries_ptr,
-	u32 *table_data_size_ptr,
-	bool is_kva)
-
-{
-	int error = 0;
-	/* Array of pointers of page */
-	struct sep_lli_entry *lli_in_array;
-	/* Array of pointers of page */
-	struct sep_lli_entry *lli_out_array;
-
-	if (data_size == 0) {
-		/* Prepare empty table for input and output */
-		sep_prepare_empty_lli_table(sep, lli_table_in_ptr,
-			in_num_entries_ptr, table_data_size_ptr);
-
-		sep_prepare_empty_lli_table(sep, lli_table_out_ptr,
-			out_num_entries_ptr, table_data_size_ptr);
-
-		goto update_dcb_counter;
-	}
-
-	/* Initialize the pages pointers */
-	sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = NULL;
-	sep->dma_res_arr[sep->nr_dcb_creat].out_page_array = NULL;
-
-	/* Lock the pages of the buffer and translate them to pages */
-	if (is_kva == true) {
-		error = sep_lock_kernel_pages(sep, app_virt_in_addr,
-			data_size, &lli_in_array, SEP_DRIVER_IN_FLAG);
-
-		if (error) {
-			dev_warn(&sep->pdev->dev,
-				"lock kernel for in failed\n");
-			goto end_function;
-		}
-
-		error = sep_lock_kernel_pages(sep, app_virt_out_addr,
-			data_size, &lli_out_array, SEP_DRIVER_OUT_FLAG);
-
-		if (error) {
-			dev_warn(&sep->pdev->dev,
-				"lock kernel for out failed\n");
-			goto end_function;
-		}
-	}
-
-	else {
-		error = sep_lock_user_pages(sep, app_virt_in_addr,
-				data_size, &lli_in_array, SEP_DRIVER_IN_FLAG);
-		if (error) {
-			dev_warn(&sep->pdev->dev,
-				"sep_lock_user_pages for input virtual buffer failed\n");
-			goto end_function;
-		}
-
-		error = sep_lock_user_pages(sep, app_virt_out_addr,
-			data_size, &lli_out_array, SEP_DRIVER_OUT_FLAG);
-
-		if (error) {
-			dev_warn(&sep->pdev->dev,
-				"sep_lock_user_pages for output virtual buffer failed\n");
-			goto end_function_free_lli_in;
-		}
-	}
-
-	dev_dbg(&sep->pdev->dev, "prep input output dma table sep_in_num_pages is %x\n",
-		sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages);
-	dev_dbg(&sep->pdev->dev, "sep_out_num_pages is %x\n",
-		sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages);
-	dev_dbg(&sep->pdev->dev, "SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP is %x\n",
-		SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP);
-
-	/* Call the function that creates table from the lli arrays */
-	error = sep_construct_dma_tables_from_lli(sep, lli_in_array,
-		sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages,
-		lli_out_array,
-		sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages,
-		block_size, lli_table_in_ptr, lli_table_out_ptr,
-		in_num_entries_ptr, out_num_entries_ptr, table_data_size_ptr);
-
-	if (error) {
-		dev_warn(&sep->pdev->dev,
-			"sep_construct_dma_tables_from_lli failed\n");
-		goto end_function_with_error;
-	}
-
-	kfree(lli_out_array);
-	kfree(lli_in_array);
-
-update_dcb_counter:
-	/* Update DCB counter */
-	sep->nr_dcb_creat++;
-
-	goto end_function;
-
-end_function_with_error:
-	kfree(sep->dma_res_arr[sep->nr_dcb_creat].out_map_array);
-	kfree(sep->dma_res_arr[sep->nr_dcb_creat].out_page_array);
-	kfree(lli_out_array);
-
-
-end_function_free_lli_in:
-	kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_map_array);
-	kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_page_array);
-	kfree(lli_in_array);
-
-end_function:
-
-	return error;
-
-}
-
-/**
- *	sep_prepare_input_output_dma_table_in_dcb - prepare control blocks
- *	@app_in_address: unsigned long; for data buffer in (user space)
- *	@app_out_address: unsigned long; for data buffer out (user space)
- *	@data_in_size: u32; for size of data
- *	@block_size: u32; for block size
- *	@tail_block_size: u32; for size of tail block
- *	@isapplet: bool; to indicate external app
- *	@is_kva: bool; kernel buffer; only used for kernel crypto module
- *
- *	This function prepares the linked DMA tables and puts the
- *	address for the linked list of tables inta a DCB (data control
- *	block) the address of which is known by the SEP hardware
- *	Note that all bus addresses that are passed to the SEP
- *	are in 32 bit format; the SEP is a 32 bit device
- */
-static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep,
-	unsigned long  app_in_address,
-	unsigned long  app_out_address,
-	u32  data_in_size,
-	u32  block_size,
-	u32  tail_block_size,
-	bool isapplet,
-	bool	is_kva)
-{
-	int error = 0;
-	/* Size of tail */
-	u32 tail_size = 0;
-	/* Address of the created DCB table */
-	struct sep_dcblock *dcb_table_ptr = NULL;
-	/* The physical address of the first input DMA table */
-	dma_addr_t in_first_mlli_address = 0;
-	/* Number of entries in the first input DMA table */
-	u32  in_first_num_entries = 0;
-	/* The physical address of the first output DMA table */
-	dma_addr_t  out_first_mlli_address = 0;
-	/* Number of entries in the first output DMA table */
-	u32  out_first_num_entries = 0;
-	/* Data in the first input/output table */
-	u32  first_data_size = 0;
-
-	if (sep->nr_dcb_creat == SEP_MAX_NUM_SYNC_DMA_OPS) {
-		/* No more DCBs to allocate */
-		dev_warn(&sep->pdev->dev, "no more DCBs available\n");
-		error = -ENOSPC;
-		goto end_function;
-	}
-
-	/* Allocate new DCB */
-	dcb_table_ptr = (struct sep_dcblock *)(sep->shared_addr +
-		SEP_DRIVER_SYSTEM_DCB_MEMORY_OFFSET_IN_BYTES +
-		(sep->nr_dcb_creat * sizeof(struct sep_dcblock)));
-
-	/* Set the default values in the DCB */
-	dcb_table_ptr->input_mlli_address = 0;
-	dcb_table_ptr->input_mlli_num_entries = 0;
-	dcb_table_ptr->input_mlli_data_size = 0;
-	dcb_table_ptr->output_mlli_address = 0;
-	dcb_table_ptr->output_mlli_num_entries = 0;
-	dcb_table_ptr->output_mlli_data_size = 0;
-	dcb_table_ptr->tail_data_size = 0;
-	dcb_table_ptr->out_vr_tail_pt = 0;
-
-	if (isapplet == true) {
-
-		/* Check if there is enough data for DMA operation */
-		if (data_in_size < SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE) {
-			if (is_kva == true) {
-				memcpy(dcb_table_ptr->tail_data,
-					(void *)app_in_address, data_in_size);
-			} else {
-				if (copy_from_user(dcb_table_ptr->tail_data,
-					(void __user *)app_in_address,
-					data_in_size)) {
-					error = -EFAULT;
-					goto end_function;
-				}
-			}
-
-			dcb_table_ptr->tail_data_size = data_in_size;
-
-			/* Set the output user-space address for mem2mem op */
-			if (app_out_address)
-				dcb_table_ptr->out_vr_tail_pt =
-							(aligned_u64)app_out_address;
-
-			/*
-			 * Update both data length parameters in order to avoid
-			 * second data copy and allow building of empty mlli
-			 * tables
-			 */
-			tail_size = 0x0;
-			data_in_size = 0x0;
-
-		} else {
-			if (!app_out_address) {
-				tail_size = data_in_size % block_size;
-				if (!tail_size) {
-					if (tail_block_size == block_size)
-						tail_size = block_size;
-				}
-			} else {
-				tail_size = 0;
-			}
-		}
-		if (tail_size) {
-			if (tail_size > sizeof(dcb_table_ptr->tail_data))
-				return -EINVAL;
-			if (is_kva == true) {
-				memcpy(dcb_table_ptr->tail_data,
-					(void *)(app_in_address + data_in_size -
-					tail_size), tail_size);
-			} else {
-				/* We have tail data - copy it to DCB */
-				if (copy_from_user(dcb_table_ptr->tail_data,
-					(void *)(app_in_address +
-					data_in_size - tail_size), tail_size)) {
-					error = -EFAULT;
-					goto end_function;
-				}
-			}
-			if (app_out_address)
-				/*
-				 * Calculate the output address
-				 * according to tail data size
-				 */
-				dcb_table_ptr->out_vr_tail_pt =
-					(aligned_u64)app_out_address + data_in_size
-					- tail_size;
-
-			/* Save the real tail data size */
-			dcb_table_ptr->tail_data_size = tail_size;
-			/*
-			 * Update the data size without the tail
-			 * data size AKA data for the dma
-			 */
-			data_in_size = (data_in_size - tail_size);
-		}
-	}
-	/* Check if we need to build only input table or input/output */
-	if (app_out_address) {
-		/* Prepare input/output tables */
-		error = sep_prepare_input_output_dma_table(sep,
-			app_in_address,
-			app_out_address,
-			data_in_size,
-			block_size,
-			&in_first_mlli_address,
-			&out_first_mlli_address,
-			&in_first_num_entries,
-			&out_first_num_entries,
-			&first_data_size,
-			is_kva);
-	} else {
-		/* Prepare input tables */
-		error = sep_prepare_input_dma_table(sep,
-			app_in_address,
-			data_in_size,
-			block_size,
-			&in_first_mlli_address,
-			&in_first_num_entries,
-			&first_data_size,
-			is_kva);
-	}
-
-	if (error) {
-		dev_warn(&sep->pdev->dev, "prepare DMA table call failed from prepare DCB call\n");
-		goto end_function;
-	}
-
-	/* Set the DCB values */
-	dcb_table_ptr->input_mlli_address = in_first_mlli_address;
-	dcb_table_ptr->input_mlli_num_entries = in_first_num_entries;
-	dcb_table_ptr->input_mlli_data_size = first_data_size;
-	dcb_table_ptr->output_mlli_address = out_first_mlli_address;
-	dcb_table_ptr->output_mlli_num_entries = out_first_num_entries;
-	dcb_table_ptr->output_mlli_data_size = first_data_size;
-
-end_function:
-	return error;
-
-}
-
-/**
- *	sep_free_dma_tables_and_dcb - free DMA tables and DCBs
- *	@sep: pointer to struct sep_device
- *	@isapplet: indicates external application (used for kernel access)
- *	@is_kva: indicates kernel addresses (only used for kernel crypto)
- *
- *	This function frees the DMA tables and DCB
- */
-static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet,
-	bool is_kva)
-{
-	int i = 0;
-	int error = 0;
-	int error_temp = 0;
-	struct sep_dcblock *dcb_table_ptr;
-	unsigned long pt_hold;
-	void *tail_pt;
-
-	if (isapplet == true) {
-		/* Set pointer to first DCB table */
-		dcb_table_ptr = (struct sep_dcblock *)
-			(sep->shared_addr +
-			SEP_DRIVER_SYSTEM_DCB_MEMORY_OFFSET_IN_BYTES);
-
-		/* Go over each DCB and see if tail pointer must be updated */
-		for (i = 0; i < sep->nr_dcb_creat; i++, dcb_table_ptr++) {
-			if (dcb_table_ptr->out_vr_tail_pt) {
-				pt_hold = (unsigned long)dcb_table_ptr->out_vr_tail_pt;
-				tail_pt = (void *)pt_hold;
-				if (is_kva == true) {
-					memcpy(tail_pt,
-						dcb_table_ptr->tail_data,
-						dcb_table_ptr->tail_data_size);
-				} else {
-					error_temp = copy_to_user(
-						tail_pt,
-						dcb_table_ptr->tail_data,
-						dcb_table_ptr->tail_data_size);
-				}
-				if (error_temp) {
-					/* Release the DMA resource */
-					error = -EFAULT;
-					break;
-				}
-			}
-		}
-	}
-	/* Free the output pages, if any */
-	sep_free_dma_table_data_handler(sep);
-
-	return error;
-}
-
-/**
- *	sep_get_static_pool_addr_handler - get static pool address
- *	@sep: pointer to struct sep_device
- *
- *	This function sets the bus and virtual addresses of the static pool
- */
-static int sep_get_static_pool_addr_handler(struct sep_device *sep)
-{
-	u32 *static_pool_addr = NULL;
-
-	static_pool_addr = (u32 *)(sep->shared_addr +
-		SEP_DRIVER_SYSTEM_RAR_MEMORY_OFFSET_IN_BYTES);
-
-	static_pool_addr[0] = SEP_STATIC_POOL_VAL_TOKEN;
-	static_pool_addr[1] = (u32)sep->shared_bus +
-		SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES;
-
-	dev_dbg(&sep->pdev->dev, "static pool segment: physical %x\n",
-		(u32)static_pool_addr[1]);
-
-	return 0;
-}
-
-/**
- *	sep_end_transaction_handler - end transaction
- *	@sep: pointer to struct sep_device
- *
- *	This API handles the end transaction request
- */
-static int sep_end_transaction_handler(struct sep_device *sep)
-{
-	/* Clear the data pool pointers Token */
-	memset((void *)(sep->shared_addr +
-		SEP_DRIVER_DATA_POOL_ALLOCATION_OFFSET_IN_BYTES),
-		0, sep->num_of_data_allocations*2*sizeof(u32));
-
-	/* Check that all the DMA resources were freed */
-	sep_free_dma_table_data_handler(sep);
-
-	clear_bit(SEP_MMAP_LOCK_BIT, &sep->in_use_flags);
-
-	/*
-	 * We are now through with the transaction. Let's
-	 * allow other processes who have the device open
-	 * to perform transactions
-	 */
-	mutex_lock(&sep->sep_mutex);
-	sep->pid_doing_transaction = 0;
-	mutex_unlock(&sep->sep_mutex);
-	/* Raise event for stuck contextes */
-	wake_up(&sep->event);
-
-	return 0;
-}
-
-/**
- *	sep_prepare_dcb_handler - prepare a control block
- *	@sep: pointer to struct sep_device
- *	@arg: pointer to user parameters
- *
- *	This function will retrieve the RAR buffer physical addresses, type
- *	& size corresponding to the RAR handles provided in the buffers vector.
- */
-static int sep_prepare_dcb_handler(struct sep_device *sep, unsigned long arg)
-{
-	int error;
-	/* Command arguments */
-	struct build_dcb_struct command_args;
-
-	/* Get the command arguments */
-	if (copy_from_user(&command_args, (void __user *)arg,
-					sizeof(struct build_dcb_struct))) {
-		error = -EFAULT;
-		goto end_function;
-	}
-
-	dev_dbg(&sep->pdev->dev, "prep dcb handler app_in_address is %08llx\n",
-						command_args.app_in_address);
-	dev_dbg(&sep->pdev->dev, "app_out_address is %08llx\n",
-						command_args.app_out_address);
-	dev_dbg(&sep->pdev->dev, "data_size is %x\n",
-						command_args.data_in_size);
-	dev_dbg(&sep->pdev->dev, "block_size is %x\n",
-						command_args.block_size);
-	dev_dbg(&sep->pdev->dev, "tail block_size is %x\n",
-						command_args.tail_block_size);
-
-	error = sep_prepare_input_output_dma_table_in_dcb(sep,
-		(unsigned long)command_args.app_in_address,
-		(unsigned long)command_args.app_out_address,
-		command_args.data_in_size, command_args.block_size,
-		command_args.tail_block_size, true, false);
-
-end_function:
-	return error;
-
-}
-
-/**
- *	sep_free_dcb_handler - free control block resources
- *	@sep: pointer to struct sep_device
- *
- *	This function frees the DCB resources and updates the needed
- *	user-space buffers.
- */
-static int sep_free_dcb_handler(struct sep_device *sep)
-{
-	return sep_free_dma_tables_and_dcb(sep, false, false);
-}
-
-/**
- *	sep_rar_prepare_output_msg_handler - prepare an output message
- *	@sep: pointer to struct sep_device
- *	@arg: pointer to user parameters
- *
- *	This function will retrieve the RAR buffer physical addresses, type
- *	& size corresponding to the RAR handles provided in the buffers vector.
- */
-static int sep_rar_prepare_output_msg_handler(struct sep_device *sep,
-	unsigned long arg)
-{
-	int error = 0;
-	/* Command args */
-	struct rar_hndl_to_bus_struct command_args;
-	/* Bus address */
-	dma_addr_t  rar_bus = 0;
-	/* Holds the RAR address in the system memory offset */
-	u32 *rar_addr;
-
-	/* Copy the data */
-	if (copy_from_user(&command_args, (void __user *)arg,
-						sizeof(command_args))) {
-		error = -EFAULT;
-		goto end_function;
-	}
-
-	/* Call to translation function only if user handle is not NULL */
-	if (command_args.rar_handle)
-		return -EOPNOTSUPP;
-	dev_dbg(&sep->pdev->dev, "rar msg; rar_addr_bus = %x\n", (u32)rar_bus);
-
-	/* Set value in the SYSTEM MEMORY offset */
-	rar_addr = (u32 *)(sep->shared_addr +
-		SEP_DRIVER_SYSTEM_RAR_MEMORY_OFFSET_IN_BYTES);
-
-	/* Copy the physical address to the System Area for the SEP */
-	rar_addr[0] = SEP_RAR_VAL_TOKEN;
-	rar_addr[1] = rar_bus;
-
-end_function:
-	return error;
-}
-
-/**
- *	sep_ioctl - ioctl api
- *	@filp: pointer to struct file
- *	@cmd: command
- *	@arg: pointer to argument structure
- *
- *	Implement the ioctl methods available on the SEP device.
- */
-static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
-	int error = 0;
-	struct sep_device *sep = filp->private_data;
-
-	/* Make sure we own this device */
-	mutex_lock(&sep->sep_mutex);
-	if ((current->pid != sep->pid_doing_transaction) &&
-				(sep->pid_doing_transaction != 0)) {
-		dev_dbg(&sep->pdev->dev, "ioctl pid is not owner\n");
-		error = -EACCES;
-	}
-	mutex_unlock(&sep->sep_mutex);
-
-	if (error)
-		return error;
-
-	if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER)
-		return -ENOTTY;
-
-	/* Lock to prevent the daemon to interfere with operation */
-	mutex_lock(&sep->ioctl_mutex);
-
-	switch (cmd) {
-	case SEP_IOCSENDSEPCOMMAND:
-		/* Send command to SEP */
-		error = sep_send_command_handler(sep);
-		break;
-	case SEP_IOCALLOCDATAPOLL:
-		/* Allocate data pool */
-		error = sep_allocate_data_pool_memory_handler(sep, arg);
-		break;
-	case SEP_IOCGETSTATICPOOLADDR:
-		/* Inform the SEP the bus address of the static pool */
-		error = sep_get_static_pool_addr_handler(sep);
-		break;
-	case SEP_IOCENDTRANSACTION:
-		error = sep_end_transaction_handler(sep);
-		break;
-	case SEP_IOCRARPREPAREMESSAGE:
-		error = sep_rar_prepare_output_msg_handler(sep, arg);
-		break;
-	case SEP_IOCPREPAREDCB:
-		error = sep_prepare_dcb_handler(sep, arg);
-		break;
-	case SEP_IOCFREEDCB:
-		error = sep_free_dcb_handler(sep);
-		break;
-	default:
-		error = -ENOTTY;
-		break;
-	}
-
-	mutex_unlock(&sep->ioctl_mutex);
-	return error;
-}
-
-/**
- *	sep_singleton_ioctl - ioctl api for singleton interface
- *	@filp: pointer to struct file
- *	@cmd: command
- *	@arg: pointer to argument structure
- *
- *	Implement the additional ioctls for the singleton device
- */
-static long sep_singleton_ioctl(struct file  *filp, u32 cmd, unsigned long arg)
-{
-	long error = 0;
-	struct sep_device *sep = filp->private_data;
-
-	/* Check that the command is for the SEP device */
-	if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER)
-		return -ENOTTY;
-
-	/* Make sure we own this device */
-	mutex_lock(&sep->sep_mutex);
-	if ((current->pid != sep->pid_doing_transaction) &&
-				(sep->pid_doing_transaction != 0)) {
-		dev_dbg(&sep->pdev->dev, "singleton ioctl pid is not owner\n");
-		mutex_unlock(&sep->sep_mutex);
-		return -EACCES;
-	}
-
-	mutex_unlock(&sep->sep_mutex);
-
-	switch (cmd) {
-	case SEP_IOCTLSETCALLERID:
-		mutex_lock(&sep->ioctl_mutex);
-		error = sep_set_caller_id_handler(sep, arg);
-		mutex_unlock(&sep->ioctl_mutex);
-		break;
-	default:
-		error = sep_ioctl(filp, cmd, arg);
-		break;
-	}
-	return error;
-}
-
-/**
- *	sep_request_daemon_ioctl - ioctl for daemon
- *	@filp: pointer to struct file
- *	@cmd: command
- *	@arg: pointer to argument structure
- *
- *	Called by the request daemon to perform ioctls on the daemon device
- */
-static long sep_request_daemon_ioctl(struct file *filp, u32 cmd,
-	unsigned long arg)
-{
-
-	long error;
-	struct sep_device *sep = filp->private_data;
-
-	/* Check that the command is for SEP device */
-	if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER)
-		return -ENOTTY;
-
-	/* Only one process can access ioctl at any given time */
-	mutex_lock(&sep->ioctl_mutex);
-
-	switch (cmd) {
-	case SEP_IOCSENDSEPRPLYCOMMAND:
-		/* Send reply command to SEP */
-		error = sep_req_daemon_send_reply_command_handler(sep);
-		break;
-	case SEP_IOCENDTRANSACTION:
-		/*
-		 * End req daemon transaction, do nothing
-		 * will be removed upon update in middleware
-		 * API library
-		 */
-		error = 0;
-		break;
-	default:
-		error = -ENOTTY;
-	}
-	mutex_unlock(&sep->ioctl_mutex);
-	return error;
-}
-
-/**
- *	sep_inthandler - interrupt handler
- *	@irq: interrupt
- *	@dev_id: device id
- */
-static irqreturn_t sep_inthandler(int irq, void *dev_id)
-{
-	irqreturn_t int_error = IRQ_HANDLED;
-	unsigned long lck_flags;
-	u32 reg_val, reg_val2 = 0;
-	struct sep_device *sep = dev_id;
-
-	/* Read the IRR register to check if this is SEP interrupt */
-	reg_val = sep_read_reg(sep, HW_HOST_IRR_REG_ADDR);
-
-	if (reg_val & (0x1 << 13)) {
-		/* Lock and update the counter of reply messages */
-		spin_lock_irqsave(&sep->snd_rply_lck, lck_flags);
-		sep->reply_ct++;
-		spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags);
-
-		dev_dbg(&sep->pdev->dev, "sep int: send_ct %lx reply_ct %lx\n",
-					sep->send_ct, sep->reply_ct);
-
-		/* Is this printf or daemon request? */
-		reg_val2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
-		dev_dbg(&sep->pdev->dev,
-			"SEP Interrupt - reg2 is %08x\n", reg_val2);
-
-		if ((reg_val2 >> 30) & 0x1) {
-			dev_dbg(&sep->pdev->dev, "int: printf request\n");
-			wake_up(&sep->event_request_daemon);
-		} else if (reg_val2 >> 31) {
-			dev_dbg(&sep->pdev->dev, "int: daemon request\n");
-			wake_up(&sep->event_request_daemon);
-		} else {
-			dev_dbg(&sep->pdev->dev, "int: SEP reply\n");
-			wake_up(&sep->event);
-		}
-	} else {
-		dev_dbg(&sep->pdev->dev, "int: not SEP interrupt\n");
-		int_error = IRQ_NONE;
-	}
-	if (int_error == IRQ_HANDLED)
-		sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, reg_val);
-
-	return int_error;
-}
-
-/**
- *	sep_reconfig_shared_area - reconfigure shared area
- *	@sep: pointer to struct sep_device
- *
- *	Reconfig the shared area between HOST and SEP - needed in case
- *	the DX_CC_Init function was called before OS loading.
- */
-static int sep_reconfig_shared_area(struct sep_device *sep)
-{
-	int ret_val;
-
-	/* use to limit waiting for SEP */
-	unsigned long end_time;
-
-	/* Send the new SHARED MESSAGE AREA to the SEP */
-	dev_dbg(&sep->pdev->dev, "reconfig shared; sending %08llx to sep\n",
-				(unsigned long long)sep->shared_bus);
-
-	sep_write_reg(sep, HW_HOST_HOST_SEP_GPR1_REG_ADDR, sep->shared_bus);
-
-	/* Poll for SEP response */
-	ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR);
-
-	end_time = jiffies + (WAIT_TIME * HZ);
-
-	while ((time_before(jiffies, end_time)) && (ret_val != 0xffffffff) &&
-		(ret_val != sep->shared_bus))
-		ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR);
-
-	/* Check the return value (register) */
-	if (ret_val != sep->shared_bus) {
-		dev_warn(&sep->pdev->dev, "could not reconfig shared area\n");
-		dev_warn(&sep->pdev->dev, "result was %x\n", ret_val);
-		ret_val = -ENOMEM;
-	} else
-		ret_val = 0;
-
-	dev_dbg(&sep->pdev->dev, "reconfig shared area end\n");
-	return ret_val;
-}
-
-/* File operation for singleton SEP operations */
-static const struct file_operations singleton_file_operations = {
-	.owner = THIS_MODULE,
-	.unlocked_ioctl = sep_singleton_ioctl,
-	.poll = sep_poll,
-	.open = sep_singleton_open,
-	.release = sep_singleton_release,
-	.mmap = sep_mmap,
-};
-
-/* File operation for daemon operations */
-static const struct file_operations daemon_file_operations = {
-	.owner = THIS_MODULE,
-	.unlocked_ioctl = sep_request_daemon_ioctl,
-	.poll = sep_request_daemon_poll,
-	.open = sep_request_daemon_open,
-	.release = sep_request_daemon_release,
-	.mmap = sep_request_daemon_mmap,
-};
-
-/* The files operations structure of the driver */
-static const struct file_operations sep_file_operations = {
-	.owner = THIS_MODULE,
-	.unlocked_ioctl = sep_ioctl,
-	.poll = sep_poll,
-	.open = sep_open,
-	.release = sep_release,
-	.mmap = sep_mmap,
-};
-
-/**
- *	sep_register_driver_with_fs - register misc devices
- *	@sep: pointer to struct sep_device
- *
- *	This function registers the driver with the file system
- */
-static int sep_register_driver_with_fs(struct sep_device *sep)
-{
-	int ret_val;
-
-	sep->miscdev_sep.minor = MISC_DYNAMIC_MINOR;
-	sep->miscdev_sep.name = SEP_DEV_NAME;
-	sep->miscdev_sep.fops = &sep_file_operations;
-
-	sep->miscdev_singleton.minor = MISC_DYNAMIC_MINOR;
-	sep->miscdev_singleton.name = SEP_DEV_SINGLETON;
-	sep->miscdev_singleton.fops = &singleton_file_operations;
-
-	sep->miscdev_daemon.minor = MISC_DYNAMIC_MINOR;
-	sep->miscdev_daemon.name = SEP_DEV_DAEMON;
-	sep->miscdev_daemon.fops = &daemon_file_operations;
-
-	ret_val = misc_register(&sep->miscdev_sep);
-	if (ret_val) {
-		dev_warn(&sep->pdev->dev, "misc reg fails for SEP %x\n",
-			ret_val);
-		return ret_val;
-	}
-
-	ret_val = misc_register(&sep->miscdev_singleton);
-	if (ret_val) {
-		dev_warn(&sep->pdev->dev, "misc reg fails for sing %x\n",
-			ret_val);
-		misc_deregister(&sep->miscdev_sep);
-		return ret_val;
-	}
-
-	ret_val = misc_register(&sep->miscdev_daemon);
-	if (ret_val) {
-		dev_warn(&sep->pdev->dev, "misc reg fails for dmn %x\n",
-			ret_val);
-		misc_deregister(&sep->miscdev_sep);
-		misc_deregister(&sep->miscdev_singleton);
-
-		return ret_val;
-	}
-	return ret_val;
-}
-
-
-/**
- *	sep_probe - probe a matching PCI device
- *	@pdev: pci_device
- *	@end: pci_device_id
- *
- *	Attempt to set up and configure a SEP device that has been
- *	discovered by the PCI layer.
- */
-static int __devinit sep_probe(struct pci_dev *pdev,
-	const struct pci_device_id *ent)
-{
-	int error = 0;
-	struct sep_device *sep;
-
-	if (sep_dev != NULL) {
-		dev_warn(&pdev->dev, "only one SEP supported.\n");
-		return -EBUSY;
-	}
-
-	/* Enable the device */
-	error = pci_enable_device(pdev);
-	if (error) {
-		dev_warn(&pdev->dev, "error enabling pci device\n");
-		goto end_function;
-	}
-
-	/* Allocate the sep_device structure for this device */
-	sep_dev = kzalloc(sizeof(struct sep_device), GFP_ATOMIC);
-	if (sep_dev == NULL) {
-		dev_warn(&pdev->dev,
-			"can't kmalloc the sep_device structure\n");
-		error = -ENOMEM;
-		goto end_function_disable_device;
-	}
-
-	/*
-	 * We're going to use another variable for actually
-	 * working with the device; this way, if we have
-	 * multiple devices in the future, it would be easier
-	 * to make appropriate changes
-	 */
-	sep = sep_dev;
-
-	sep->pdev = pci_dev_get(pdev);
-
-	init_waitqueue_head(&sep->event);
-	init_waitqueue_head(&sep->event_request_daemon);
-	spin_lock_init(&sep->snd_rply_lck);
-	mutex_init(&sep->sep_mutex);
-	mutex_init(&sep->ioctl_mutex);
-
-	dev_dbg(&sep->pdev->dev, "sep probe: PCI obtained, device being prepared\n");
-	dev_dbg(&sep->pdev->dev, "revision is %d\n", sep->pdev->revision);
-
-	/* Set up our register area */
-	sep->reg_physical_addr = pci_resource_start(sep->pdev, 0);
-	if (!sep->reg_physical_addr) {
-		dev_warn(&sep->pdev->dev, "Error getting register start\n");
-		error = -ENODEV;
-		goto end_function_free_sep_dev;
-	}
-
-	sep->reg_physical_end = pci_resource_end(sep->pdev, 0);
-	if (!sep->reg_physical_end) {
-		dev_warn(&sep->pdev->dev, "Error getting register end\n");
-		error = -ENODEV;
-		goto end_function_free_sep_dev;
-	}
-
-	sep->reg_addr = ioremap_nocache(sep->reg_physical_addr,
-		(size_t)(sep->reg_physical_end - sep->reg_physical_addr + 1));
-	if (!sep->reg_addr) {
-		dev_warn(&sep->pdev->dev, "Error getting register virtual\n");
-		error = -ENODEV;
-		goto end_function_free_sep_dev;
-	}
-
-	dev_dbg(&sep->pdev->dev,
-		"Register area start %llx end %llx virtual %p\n",
-		(unsigned long long)sep->reg_physical_addr,
-		(unsigned long long)sep->reg_physical_end,
-		sep->reg_addr);
-
-	/* Allocate the shared area */
-	sep->shared_size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES +
-		SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES +
-		SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES +
-		SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES +
-		SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES;
-
-	if (sep_map_and_alloc_shared_area(sep)) {
-		error = -ENOMEM;
-		/* Allocation failed */
-		goto end_function_error;
-	}
-
-	/* Clear ICR register */
-	sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, 0xFFFFFFFF);
-
-	/* Set the IMR register - open only GPR 2 */
-	sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13)));
-
-	/* Read send/receive counters from SEP */
-	sep->reply_ct = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
-	sep->reply_ct &= 0x3FFFFFFF;
-	sep->send_ct = sep->reply_ct;
-
-	/* Get the interrupt line */
-	error = request_irq(pdev->irq, sep_inthandler, IRQF_SHARED,
-		"sep_driver", sep);
-
-	if (error)
-		goto end_function_deallocate_sep_shared_area;
-
-	/* The new chip requires a shared area reconfigure */
-	if (sep->pdev->revision == 4) { /* Only for new chip */
-		error = sep_reconfig_shared_area(sep);
-		if (error)
-			goto end_function_free_irq;
-	}
-	/* Finally magic up the device nodes */
-	/* Register driver with the fs */
-	error = sep_register_driver_with_fs(sep);
-	if (error == 0)
-		/* Success */
-		return 0;
-
-end_function_free_irq:
-	free_irq(pdev->irq, sep);
-
-end_function_deallocate_sep_shared_area:
-	/* De-allocate shared area */
-	sep_unmap_and_free_shared_area(sep);
-
-end_function_error:
-	iounmap(sep->reg_addr);
-
-end_function_free_sep_dev:
-	pci_dev_put(sep_dev->pdev);
-	kfree(sep_dev);
-	sep_dev = NULL;
-
-end_function_disable_device:
-	pci_disable_device(pdev);
-
-end_function:
-	return error;
-}
-
-static void sep_remove(struct pci_dev *pdev)
-{
-	struct sep_device *sep = sep_dev;
-
-	/* Unregister from fs */
-	misc_deregister(&sep->miscdev_sep);
-	misc_deregister(&sep->miscdev_singleton);
-	misc_deregister(&sep->miscdev_daemon);
-
-	/* Free the irq */
-	free_irq(sep->pdev->irq, sep);
-
-	/* Free the shared area  */
-	sep_unmap_and_free_shared_area(sep_dev);
-	iounmap((void *) sep_dev->reg_addr);
-}
-
-static DEFINE_PCI_DEVICE_TABLE(sep_pci_id_tbl) = {
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MFLD_PCI_DEVICE_ID)},
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, sep_pci_id_tbl);
-
-/* Field for registering driver to PCI device */
-static struct pci_driver sep_pci_driver = {
-	.name = "sep_sec_driver",
-	.id_table = sep_pci_id_tbl,
-	.probe = sep_probe,
-	.remove = sep_remove
-};
-
-
-/**
- *	sep_init - init function
- *
- *	Module load time. Register the PCI device driver.
- */
-static int __init sep_init(void)
-{
-	return pci_register_driver(&sep_pci_driver);
-}
-
-
-/**
- *	sep_exit - called to unload driver
- *
- *	Drop the misc devices then remove and unmap the various resources
- *	that are not released by the driver remove method.
- */
-static void __exit sep_exit(void)
-{
-	pci_unregister_driver(&sep_pci_driver);
-}
-
-
-module_init(sep_init);
-module_exit(sep_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/sep/sep_driver_api.h b/drivers/staging/sep/sep_driver_api.h
index c3aacfc..8b797d5 100644
--- a/drivers/staging/sep/sep_driver_api.h
+++ b/drivers/staging/sep/sep_driver_api.h
@@ -2,8 +2,8 @@
  *
  *  sep_driver_api.h - Security Processor Driver api definitions
  *
- *  Copyright(c) 2009,2010 Intel Corporation. All rights reserved.
- *  Contributions(c) 2009,2010 Discretix. All rights reserved.
+ *  Copyright(c) 2009-2011 Intel Corporation. All rights reserved.
+ *  Contributions(c) 2009-2011 Discretix. All rights reserved.
  *
  *  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
@@ -26,6 +26,7 @@
  *  CHANGES:
  *
  *  2010.09.14  Upgrade to Medfield
+ *  2011.02.22  Enable kernel crypto
  *
  */
 
@@ -37,26 +38,32 @@
 #define SEP_DRIVER_SRC_REQ		2
 #define SEP_DRIVER_SRC_PRINTF		3
 
+/* Power state */
+#define SEP_DRIVER_POWERON		1
+#define SEP_DRIVER_POWEROFF		2
 
-/*-------------------------------------------
-    TYPEDEFS
-----------------------------------------------*/
+/* Following enums are used only for kernel crypto api */
+enum type_of_request {
+	NO_REQUEST,
+	AES_CBC,
+	AES_ECB,
+	DES_CBC,
+	DES_ECB,
+	DES3_ECB,
+	DES3_CBC,
+	SHA1,
+	MD5,
+	SHA224,
+	SHA256
+	};
 
-struct alloc_struct {
-	/* offset from start of shared pool area */
-	u32  offset;
-	/* number of bytes to allocate */
-	u32  num_bytes;
-};
-
-/* command struct for getting caller id value and address */
-struct caller_id_struct {
-	/* pid of the process */
-	u32 pid;
-	/* virtual address of the caller id hash */
-	aligned_u64 callerIdAddress;
-	/* caller id hash size in bytes */
-	u32 callerIdSizeInBytes;
+enum hash_stage {
+	HASH_INIT,
+	HASH_UPDATE,
+	HASH_FINISH,
+	HASH_DIGEST,
+	HASH_FINUP_DATA,
+	HASH_FINUP_FINISH
 };
 
 /*
@@ -83,11 +90,6 @@
 	u8	tail_data[68];
 };
 
-struct sep_caller_id_entry {
-	int pid;
-	unsigned char callerIdHash[SEP_CALLER_ID_HASH_SIZE_IN_BYTES];
-};
-
 /*
 	command structure for building dcb block (currently for ext app only
 */
@@ -104,6 +106,33 @@
 	/* the size of the block of the operation - if needed,
 	every table will be modulo this parameter */
 	u32  tail_block_size;
+
+	/* which application calls the driver DX or applet */
+	u32  is_applet;
+};
+
+/*
+	command structure for building dcb block for kernel crypto
+*/
+struct build_dcb_struct_kernel {
+	/* address value of the data in */
+	void *app_in_address;
+	/* size of data in */
+	ssize_t  data_in_size;
+	/* address of the data out */
+	void *app_out_address;
+	/* the size of the block of the operation - if needed,
+	every table will be modulo this parameter */
+	u32  block_size;
+	/* the size of the block of the operation - if needed,
+	every table will be modulo this parameter */
+	u32  tail_block_size;
+
+	/* which application calls the driver DX or applet */
+	u32  is_applet;
+
+	struct scatterlist *src_sg;
+	struct scatterlist *dst_sg;
 };
 
 /**
@@ -147,6 +176,10 @@
 
 	/* number of entries of the output mapp array */
 	u32 out_map_num_entries;
+
+	/* Scatter list for kernel operations */
+	struct scatterlist *src_sg;
+	struct scatterlist *dst_sg;
 };
 
 
@@ -169,47 +202,201 @@
 	u32 block_size;
 };
 
-/*----------------------------------------------------------------
-	IOCTL command defines
-	-----------------------------------------------------------------*/
+/*
+ * header format for each fastcall write operation
+ */
+struct sep_fastcall_hdr {
+	u32 magic;
+	u32 secure_dma;
+	u32 msg_len;
+	u32 num_dcbs;
+};
 
+/*
+ * structure used in file pointer's private data field
+ * to track the status of the calls to the various
+ * driver interface
+ */
+struct sep_call_status {
+	unsigned long status;
+};
+
+/*
+ * format of dma context buffer used to store all DMA-related
+ * context information of a particular transaction
+ */
+struct sep_dma_context {
+	/* number of data control blocks */
+	u32 nr_dcb_creat;
+	/* number of the lli tables created in the current transaction */
+	u32 num_lli_tables_created;
+	/* size of currently allocated dma tables region */
+	u32 dmatables_len;
+	/* size of input data */
+	u32 input_data_len;
+	/* secure dma use (for imr memory restriced area in output */
+	bool secure_dma;
+	struct sep_dma_resource dma_res_arr[SEP_MAX_NUM_SYNC_DMA_OPS];
+	/* Scatter gather for kernel crypto */
+	struct scatterlist *src_sg;
+	struct scatterlist *dst_sg;
+};
+
+/*
+ * format for file pointer's private_data field
+ */
+struct sep_private_data {
+	struct sep_queue_info *my_queue_elem;
+	struct sep_device *device;
+	struct sep_call_status call_status;
+	struct sep_dma_context *dma_ctx;
+};
+
+
+/* Functions used by sep_crypto */
+
+/**
+ * sep_queue_status_remove - Removes transaction from status queue
+ * @sep: SEP device
+ * @sep_queue_info: pointer to status queue
+ *
+ * This function will removes information about transaction from the queue.
+ */
+void sep_queue_status_remove(struct sep_device *sep,
+				      struct sep_queue_info **queue_elem);
+/**
+ * sep_queue_status_add - Adds transaction to status queue
+ * @sep: SEP device
+ * @opcode: transaction opcode
+ * @size: input data size
+ * @pid: pid of current process
+ * @name: current process name
+ * @name_len: length of name (current process)
+ *
+ * This function adds information about about transaction started to the status
+ * queue.
+ */
+struct sep_queue_info *sep_queue_status_add(
+						struct sep_device *sep,
+						u32 opcode,
+						u32 size,
+						u32 pid,
+						u8 *name, size_t name_len);
+
+/**
+ *	sep_create_dcb_dmatables_context_kernel - Creates DCB & MLLI/DMA table context
+ *      for kernel crypto
+ *	@sep: SEP device
+ *	@dcb_region: DCB region buf to create for current transaction
+ *	@dmatables_region: MLLI/DMA tables buf to create for current transaction
+ *	@dma_ctx: DMA context buf to create for current transaction
+ *	@user_dcb_args: User arguments for DCB/MLLI creation
+ *	@num_dcbs: Number of DCBs to create
+ */
+int sep_create_dcb_dmatables_context_kernel(struct sep_device *sep,
+			struct sep_dcblock **dcb_region,
+			void **dmatables_region,
+			struct sep_dma_context **dma_ctx,
+			const struct build_dcb_struct_kernel *dcb_data,
+			const u32 num_dcbs);
+
+/**
+ *	sep_activate_dcb_dmatables_context - Takes DCB & DMA tables
+ *						contexts into use
+ *	@sep: SEP device
+ *	@dcb_region: DCB region copy
+ *	@dmatables_region: MLLI/DMA tables copy
+ *	@dma_ctx: DMA context for current transaction
+ */
+ssize_t sep_activate_dcb_dmatables_context(struct sep_device *sep,
+					struct sep_dcblock **dcb_region,
+					void **dmatables_region,
+					struct sep_dma_context *dma_ctx);
+
+/**
+ * sep_prepare_input_output_dma_table_in_dcb - prepare control blocks
+ * @app_in_address: unsigned long; for data buffer in (user space)
+ * @app_out_address: unsigned long; for data buffer out (user space)
+ * @data_in_size: u32; for size of data
+ * @block_size: u32; for block size
+ * @tail_block_size: u32; for size of tail block
+ * @isapplet: bool; to indicate external app
+ * @is_kva: bool; kernel buffer; only used for kernel crypto module
+ * @secure_dma; indicates whether this is secure_dma using IMR
+ *
+ * This function prepares the linked DMA tables and puts the
+ * address for the linked list of tables inta a DCB (data control
+ * block) the address of which is known by the SEP hardware
+ * Note that all bus addresses that are passed to the SEP
+ * are in 32 bit format; the SEP is a 32 bit device
+ */
+int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep,
+	unsigned long  app_in_address,
+	unsigned long  app_out_address,
+	u32  data_in_size,
+	u32  block_size,
+	u32  tail_block_size,
+	bool isapplet,
+	bool	is_kva,
+	bool    secure_dma,
+	struct sep_dcblock *dcb_region,
+	void **dmatables_region,
+	struct sep_dma_context **dma_ctx,
+	struct scatterlist *src_sg,
+	struct scatterlist *dst_sg);
+
+/**
+ * sep_free_dma_table_data_handler - free DMA table
+ * @sep: pointere to struct sep_device
+ * @dma_ctx: dma context
+ *
+ * Handles the request to  free DMA table for synchronic actions
+ */
+int sep_free_dma_table_data_handler(struct sep_device *sep,
+					   struct sep_dma_context **dma_ctx);
+/**
+ * sep_send_command_handler - kick off a command
+ * @sep: SEP being signalled
+ *
+ * This function raises interrupt to SEP that signals that is has a new
+ * command from the host
+ *
+ * Note that this function does fall under the ioctl lock
+ */
+int sep_send_command_handler(struct sep_device *sep);
+
+/**
+ *	sep_wait_transaction - Used for synchronizing transactions
+ *	@sep: SEP device
+ */
+int sep_wait_transaction(struct sep_device *sep);
+
+/**
+ * IOCTL command defines
+ */
 /* magic number 1 of the sep IOCTL command */
-#define SEP_IOC_MAGIC_NUMBER	                     's'
+#define SEP_IOC_MAGIC_NUMBER	's'
 
 /* sends interrupt to sep that message is ready */
 #define SEP_IOCSENDSEPCOMMAND	 \
 	_IO(SEP_IOC_MAGIC_NUMBER, 0)
 
-/* sends interrupt to sep that message is ready */
-#define SEP_IOCSENDSEPRPLYCOMMAND	 \
-	_IO(SEP_IOC_MAGIC_NUMBER, 1)
-
-/* allocate memory in data pool */
-#define SEP_IOCALLOCDATAPOLL	\
-	_IOW(SEP_IOC_MAGIC_NUMBER, 2, struct alloc_struct)
-
-/* free dynamic data aalocated during table creation */
-#define SEP_IOCFREEDMATABLEDATA	 \
-	_IO(SEP_IOC_MAGIC_NUMBER, 7)
-
-/* get the static pool area addersses (physical and virtual) */
-#define SEP_IOCGETSTATICPOOLADDR	\
-	_IO(SEP_IOC_MAGIC_NUMBER, 8)
-
 /* end transaction command */
 #define SEP_IOCENDTRANSACTION	 \
 	_IO(SEP_IOC_MAGIC_NUMBER, 15)
 
-#define SEP_IOCRARPREPAREMESSAGE	\
-	_IOW(SEP_IOC_MAGIC_NUMBER, 20, struct rar_hndl_to_bus_struct)
-
-#define SEP_IOCTLSETCALLERID	\
-	_IOW(SEP_IOC_MAGIC_NUMBER, 34, struct caller_id_struct)
-
 #define SEP_IOCPREPAREDCB					\
 	_IOW(SEP_IOC_MAGIC_NUMBER, 35, struct build_dcb_struct)
 
 #define SEP_IOCFREEDCB					\
 	_IO(SEP_IOC_MAGIC_NUMBER, 36)
 
+struct sep_device;
+
+#define SEP_IOCPREPAREDCB_SECURE_DMA	\
+	_IOW(SEP_IOC_MAGIC_NUMBER, 38, struct build_dcb_struct)
+
+#define SEP_IOCFREEDCB_SECURE_DMA	\
+	_IO(SEP_IOC_MAGIC_NUMBER, 39)
+
 #endif
diff --git a/drivers/staging/sep/sep_driver_config.h b/drivers/staging/sep/sep_driver_config.h
index d6bfd24..fa7c0d0 100644
--- a/drivers/staging/sep/sep_driver_config.h
+++ b/drivers/staging/sep/sep_driver_config.h
@@ -2,8 +2,8 @@
  *
  *  sep_driver_config.h - Security Processor Driver configuration
  *
- *  Copyright(c) 2009,2010 Intel Corporation. All rights reserved.
- *  Contributions(c) 2009,2010 Discretix. All rights reserved.
+ *  Copyright(c) 2009-2011 Intel Corporation. All rights reserved.
+ *  Contributions(c) 2009-2011 Discretix. All rights reserved.
  *
  *  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
@@ -26,6 +26,7 @@
  *  CHANGES:
  *
  *  2010.06.26	Upgrade to Medfield
+ *  2011.02.22  Enable kernel crypto
  *
  */
 
@@ -48,6 +49,8 @@
 /* the mode for running on the ARM1172 Evaluation platform (flag is 1) */
 #define SEP_DRIVER_ARM_DEBUG_MODE                       0
 
+/* Critical message area contents for sanity checking */
+#define SEP_START_MSG_TOKEN				0x02558808
 /*-------------------------------------------
 	INTERNAL DATA CONFIGURATION
 	-------------------------------------------*/
@@ -65,21 +68,17 @@
 #define SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE		16
 
 /* flag that signifies tah the lock is
-currently held by the process (struct file) */
+currently held by the proccess (struct file) */
 #define SEP_DRIVER_OWN_LOCK_FLAG                        1
 
 /* flag that signifies tah the lock is currently NOT
-held by the process (struct file) */
+held by the proccess (struct file) */
 #define SEP_DRIVER_DISOWN_LOCK_FLAG                     0
 
 /* indicates whether driver has mapped/unmapped shared area */
 #define SEP_REQUEST_DAEMON_MAPPED 1
 #define SEP_REQUEST_DAEMON_UNMAPPED 0
 
-#define SEP_DEV_NAME "sep_sec_driver"
-#define SEP_DEV_SINGLETON "sep_sec_singleton_driver"
-#define SEP_DEV_DAEMON "sep_req_daemon_driver"
-
 /*--------------------------------------------------------
 	SHARED AREA  memory total size is 36K
 	it is divided is following:
@@ -90,7 +89,7 @@
 									}
 	DATA_POOL_AREA                          12K        }
 
-	SYNCHRONIC_DMA_TABLES_AREA              5K
+	SYNCHRONIC_DMA_TABLES_AREA              29K
 
 	placeholder until drver changes
 	FLOW_DMA_TABLES_AREA                    4K
@@ -109,6 +108,12 @@
 
 
 /*
+	the minimum length of the message - includes 2 reserved fields
+	at the start, then token, message size and opcode fields. all dwords
+*/
+#define SEP_DRIVER_MIN_MESSAGE_SIZE_IN_BYTES			(5*sizeof(u32))
+
+/*
 	the maximum length of the message - the rest of the message shared
 	area will be dedicated to the dma lli tables
 */
@@ -124,7 +129,7 @@
 #define SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES		(16 * 1024)
 
 /* the size of the message shared area in pages */
-#define SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES	(1024 * 5)
+#define SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES	(1024 * 29)
 
 /* Placeholder until driver changes */
 #define SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES		(1024 * 4)
@@ -132,6 +137,9 @@
 /* system data (time, caller id etc') pool */
 #define SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES		(1024 * 3)
 
+/* Offset of the sep printf buffer in the message area */
+#define SEP_DRIVER_PRINTF_OFFSET_IN_BYTES			(5888)
+
 /* the size in bytes of the time memory */
 #define SEP_DRIVER_TIME_MEMORY_SIZE_IN_BYTES			8
 
@@ -223,10 +231,10 @@
 #define SEP_ALREADY_INITIALIZED_ERR                           12
 
 /* bit that locks access to the shared area */
-#define SEP_MMAP_LOCK_BIT                                     0
+#define SEP_TRANSACTION_STARTED_LOCK_BIT                      0
 
 /* bit that lock access to the poll  - after send_command */
-#define SEP_SEND_MSG_LOCK_BIT                                 1
+#define SEP_WORKING_LOCK_BIT                                  1
 
 /* the token that defines the static pool address address */
 #define SEP_STATIC_POOL_VAL_TOKEN                             0xABBAABBA
@@ -240,4 +248,51 @@
 /* Time limit for SEP to finish */
 #define WAIT_TIME 10
 
+/* Delay for pm runtime suspend (reduces pm thrashing with bursty traffic */
+#define SUSPEND_DELAY 10
+
+/* Number of delays to wait until scu boots after runtime resume */
+#define SCU_DELAY_MAX 50
+
+/* Delay for each iteration (usec) wait for scu boots after runtime resume */
+#define SCU_DELAY_ITERATION 10
+
+
+/*
+ * Bits used in struct sep_call_status to check that
+ * driver's APIs are called in valid order
+ */
+
+/* Bit offset which indicates status of sep_write() */
+#define SEP_FASTCALL_WRITE_DONE_OFFSET		0
+
+/* Bit offset which indicates status of sep_mmap() */
+#define SEP_LEGACY_MMAP_DONE_OFFSET		1
+
+/* Bit offset which indicates status of the SEP_IOCSENDSEPCOMMAND ioctl */
+#define SEP_LEGACY_SENDMSG_DONE_OFFSET		2
+
+/* Bit offset which indicates status of sep_poll() */
+#define SEP_LEGACY_POLL_DONE_OFFSET		3
+
+/* Bit offset which indicates status of the SEP_IOCENDTRANSACTION ioctl */
+#define SEP_LEGACY_ENDTRANSACTION_DONE_OFFSET	4
+
+/*
+ * Used to limit number of concurrent processes
+ * allowed to allocte dynamic buffers in fastcall
+ * interface.
+ */
+#define SEP_DOUBLEBUF_USERS_LIMIT		3
+
+/* Identifier for valid fastcall header */
+#define SEP_FC_MAGIC				0xFFAACCAA
+
+/*
+ * Used for enabling driver runtime power management.
+ * Useful for enabling/disabling it during performance
+ * testing
+ */
+#define SEP_ENABLE_RUNTIME_PM
+
 #endif /* SEP DRIVER CONFIG */
diff --git a/drivers/staging/sep/sep_driver_hw_defs.h b/drivers/staging/sep/sep_driver_hw_defs.h
index 300f909..a6a4481 100644
--- a/drivers/staging/sep/sep_driver_hw_defs.h
+++ b/drivers/staging/sep/sep_driver_hw_defs.h
@@ -2,8 +2,8 @@
  *
  *  sep_driver_hw_defs.h - Security Processor Driver hardware definitions
  *
- *  Copyright(c) 2009,2010 Intel Corporation. All rights reserved.
- *  Contributions(c) 2009,2010 Discretix. All rights reserved.
+ *  Copyright(c) 2009-2011 Intel Corporation. All rights reserved.
+ *  Contributions(c) 2009-2011 Discretix. All rights reserved.
  *
  *  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
@@ -26,15 +26,13 @@
  *  CHANGES:
  *
  *  2010.09.20	Upgrade to Medfield
+ *  2011.02.22  Enable kernel crypto
  *
  */
 
 #ifndef SEP_DRIVER_HW_DEFS__H
 #define SEP_DRIVER_HW_DEFS__H
 
-/* PCI ID's */
-#define MFLD_PCI_DEVICE_ID 0x0826
-
 /*----------------------- */
 /* HW Registers Defines.  */
 /*                        */
@@ -42,181 +40,9 @@
 
 
 /* cf registers */
-#define		HW_R0B_ADDR_0_REG_ADDR			0x0000UL
-#define		HW_R0B_ADDR_1_REG_ADDR			0x0004UL
-#define		HW_R0B_ADDR_2_REG_ADDR			0x0008UL
-#define		HW_R0B_ADDR_3_REG_ADDR			0x000cUL
-#define		HW_R0B_ADDR_4_REG_ADDR			0x0010UL
-#define		HW_R0B_ADDR_5_REG_ADDR			0x0014UL
-#define		HW_R0B_ADDR_6_REG_ADDR			0x0018UL
-#define		HW_R0B_ADDR_7_REG_ADDR			0x001cUL
-#define		HW_R0B_ADDR_8_REG_ADDR			0x0020UL
-#define		HW_R2B_ADDR_0_REG_ADDR			0x0080UL
-#define		HW_R2B_ADDR_1_REG_ADDR			0x0084UL
-#define		HW_R2B_ADDR_2_REG_ADDR			0x0088UL
-#define		HW_R2B_ADDR_3_REG_ADDR			0x008cUL
-#define		HW_R2B_ADDR_4_REG_ADDR			0x0090UL
-#define		HW_R2B_ADDR_5_REG_ADDR			0x0094UL
-#define		HW_R2B_ADDR_6_REG_ADDR			0x0098UL
-#define		HW_R2B_ADDR_7_REG_ADDR			0x009cUL
-#define		HW_R2B_ADDR_8_REG_ADDR			0x00a0UL
-#define		HW_R3B_REG_ADDR				0x00C0UL
-#define		HW_R4B_REG_ADDR				0x0100UL
-#define		HW_CSA_ADDR_0_REG_ADDR			0x0140UL
-#define		HW_CSA_ADDR_1_REG_ADDR			0x0144UL
-#define		HW_CSA_ADDR_2_REG_ADDR			0x0148UL
-#define		HW_CSA_ADDR_3_REG_ADDR			0x014cUL
-#define		HW_CSA_ADDR_4_REG_ADDR			0x0150UL
-#define		HW_CSA_ADDR_5_REG_ADDR			0x0154UL
-#define		HW_CSA_ADDR_6_REG_ADDR			0x0158UL
-#define		HW_CSA_ADDR_7_REG_ADDR			0x015cUL
-#define		HW_CSA_ADDR_8_REG_ADDR			0x0160UL
-#define		HW_CSA_REG_ADDR				0x0140UL
-#define		HW_SINB_REG_ADDR			0x0180UL
-#define		HW_SOUTB_REG_ADDR			0x0184UL
-#define		HW_PKI_CONTROL_REG_ADDR			0x01C0UL
-#define		HW_PKI_STATUS_REG_ADDR			0x01C4UL
-#define		HW_PKI_BUSY_REG_ADDR			0x01C8UL
-#define		HW_PKI_A_1025_REG_ADDR			0x01CCUL
-#define		HW_PKI_SDMA_CTL_REG_ADDR		0x01D0UL
-#define		HW_PKI_SDMA_OFFSET_REG_ADDR		0x01D4UL
-#define		HW_PKI_SDMA_POINTERS_REG_ADDR		0x01D8UL
-#define		HW_PKI_SDMA_DLENG_REG_ADDR		0x01DCUL
-#define		HW_PKI_SDMA_EXP_POINTERS_REG_ADDR	0x01E0UL
-#define		HW_PKI_SDMA_RES_POINTERS_REG_ADDR	0x01E4UL
-#define		HW_PKI_CLR_REG_ADDR			0x01E8UL
-#define		HW_PKI_SDMA_BUSY_REG_ADDR		0x01E8UL
-#define		HW_PKI_SDMA_FIRST_EXP_N_REG_ADDR	0x01ECUL
-#define		HW_PKI_SDMA_MUL_BY1_REG_ADDR		0x01F0UL
-#define		HW_PKI_SDMA_RMUL_SEL_REG_ADDR		0x01F4UL
-#define		HW_DES_KEY_0_REG_ADDR			0x0208UL
-#define		HW_DES_KEY_1_REG_ADDR			0x020CUL
-#define		HW_DES_KEY_2_REG_ADDR			0x0210UL
-#define		HW_DES_KEY_3_REG_ADDR			0x0214UL
-#define		HW_DES_KEY_4_REG_ADDR			0x0218UL
-#define		HW_DES_KEY_5_REG_ADDR			0x021CUL
-#define		HW_DES_CONTROL_0_REG_ADDR		0x0220UL
-#define		HW_DES_CONTROL_1_REG_ADDR		0x0224UL
-#define		HW_DES_IV_0_REG_ADDR			0x0228UL
-#define		HW_DES_IV_1_REG_ADDR			0x022CUL
-#define		HW_AES_KEY_0_ADDR_0_REG_ADDR		0x0400UL
-#define		HW_AES_KEY_0_ADDR_1_REG_ADDR		0x0404UL
-#define		HW_AES_KEY_0_ADDR_2_REG_ADDR		0x0408UL
-#define		HW_AES_KEY_0_ADDR_3_REG_ADDR		0x040cUL
-#define		HW_AES_KEY_0_ADDR_4_REG_ADDR		0x0410UL
-#define		HW_AES_KEY_0_ADDR_5_REG_ADDR		0x0414UL
-#define		HW_AES_KEY_0_ADDR_6_REG_ADDR		0x0418UL
-#define		HW_AES_KEY_0_ADDR_7_REG_ADDR		0x041cUL
-#define		HW_AES_KEY_0_REG_ADDR			0x0400UL
-#define		HW_AES_IV_0_ADDR_0_REG_ADDR		0x0440UL
-#define		HW_AES_IV_0_ADDR_1_REG_ADDR		0x0444UL
-#define		HW_AES_IV_0_ADDR_2_REG_ADDR		0x0448UL
-#define		HW_AES_IV_0_ADDR_3_REG_ADDR		0x044cUL
-#define		HW_AES_IV_0_REG_ADDR			0x0440UL
-#define		HW_AES_CTR1_ADDR_0_REG_ADDR		0x0460UL
-#define		HW_AES_CTR1_ADDR_1_REG_ADDR		0x0464UL
-#define		HW_AES_CTR1_ADDR_2_REG_ADDR		0x0468UL
-#define		HW_AES_CTR1_ADDR_3_REG_ADDR		0x046cUL
-#define		HW_AES_CTR1_REG_ADDR			0x0460UL
-#define		HW_AES_SK_REG_ADDR			0x0478UL
-#define		HW_AES_MAC_OK_REG_ADDR			0x0480UL
-#define		HW_AES_PREV_IV_0_ADDR_0_REG_ADDR	0x0490UL
-#define		HW_AES_PREV_IV_0_ADDR_1_REG_ADDR	0x0494UL
-#define		HW_AES_PREV_IV_0_ADDR_2_REG_ADDR	0x0498UL
-#define		HW_AES_PREV_IV_0_ADDR_3_REG_ADDR	0x049cUL
-#define		HW_AES_PREV_IV_0_REG_ADDR		0x0490UL
-#define		HW_AES_CONTROL_REG_ADDR			0x04C0UL
-#define		HW_HASH_H0_REG_ADDR			0x0640UL
-#define		HW_HASH_H1_REG_ADDR			0x0644UL
-#define		HW_HASH_H2_REG_ADDR			0x0648UL
-#define		HW_HASH_H3_REG_ADDR			0x064CUL
-#define		HW_HASH_H4_REG_ADDR			0x0650UL
-#define		HW_HASH_H5_REG_ADDR			0x0654UL
-#define		HW_HASH_H6_REG_ADDR			0x0658UL
-#define		HW_HASH_H7_REG_ADDR			0x065CUL
-#define		HW_HASH_H8_REG_ADDR			0x0660UL
-#define		HW_HASH_H9_REG_ADDR			0x0664UL
-#define		HW_HASH_H10_REG_ADDR			0x0668UL
-#define		HW_HASH_H11_REG_ADDR			0x066CUL
-#define		HW_HASH_H12_REG_ADDR			0x0670UL
-#define		HW_HASH_H13_REG_ADDR			0x0674UL
-#define		HW_HASH_H14_REG_ADDR			0x0678UL
-#define		HW_HASH_H15_REG_ADDR			0x067CUL
-#define		HW_HASH_CONTROL_REG_ADDR		0x07C0UL
-#define		HW_HASH_PAD_EN_REG_ADDR			0x07C4UL
-#define		HW_HASH_PAD_CFG_REG_ADDR		0x07C8UL
-#define		HW_HASH_CUR_LEN_0_REG_ADDR		0x07CCUL
-#define		HW_HASH_CUR_LEN_1_REG_ADDR		0x07D0UL
-#define		HW_HASH_CUR_LEN_2_REG_ADDR		0x07D4UL
-#define		HW_HASH_CUR_LEN_3_REG_ADDR		0x07D8UL
-#define		HW_HASH_PARAM_REG_ADDR			0x07DCUL
-#define		HW_HASH_INT_BUSY_REG_ADDR		0x07E0UL
-#define		HW_HASH_SW_RESET_REG_ADDR		0x07E4UL
-#define		HW_HASH_ENDIANESS_REG_ADDR		0x07E8UL
-#define		HW_HASH_DATA_REG_ADDR			0x07ECUL
-#define		HW_DRNG_CONTROL_REG_ADDR		0x0800UL
-#define		HW_DRNG_VALID_REG_ADDR			0x0804UL
-#define		HW_DRNG_DATA_REG_ADDR			0x0808UL
-#define		HW_RND_SRC_EN_REG_ADDR			0x080CUL
-#define		HW_AES_CLK_ENABLE_REG_ADDR		0x0810UL
-#define		HW_DES_CLK_ENABLE_REG_ADDR		0x0814UL
-#define		HW_HASH_CLK_ENABLE_REG_ADDR		0x0818UL
-#define		HW_PKI_CLK_ENABLE_REG_ADDR		0x081CUL
-#define		HW_CLK_STATUS_REG_ADDR			0x0824UL
-#define		HW_CLK_ENABLE_REG_ADDR			0x0828UL
-#define		HW_DRNG_SAMPLE_REG_ADDR			0x0850UL
-#define		HW_RND_SRC_CTL_REG_ADDR			0x0858UL
-#define		HW_CRYPTO_CTL_REG_ADDR			0x0900UL
-#define		HW_CRYPTO_STATUS_REG_ADDR		0x090CUL
-#define		HW_CRYPTO_BUSY_REG_ADDR			0x0910UL
-#define		HW_AES_BUSY_REG_ADDR			0x0914UL
-#define		HW_DES_BUSY_REG_ADDR			0x0918UL
-#define		HW_HASH_BUSY_REG_ADDR			0x091CUL
-#define		HW_CONTENT_REG_ADDR			0x0924UL
-#define		HW_VERSION_REG_ADDR			0x0928UL
-#define		HW_CONTEXT_ID_REG_ADDR			0x0930UL
-#define		HW_DIN_BUFFER_REG_ADDR			0x0C00UL
-#define		HW_DIN_MEM_DMA_BUSY_REG_ADDR		0x0c20UL
-#define		HW_SRC_LLI_MEM_ADDR_REG_ADDR		0x0c24UL
-#define		HW_SRC_LLI_WORD0_REG_ADDR		0x0C28UL
-#define		HW_SRC_LLI_WORD1_REG_ADDR		0x0C2CUL
-#define		HW_SRAM_SRC_ADDR_REG_ADDR		0x0c30UL
-#define		HW_DIN_SRAM_BYTES_LEN_REG_ADDR		0x0c34UL
-#define		HW_DIN_SRAM_DMA_BUSY_REG_ADDR		0x0C38UL
-#define		HW_WRITE_ALIGN_REG_ADDR			0x0C3CUL
-#define		HW_OLD_DATA_REG_ADDR			0x0C48UL
-#define		HW_WRITE_ALIGN_LAST_REG_ADDR		0x0C4CUL
-#define		HW_DOUT_BUFFER_REG_ADDR			0x0C00UL
-#define		HW_DST_LLI_WORD0_REG_ADDR		0x0D28UL
-#define		HW_DST_LLI_WORD1_REG_ADDR		0x0D2CUL
-#define		HW_DST_LLI_MEM_ADDR_REG_ADDR		0x0D24UL
-#define		HW_DOUT_MEM_DMA_BUSY_REG_ADDR		0x0D20UL
-#define		HW_SRAM_DEST_ADDR_REG_ADDR		0x0D30UL
-#define		HW_DOUT_SRAM_BYTES_LEN_REG_ADDR		0x0D34UL
-#define		HW_DOUT_SRAM_DMA_BUSY_REG_ADDR		0x0D38UL
-#define		HW_READ_ALIGN_REG_ADDR			0x0D3CUL
-#define		HW_READ_LAST_DATA_REG_ADDR		0x0D44UL
-#define		HW_RC4_THRU_CPU_REG_ADDR		0x0D4CUL
-#define		HW_AHB_SINGLE_REG_ADDR			0x0E00UL
-#define		HW_SRAM_DATA_REG_ADDR			0x0F00UL
-#define		HW_SRAM_ADDR_REG_ADDR			0x0F04UL
-#define		HW_SRAM_DATA_READY_REG_ADDR		0x0F08UL
 #define		HW_HOST_IRR_REG_ADDR			0x0A00UL
 #define		HW_HOST_IMR_REG_ADDR			0x0A04UL
 #define		HW_HOST_ICR_REG_ADDR			0x0A08UL
-#define		HW_HOST_SEP_SRAM_THRESHOLD_REG_ADDR	0x0A10UL
-#define		HW_HOST_SEP_BUSY_REG_ADDR		0x0A14UL
-#define		HW_HOST_SEP_LCS_REG_ADDR		0x0A18UL
-#define		HW_HOST_CC_SW_RST_REG_ADDR		0x0A40UL
-#define		HW_HOST_SEP_SW_RST_REG_ADDR		0x0A44UL
-#define		HW_HOST_FLOW_DMA_SW_INT0_REG_ADDR	0x0A80UL
-#define		HW_HOST_FLOW_DMA_SW_INT1_REG_ADDR	0x0A84UL
-#define		HW_HOST_FLOW_DMA_SW_INT2_REG_ADDR	0x0A88UL
-#define		HW_HOST_FLOW_DMA_SW_INT3_REG_ADDR	0x0A8cUL
-#define		HW_HOST_FLOW_DMA_SW_INT4_REG_ADDR	0x0A90UL
-#define		HW_HOST_FLOW_DMA_SW_INT5_REG_ADDR	0x0A94UL
-#define		HW_HOST_FLOW_DMA_SW_INT6_REG_ADDR	0x0A98UL
-#define		HW_HOST_FLOW_DMA_SW_INT7_REG_ADDR	0x0A9cUL
 #define		HW_HOST_SEP_HOST_GPR0_REG_ADDR		0x0B00UL
 #define		HW_HOST_SEP_HOST_GPR1_REG_ADDR		0x0B04UL
 #define		HW_HOST_SEP_HOST_GPR2_REG_ADDR		0x0B08UL
@@ -225,9 +51,6 @@
 #define		HW_HOST_HOST_SEP_GPR1_REG_ADDR		0x0B84UL
 #define		HW_HOST_HOST_SEP_GPR2_REG_ADDR		0x0B88UL
 #define		HW_HOST_HOST_SEP_GPR3_REG_ADDR		0x0B8CUL
-#define		HW_HOST_HOST_ENDIAN_REG_ADDR		0x0B90UL
-#define		HW_HOST_HOST_COMM_CLK_EN_REG_ADDR	0x0B94UL
-#define		HW_CLR_SRAM_BUSY_REG_REG_ADDR		0x0F0CUL
-#define		HW_CC_SRAM_BASE_ADDRESS			0x5800UL
+#define		HW_SRAM_DATA_READY_REG_ADDR		0x0F08UL
 
 #endif		/* ifndef HW_DEFS */
diff --git a/drivers/staging/sep/sep_main.c b/drivers/staging/sep/sep_main.c
new file mode 100644
index 0000000..ad54c2e
--- /dev/null
+++ b/drivers/staging/sep/sep_main.c
@@ -0,0 +1,4518 @@
+/*
+ *
+ *  sep_main.c - Security Processor Driver main group of functions
+ *
+ *  Copyright(c) 2009-2011 Intel Corporation. All rights reserved.
+ *  Contributions(c) 2009-2011 Discretix. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; version 2 of the License.
+ *
+ *  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., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ *  CONTACTS:
+ *
+ *  Mark Allyn		mark.a.allyn@intel.com
+ *  Jayant Mangalampalli jayant.mangalampalli@intel.com
+ *
+ *  CHANGES:
+ *
+ *  2009.06.26	Initial publish
+ *  2010.09.14  Upgrade to Medfield
+ *  2011.01.21  Move to sep_main.c to allow for sep_crypto.c
+ *  2011.02.22  Enable kernel crypto operation
+ *
+ *  Please note that this driver is based on information in the Discretix
+ *  CryptoCell 5.2 Driver Implementation Guide; the Discretix CryptoCell 5.2
+ *  Integration Intel Medfield appendix; the Discretix CryptoCell 5.2
+ *  Linux Driver Integration Guide; and the Discretix CryptoCell 5.2 System
+ *  Overview and Integration Guide.
+ */
+/* #define DEBUG */
+/* #define SEP_PERF_DEBUG */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/kdev_t.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <asm/current.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/pagemap.h>
+#include <asm/cacheflush.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/async.h>
+#include <linux/crypto.h>
+#include <crypto/internal/hash.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/sha.h>
+#include <crypto/md5.h>
+#include <crypto/aes.h>
+#include <crypto/des.h>
+#include <crypto/hash.h>
+
+#include "sep_driver_hw_defs.h"
+#include "sep_driver_config.h"
+#include "sep_driver_api.h"
+#include "sep_dev.h"
+#include "sep_crypto.h"
+
+#define CREATE_TRACE_POINTS
+#include "sep_trace_events.h"
+
+/*
+ * Let's not spend cycles iterating over message
+ * area contents if debugging not enabled
+ */
+#ifdef DEBUG
+#define sep_dump_message(sep)	_sep_dump_message(sep)
+#else
+#define sep_dump_message(sep)
+#endif
+
+/**
+ * Currenlty, there is only one SEP device per platform;
+ * In event platforms in the future have more than one SEP
+ * device, this will be a linked list
+ */
+
+struct sep_device *sep_dev;
+
+/**
+ * sep_queue_status_remove - Removes transaction from status queue
+ * @sep: SEP device
+ * @sep_queue_info: pointer to status queue
+ *
+ * This function will removes information about transaction from the queue.
+ */
+void sep_queue_status_remove(struct sep_device *sep,
+				      struct sep_queue_info **queue_elem)
+{
+	unsigned long lck_flags;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] sep_queue_status_remove\n",
+		current->pid);
+
+	if (!queue_elem || !(*queue_elem)) {
+		dev_dbg(&sep->pdev->dev, "PID%d %s null\n",
+					current->pid, __func__);
+		return;
+	}
+
+	spin_lock_irqsave(&sep->sep_queue_lock, lck_flags);
+	list_del(&(*queue_elem)->list);
+	sep->sep_queue_num--;
+	spin_unlock_irqrestore(&sep->sep_queue_lock, lck_flags);
+
+	kfree(*queue_elem);
+	*queue_elem = NULL;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] sep_queue_status_remove return\n",
+		current->pid);
+	return;
+}
+
+/**
+ * sep_queue_status_add - Adds transaction to status queue
+ * @sep: SEP device
+ * @opcode: transaction opcode
+ * @size: input data size
+ * @pid: pid of current process
+ * @name: current process name
+ * @name_len: length of name (current process)
+ *
+ * This function adds information about about transaction started to the status
+ * queue.
+ */
+struct sep_queue_info *sep_queue_status_add(
+						struct sep_device *sep,
+						u32 opcode,
+						u32 size,
+						u32 pid,
+						u8 *name, size_t name_len)
+{
+	unsigned long lck_flags;
+	struct sep_queue_info *my_elem = NULL;
+
+	my_elem = kzalloc(sizeof(struct sep_queue_info), GFP_KERNEL);
+
+	if (!my_elem)
+		return NULL;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] kzalloc ok\n", current->pid);
+
+	my_elem->data.opcode = opcode;
+	my_elem->data.size = size;
+	my_elem->data.pid = pid;
+
+	if (name_len > TASK_COMM_LEN)
+		name_len = TASK_COMM_LEN;
+
+	memcpy(&my_elem->data.name, name, name_len);
+
+	spin_lock_irqsave(&sep->sep_queue_lock, lck_flags);
+
+	list_add_tail(&my_elem->list, &sep->sep_queue_status);
+	sep->sep_queue_num++;
+
+	spin_unlock_irqrestore(&sep->sep_queue_lock, lck_flags);
+
+	return my_elem;
+}
+
+/**
+ *	sep_allocate_dmatables_region - Allocates buf for the MLLI/DMA tables
+ *	@sep: SEP device
+ *	@dmatables_region: Destination pointer for the buffer
+ *	@dma_ctx: DMA context for the transaction
+ *	@table_count: Number of MLLI/DMA tables to create
+ *	The buffer created will not work as-is for DMA operations,
+ *	it needs to be copied over to the appropriate place in the
+ *	shared area.
+ */
+static int sep_allocate_dmatables_region(struct sep_device *sep,
+					 void **dmatables_region,
+					 struct sep_dma_context *dma_ctx,
+					 const u32 table_count)
+{
+	const size_t new_len =
+		SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES - 1;
+
+	void *tmp_region = NULL;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] dma_ctx = 0x%p\n",
+				current->pid, dma_ctx);
+	dev_dbg(&sep->pdev->dev, "[PID%d] dmatables_region = 0x%p\n",
+				current->pid, dmatables_region);
+
+	if (!dma_ctx || !dmatables_region) {
+		dev_warn(&sep->pdev->dev,
+			"[PID%d] dma context/region uninitialized\n",
+			current->pid);
+		return -EINVAL;
+	}
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] newlen = 0x%08zX\n",
+				current->pid, new_len);
+	dev_dbg(&sep->pdev->dev, "[PID%d] oldlen = 0x%08X\n", current->pid,
+				dma_ctx->dmatables_len);
+	tmp_region = kzalloc(new_len + dma_ctx->dmatables_len, GFP_KERNEL);
+	if (!tmp_region) {
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] no mem for dma tables region\n",
+				current->pid);
+		return -ENOMEM;
+	}
+
+	/* Were there any previous tables that need to be preserved ? */
+	if (*dmatables_region) {
+		memcpy(tmp_region, *dmatables_region, dma_ctx->dmatables_len);
+		kfree(*dmatables_region);
+		*dmatables_region = NULL;
+	}
+
+	*dmatables_region = tmp_region;
+
+	dma_ctx->dmatables_len += new_len;
+
+	return 0;
+}
+
+/**
+ *	sep_wait_transaction - Used for synchronizing transactions
+ *	@sep: SEP device
+ */
+int sep_wait_transaction(struct sep_device *sep)
+{
+	int error = 0;
+	DEFINE_WAIT(wait);
+
+	if (0 == test_and_set_bit(SEP_TRANSACTION_STARTED_LOCK_BIT,
+				&sep->in_use_flags)) {
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] no transactions, returning\n",
+				current->pid);
+		goto end_function_setpid;
+	}
+
+	/*
+	 * Looping needed even for exclusive waitq entries
+	 * due to process wakeup latencies, previous process
+	 * might have already created another transaction.
+	 */
+	for (;;) {
+		/*
+		 * Exclusive waitq entry, so that only one process is
+		 * woken up from the queue at a time.
+		 */
+		prepare_to_wait_exclusive(&sep->event_transactions,
+					  &wait,
+					  TASK_INTERRUPTIBLE);
+		if (0 == test_and_set_bit(SEP_TRANSACTION_STARTED_LOCK_BIT,
+					  &sep->in_use_flags)) {
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] no transactions, breaking\n",
+					current->pid);
+			break;
+		}
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] transactions ongoing, sleeping\n",
+				current->pid);
+		schedule();
+		dev_dbg(&sep->pdev->dev, "[PID%d] woken up\n", current->pid);
+
+		if (signal_pending(current)) {
+			dev_dbg(&sep->pdev->dev, "[PID%d] received signal\n",
+							current->pid);
+			error = -EINTR;
+			goto end_function;
+		}
+	}
+end_function_setpid:
+	/*
+	 * The pid_doing_transaction indicates that this process
+	 * now owns the facilities to performa a transaction with
+	 * the SEP. While this process is performing a transaction,
+	 * no other process who has the SEP device open can perform
+	 * any transactions. This method allows more than one process
+	 * to have the device open at any given time, which provides
+	 * finer granularity for device utilization by multiple
+	 * processes.
+	 */
+	/* Only one process is able to progress here at a time */
+	sep->pid_doing_transaction = current->pid;
+
+end_function:
+	finish_wait(&sep->event_transactions, &wait);
+
+	return error;
+}
+
+/**
+ * sep_check_transaction_owner - Checks if current process owns transaction
+ * @sep: SEP device
+ */
+static inline int sep_check_transaction_owner(struct sep_device *sep)
+{
+	dev_dbg(&sep->pdev->dev, "[PID%d] transaction pid = %d\n",
+		current->pid,
+		sep->pid_doing_transaction);
+
+	if ((sep->pid_doing_transaction == 0) ||
+		(current->pid != sep->pid_doing_transaction)) {
+		return -EACCES;
+	}
+
+	/* We own the transaction */
+	return 0;
+}
+
+#ifdef DEBUG
+
+/**
+ * sep_dump_message - dump the message that is pending
+ * @sep: SEP device
+ * This will only print dump if DEBUG is set; it does
+ * follow kernel debug print enabling
+ */
+static void _sep_dump_message(struct sep_device *sep)
+{
+	int count;
+
+	u32 *p = sep->shared_addr;
+
+	for (count = 0; count < 10 * 4; count += 4)
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] Word %d of the message is %x\n",
+				current->pid, count/4, *p++);
+}
+
+#endif
+
+/**
+ * sep_map_and_alloc_shared_area -allocate shared block
+ * @sep: security processor
+ * @size: size of shared area
+ */
+static int sep_map_and_alloc_shared_area(struct sep_device *sep)
+{
+	sep->shared_addr = dma_alloc_coherent(&sep->pdev->dev,
+		sep->shared_size,
+		&sep->shared_bus, GFP_KERNEL);
+
+	if (!sep->shared_addr) {
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] shared memory dma_alloc_coherent failed\n",
+				current->pid);
+		return -ENOMEM;
+	}
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] shared_addr %zx bytes @%p (bus %llx)\n",
+				current->pid,
+				sep->shared_size, sep->shared_addr,
+				(unsigned long long)sep->shared_bus);
+	return 0;
+}
+
+/**
+ * sep_unmap_and_free_shared_area - free shared block
+ * @sep: security processor
+ */
+static void sep_unmap_and_free_shared_area(struct sep_device *sep)
+{
+	dma_free_coherent(&sep->pdev->dev, sep->shared_size,
+				sep->shared_addr, sep->shared_bus);
+}
+
+#ifdef DEBUG
+
+/**
+ * sep_shared_bus_to_virt - convert bus/virt addresses
+ * @sep: pointer to struct sep_device
+ * @bus_address: address to convert
+ *
+ * Returns virtual address inside the shared area according
+ * to the bus address.
+ */
+static void *sep_shared_bus_to_virt(struct sep_device *sep,
+						dma_addr_t bus_address)
+{
+	return sep->shared_addr + (bus_address - sep->shared_bus);
+}
+
+#endif
+
+/**
+ * sep_open - device open method
+ * @inode: inode of SEP device
+ * @filp: file handle to SEP device
+ *
+ * Open method for the SEP device. Called when userspace opens
+ * the SEP device node.
+ *
+ * Returns zero on success otherwise an error code.
+ */
+static int sep_open(struct inode *inode, struct file *filp)
+{
+	struct sep_device *sep;
+	struct sep_private_data *priv;
+
+	dev_dbg(&sep_dev->pdev->dev, "[PID%d] open\n", current->pid);
+
+	if (filp->f_flags & O_NONBLOCK)
+		return -ENOTSUPP;
+
+	/*
+	 * Get the SEP device structure and use it for the
+	 * private_data field in filp for other methods
+	 */
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	sep = sep_dev;
+	priv->device = sep;
+	filp->private_data = priv;
+
+	dev_dbg(&sep_dev->pdev->dev, "[PID%d] priv is 0x%p\n",
+					current->pid, priv);
+
+	/* Anyone can open; locking takes place at transaction level */
+	return 0;
+}
+
+/**
+ * sep_free_dma_table_data_handler - free DMA table
+ * @sep: pointere to struct sep_device
+ * @dma_ctx: dma context
+ *
+ * Handles the request to  free DMA table for synchronic actions
+ */
+int sep_free_dma_table_data_handler(struct sep_device *sep,
+					   struct sep_dma_context **dma_ctx)
+{
+	int count;
+	int dcb_counter;
+	/* Pointer to the current dma_resource struct */
+	struct sep_dma_resource *dma;
+
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] sep_free_dma_table_data_handler\n",
+			current->pid);
+
+	if (!dma_ctx || !(*dma_ctx)) {
+		/* No context or context already freed */
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] no DMA context or context already freed\n",
+				current->pid);
+
+		return 0;
+	}
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] (*dma_ctx)->nr_dcb_creat 0x%x\n",
+					current->pid,
+					(*dma_ctx)->nr_dcb_creat);
+
+	for (dcb_counter = 0;
+	     dcb_counter < (*dma_ctx)->nr_dcb_creat; dcb_counter++) {
+		dma = &(*dma_ctx)->dma_res_arr[dcb_counter];
+
+		/* Unmap and free input map array */
+		if (dma->in_map_array) {
+			for (count = 0; count < dma->in_num_pages; count++) {
+				dma_unmap_page(&sep->pdev->dev,
+					dma->in_map_array[count].dma_addr,
+					dma->in_map_array[count].size,
+					DMA_TO_DEVICE);
+			}
+			kfree(dma->in_map_array);
+		}
+
+		/**
+		 * Output is handled different. If
+		 * this was a secure dma into restricted memory,
+		 * then we skip this step altogether as restricted
+		 * memory is not available to the o/s at all.
+		 */
+		if (((*dma_ctx)->secure_dma == false) &&
+			(dma->out_map_array)) {
+
+			for (count = 0; count < dma->out_num_pages; count++) {
+				dma_unmap_page(&sep->pdev->dev,
+					dma->out_map_array[count].dma_addr,
+					dma->out_map_array[count].size,
+					DMA_FROM_DEVICE);
+			}
+			kfree(dma->out_map_array);
+		}
+
+		/* Free page cache for output */
+		if (dma->in_page_array) {
+			for (count = 0; count < dma->in_num_pages; count++) {
+				flush_dcache_page(dma->in_page_array[count]);
+				page_cache_release(dma->in_page_array[count]);
+			}
+			kfree(dma->in_page_array);
+		}
+
+		/* Again, we do this only for non secure dma */
+		if (((*dma_ctx)->secure_dma == false) &&
+			(dma->out_page_array)) {
+
+			for (count = 0; count < dma->out_num_pages; count++) {
+				if (!PageReserved(dma->out_page_array[count]))
+
+					SetPageDirty(dma->
+					out_page_array[count]);
+
+				flush_dcache_page(dma->out_page_array[count]);
+				page_cache_release(dma->out_page_array[count]);
+			}
+			kfree(dma->out_page_array);
+		}
+
+		/**
+		 * Note that here we use in_map_num_entries because we
+		 * don't have a page array; the page array is generated
+		 * only in the lock_user_pages, which is not called
+		 * for kernel crypto, which is what the sg (scatter gather
+		 * is used for exclusively
+		 */
+		if (dma->src_sg) {
+			dma_unmap_sg(&sep->pdev->dev, dma->src_sg,
+				dma->in_map_num_entries, DMA_TO_DEVICE);
+			dma->src_sg = NULL;
+		}
+
+		if (dma->dst_sg) {
+			dma_unmap_sg(&sep->pdev->dev, dma->dst_sg,
+				dma->in_map_num_entries, DMA_FROM_DEVICE);
+			dma->dst_sg = NULL;
+		}
+
+		/* Reset all the values */
+		dma->in_page_array = NULL;
+		dma->out_page_array = NULL;
+		dma->in_num_pages = 0;
+		dma->out_num_pages = 0;
+		dma->in_map_array = NULL;
+		dma->out_map_array = NULL;
+		dma->in_map_num_entries = 0;
+		dma->out_map_num_entries = 0;
+	}
+
+	(*dma_ctx)->nr_dcb_creat = 0;
+	(*dma_ctx)->num_lli_tables_created = 0;
+
+	kfree(*dma_ctx);
+	*dma_ctx = NULL;
+
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] sep_free_dma_table_data_handler end\n",
+			current->pid);
+
+	return 0;
+}
+
+/**
+ * sep_end_transaction_handler - end transaction
+ * @sep: pointer to struct sep_device
+ * @dma_ctx: DMA context
+ * @call_status: Call status
+ *
+ * This API handles the end transaction request.
+ */
+static int sep_end_transaction_handler(struct sep_device *sep,
+				       struct sep_dma_context **dma_ctx,
+				       struct sep_call_status *call_status,
+				       struct sep_queue_info **my_queue_elem)
+{
+	dev_dbg(&sep->pdev->dev, "[PID%d] ending transaction\n", current->pid);
+
+	/*
+	 * Extraneous transaction clearing would mess up PM
+	 * device usage counters and SEP would get suspended
+	 * just before we send a command to SEP in the next
+	 * transaction
+	 * */
+	if (sep_check_transaction_owner(sep)) {
+		dev_dbg(&sep->pdev->dev, "[PID%d] not transaction owner\n",
+						current->pid);
+		return 0;
+	}
+
+	/* Update queue status */
+	sep_queue_status_remove(sep, my_queue_elem);
+
+	/* Check that all the DMA resources were freed */
+	if (dma_ctx)
+		sep_free_dma_table_data_handler(sep, dma_ctx);
+
+	/* Reset call status for next transaction */
+	if (call_status)
+		call_status->status = 0;
+
+	/* Clear the message area to avoid next transaction reading
+	 * sensitive results from previous transaction */
+	memset(sep->shared_addr, 0,
+	       SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES);
+
+	/* start suspend delay */
+#ifdef SEP_ENABLE_RUNTIME_PM
+	if (sep->in_use) {
+		sep->in_use = 0;
+		pm_runtime_mark_last_busy(&sep->pdev->dev);
+		pm_runtime_put_autosuspend(&sep->pdev->dev);
+	}
+#endif
+
+	clear_bit(SEP_WORKING_LOCK_BIT, &sep->in_use_flags);
+	sep->pid_doing_transaction = 0;
+
+	/* Now it's safe for next process to proceed */
+	dev_dbg(&sep->pdev->dev, "[PID%d] waking up next transaction\n",
+					current->pid);
+	clear_bit(SEP_TRANSACTION_STARTED_LOCK_BIT, &sep->in_use_flags);
+	wake_up(&sep->event_transactions);
+
+	return 0;
+}
+
+
+/**
+ * sep_release - close a SEP device
+ * @inode: inode of SEP device
+ * @filp: file handle being closed
+ *
+ * Called on the final close of a SEP device.
+ */
+static int sep_release(struct inode *inode, struct file *filp)
+{
+	struct sep_private_data * const private_data = filp->private_data;
+	struct sep_call_status *call_status = &private_data->call_status;
+	struct sep_device *sep = private_data->device;
+	struct sep_dma_context **dma_ctx = &private_data->dma_ctx;
+	struct sep_queue_info **my_queue_elem = &private_data->my_queue_elem;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] release\n", current->pid);
+
+	sep_end_transaction_handler(sep, dma_ctx, call_status,
+		my_queue_elem);
+
+	kfree(filp->private_data);
+
+	return 0;
+}
+
+/**
+ * sep_mmap -  maps the shared area to user space
+ * @filp: pointer to struct file
+ * @vma: pointer to vm_area_struct
+ *
+ * Called on an mmap of our space via the normal SEP device
+ */
+static int sep_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct sep_private_data * const private_data = filp->private_data;
+	struct sep_call_status *call_status = &private_data->call_status;
+	struct sep_device *sep = private_data->device;
+	struct sep_queue_info **my_queue_elem = &private_data->my_queue_elem;
+	dma_addr_t bus_addr;
+	unsigned long error = 0;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] sep_mmap\n", current->pid);
+
+	/* Set the transaction busy (own the device) */
+	/*
+	 * Problem for multithreaded applications is that here we're
+	 * possibly going to sleep while holding a write lock on
+	 * current->mm->mmap_sem, which will cause deadlock for ongoing
+	 * transaction trying to create DMA tables
+	 */
+	error = sep_wait_transaction(sep);
+	if (error)
+		/* Interrupted by signal, don't clear transaction */
+		goto end_function;
+
+	/* Clear the message area to avoid next transaction reading
+	 * sensitive results from previous transaction */
+	memset(sep->shared_addr, 0,
+	       SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES);
+
+	/*
+	 * Check that the size of the mapped range is as the size of the message
+	 * shared area
+	 */
+	if ((vma->vm_end - vma->vm_start) > SEP_DRIVER_MMMAP_AREA_SIZE) {
+		error = -EINVAL;
+		goto end_function_with_error;
+	}
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] shared_addr is %p\n",
+					current->pid, sep->shared_addr);
+
+	/* Get bus address */
+	bus_addr = sep->shared_bus;
+
+	if (remap_pfn_range(vma, vma->vm_start, bus_addr >> PAGE_SHIFT,
+		vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
+		dev_dbg(&sep->pdev->dev, "[PID%d] remap_page_range failed\n",
+						current->pid);
+		error = -EAGAIN;
+		goto end_function_with_error;
+	}
+
+	/* Update call status */
+	set_bit(SEP_LEGACY_MMAP_DONE_OFFSET, &call_status->status);
+
+	goto end_function;
+
+end_function_with_error:
+	/* Clear our transaction */
+	sep_end_transaction_handler(sep, NULL, call_status,
+		my_queue_elem);
+
+end_function:
+	return error;
+}
+
+/**
+ * sep_poll - poll handler
+ * @filp:	pointer to struct file
+ * @wait:	pointer to poll_table
+ *
+ * Called by the OS when the kernel is asked to do a poll on
+ * a SEP file handle.
+ */
+static unsigned int sep_poll(struct file *filp, poll_table *wait)
+{
+	struct sep_private_data * const private_data = filp->private_data;
+	struct sep_call_status *call_status = &private_data->call_status;
+	struct sep_device *sep = private_data->device;
+	u32 mask = 0;
+	u32 retval = 0;
+	u32 retval2 = 0;
+	unsigned long lock_irq_flag;
+
+	/* Am I the process that owns the transaction? */
+	if (sep_check_transaction_owner(sep)) {
+		dev_dbg(&sep->pdev->dev, "[PID%d] poll pid not owner\n",
+						current->pid);
+		mask = POLLERR;
+		goto end_function;
+	}
+
+	/* Check if send command or send_reply were activated previously */
+	if (0 == test_bit(SEP_LEGACY_SENDMSG_DONE_OFFSET,
+			  &call_status->status)) {
+		dev_warn(&sep->pdev->dev, "[PID%d] sendmsg not called\n",
+						current->pid);
+		mask = POLLERR;
+		goto end_function;
+	}
+
+
+	/* Add the event to the polling wait table */
+	dev_dbg(&sep->pdev->dev, "[PID%d] poll: calling wait sep_event\n",
+					current->pid);
+
+	poll_wait(filp, &sep->event_interrupt, wait);
+
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] poll: send_ct is %lx reply ct is %lx\n",
+			current->pid, sep->send_ct, sep->reply_ct);
+
+	/* Check if error occured during poll */
+	retval2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
+	if ((retval2 != 0x0) && (retval2 != 0x8)) {
+		dev_dbg(&sep->pdev->dev, "[PID%d] poll; poll error %x\n",
+						current->pid, retval2);
+		mask |= POLLERR;
+		goto end_function;
+	}
+
+	spin_lock_irqsave(&sep->snd_rply_lck, lock_irq_flag);
+
+	if (sep->send_ct == sep->reply_ct) {
+		spin_unlock_irqrestore(&sep->snd_rply_lck, lock_irq_flag);
+		retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] poll: data ready check (GPR2)  %x\n",
+				current->pid, retval);
+
+		/* Check if printf request  */
+		if ((retval >> 30) & 0x1) {
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] poll: SEP printf request\n",
+					current->pid);
+			goto end_function;
+		}
+
+		/* Check if the this is SEP reply or request */
+		if (retval >> 31) {
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] poll: SEP request\n",
+					current->pid);
+		} else {
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] poll: normal return\n",
+					current->pid);
+			sep_dump_message(sep);
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] poll; SEP reply POLLIN|POLLRDNORM\n",
+					current->pid);
+			mask |= POLLIN | POLLRDNORM;
+		}
+		set_bit(SEP_LEGACY_POLL_DONE_OFFSET, &call_status->status);
+	} else {
+		spin_unlock_irqrestore(&sep->snd_rply_lck, lock_irq_flag);
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] poll; no reply; returning mask of 0\n",
+				current->pid);
+		mask = 0;
+	}
+
+end_function:
+	return mask;
+}
+
+/**
+ * sep_time_address - address in SEP memory of time
+ * @sep: SEP device we want the address from
+ *
+ * Return the address of the two dwords in memory used for time
+ * setting.
+ */
+static u32 *sep_time_address(struct sep_device *sep)
+{
+	return sep->shared_addr +
+		SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES;
+}
+
+/**
+ * sep_set_time - set the SEP time
+ * @sep: the SEP we are setting the time for
+ *
+ * Calculates time and sets it at the predefined address.
+ * Called with the SEP mutex held.
+ */
+static unsigned long sep_set_time(struct sep_device *sep)
+{
+	struct timeval time;
+	u32 *time_addr;	/* Address of time as seen by the kernel */
+
+
+	do_gettimeofday(&time);
+
+	/* Set value in the SYSTEM MEMORY offset */
+	time_addr = sep_time_address(sep);
+
+	time_addr[0] = SEP_TIME_VAL_TOKEN;
+	time_addr[1] = time.tv_sec;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] time.tv_sec is %lu\n",
+					current->pid, time.tv_sec);
+	dev_dbg(&sep->pdev->dev, "[PID%d] time_addr is %p\n",
+					current->pid, time_addr);
+	dev_dbg(&sep->pdev->dev, "[PID%d] sep->shared_addr is %p\n",
+					current->pid, sep->shared_addr);
+
+	return time.tv_sec;
+}
+
+/**
+ * sep_send_command_handler - kick off a command
+ * @sep: SEP being signalled
+ *
+ * This function raises interrupt to SEP that signals that is has a new
+ * command from the host
+ *
+ * Note that this function does fall under the ioctl lock
+ */
+int sep_send_command_handler(struct sep_device *sep)
+{
+	unsigned long lock_irq_flag;
+	u32 *msg_pool;
+	int error = 0;
+
+	/* Basic sanity check; set msg pool to start of shared area */
+	msg_pool = (u32 *)sep->shared_addr;
+	msg_pool += 2;
+
+	/* Look for start msg token */
+	if (*msg_pool != SEP_START_MSG_TOKEN) {
+		dev_warn(&sep->pdev->dev, "start message token not present\n");
+		error = -EPROTO;
+		goto end_function;
+	}
+
+	/* Do we have a reasonable size? */
+	msg_pool += 1;
+	if ((*msg_pool < 2) ||
+		(*msg_pool > SEP_DRIVER_MAX_MESSAGE_SIZE_IN_BYTES)) {
+
+		dev_warn(&sep->pdev->dev, "invalid message size\n");
+		error = -EPROTO;
+		goto end_function;
+	}
+
+	/* Does the command look reasonable? */
+	msg_pool += 1;
+	if (*msg_pool < 2) {
+		dev_warn(&sep->pdev->dev, "invalid message opcode\n");
+		error = -EPROTO;
+		goto end_function;
+	}
+
+#if defined(CONFIG_PM_RUNTIME) && defined(SEP_ENABLE_RUNTIME_PM)
+	dev_dbg(&sep->pdev->dev, "[PID%d] before pm sync status 0x%X\n",
+					current->pid,
+					sep->pdev->dev.power.runtime_status);
+	sep->in_use = 1; /* device is about to be used */
+	pm_runtime_get_sync(&sep->pdev->dev);
+#endif
+
+	if (test_and_set_bit(SEP_WORKING_LOCK_BIT, &sep->in_use_flags)) {
+		error = -EPROTO;
+		goto end_function;
+	}
+	sep->in_use = 1; /* device is about to be used */
+	sep_set_time(sep);
+
+	sep_dump_message(sep);
+
+	/* Update counter */
+	spin_lock_irqsave(&sep->snd_rply_lck, lock_irq_flag);
+	sep->send_ct++;
+	spin_unlock_irqrestore(&sep->snd_rply_lck, lock_irq_flag);
+
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] sep_send_command_handler send_ct %lx reply_ct %lx\n",
+			current->pid, sep->send_ct, sep->reply_ct);
+
+	/* Send interrupt to SEP */
+	sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2);
+
+end_function:
+	return error;
+}
+
+/**
+ *	sep_crypto_dma -
+ *	@sep: pointer to struct sep_device
+ *	@sg: pointer to struct scatterlist
+ *	@direction:
+ *	@dma_maps: pointer to place a pointer to array of dma maps
+ *	 This is filled in; anything previous there will be lost
+ *	 The structure for dma maps is sep_dma_map
+ *	@returns number of dma maps on success; negative on error
+ *
+ *	This creates the dma table from the scatterlist
+ *	It is used only for kernel crypto as it works with scatterlists
+ *	representation of data buffers
+ *
+ */
+static int sep_crypto_dma(
+	struct sep_device *sep,
+	struct scatterlist *sg,
+	struct sep_dma_map **dma_maps,
+	enum dma_data_direction direction)
+{
+	struct scatterlist *temp_sg;
+
+	u32 count_segment;
+	u32 count_mapped;
+	struct sep_dma_map *sep_dma;
+	int ct1;
+
+	if (sg->length == 0)
+		return 0;
+
+	/* Count the segments */
+	temp_sg = sg;
+	count_segment = 0;
+	while (temp_sg) {
+		count_segment += 1;
+		temp_sg = scatterwalk_sg_next(temp_sg);
+	}
+	dev_dbg(&sep->pdev->dev,
+		"There are (hex) %x segments in sg\n", count_segment);
+
+	/* DMA map segments */
+	count_mapped = dma_map_sg(&sep->pdev->dev, sg,
+		count_segment, direction);
+
+	dev_dbg(&sep->pdev->dev,
+		"There are (hex) %x maps in sg\n", count_mapped);
+
+	if (count_mapped == 0) {
+		dev_dbg(&sep->pdev->dev, "Cannot dma_map_sg\n");
+		return -ENOMEM;
+	}
+
+	sep_dma = kmalloc(sizeof(struct sep_dma_map) *
+		count_mapped, GFP_ATOMIC);
+
+	if (sep_dma == NULL) {
+		dev_dbg(&sep->pdev->dev, "Cannot allocate dma_maps\n");
+		return -ENOMEM;
+	}
+
+	for_each_sg(sg, temp_sg, count_mapped, ct1) {
+		sep_dma[ct1].dma_addr = sg_dma_address(temp_sg);
+		sep_dma[ct1].size = sg_dma_len(temp_sg);
+		dev_dbg(&sep->pdev->dev, "(all hex) map %x dma %lx len %lx\n",
+			ct1, (unsigned long)sep_dma[ct1].dma_addr,
+			(unsigned long)sep_dma[ct1].size);
+		}
+
+	*dma_maps = sep_dma;
+	return count_mapped;
+
+}
+
+/**
+ *	sep_crypto_lli -
+ *	@sep: pointer to struct sep_device
+ *	@sg: pointer to struct scatterlist
+ *	@data_size: total data size
+ *	@direction:
+ *	@dma_maps: pointer to place a pointer to array of dma maps
+ *	 This is filled in; anything previous there will be lost
+ *	 The structure for dma maps is sep_dma_map
+ *	@lli_maps: pointer to place a pointer to array of lli maps
+ *	 This is filled in; anything previous there will be lost
+ *	 The structure for dma maps is sep_dma_map
+ *	@returns number of dma maps on success; negative on error
+ *
+ *	This creates the LLI table from the scatterlist
+ *	It is only used for kernel crypto as it works exclusively
+ *	with scatterlists (struct scatterlist) representation of
+ *	data buffers
+ */
+static int sep_crypto_lli(
+	struct sep_device *sep,
+	struct scatterlist *sg,
+	struct sep_dma_map **maps,
+	struct sep_lli_entry **llis,
+	u32 data_size,
+	enum dma_data_direction direction)
+{
+
+	int ct1;
+	struct sep_lli_entry *sep_lli;
+	struct sep_dma_map *sep_map;
+
+	int nbr_ents;
+
+	nbr_ents = sep_crypto_dma(sep, sg, maps, direction);
+	if (nbr_ents <= 0) {
+		dev_dbg(&sep->pdev->dev, "crypto_dma failed %x\n",
+			nbr_ents);
+		return nbr_ents;
+	}
+
+	sep_map = *maps;
+
+	sep_lli = kmalloc(sizeof(struct sep_lli_entry) * nbr_ents, GFP_ATOMIC);
+
+	if (sep_lli == NULL) {
+		dev_dbg(&sep->pdev->dev, "Cannot allocate lli_maps\n");
+
+		kfree(*maps);
+		*maps = NULL;
+		return -ENOMEM;
+	}
+
+	for (ct1 = 0; ct1 < nbr_ents; ct1 += 1) {
+		sep_lli[ct1].bus_address = (u32)sep_map[ct1].dma_addr;
+
+		/* Maximum for page is total data size */
+		if (sep_map[ct1].size > data_size)
+			sep_map[ct1].size = data_size;
+
+		sep_lli[ct1].block_size = (u32)sep_map[ct1].size;
+	}
+
+	*llis = sep_lli;
+	return nbr_ents;
+}
+
+/**
+ *	sep_lock_kernel_pages - map kernel pages for DMA
+ *	@sep: pointer to struct sep_device
+ *	@kernel_virt_addr: address of data buffer in kernel
+ *	@data_size: size of data
+ *	@lli_array_ptr: lli array
+ *	@in_out_flag: input into device or output from device
+ *
+ *	This function locks all the physical pages of the kernel virtual buffer
+ *	and construct a basic lli  array, where each entry holds the physical
+ *	page address and the size that application data holds in this page
+ *	This function is used only during kernel crypto mod calls from within
+ *	the kernel (when ioctl is not used)
+ *
+ *	This is used only for kernel crypto. Kernel pages
+ *	are handled differently as they are done via
+ *	scatter gather lists (struct scatterlist)
+ */
+static int sep_lock_kernel_pages(struct sep_device *sep,
+	unsigned long kernel_virt_addr,
+	u32 data_size,
+	struct sep_lli_entry **lli_array_ptr,
+	int in_out_flag,
+	struct sep_dma_context *dma_ctx)
+
+{
+	u32 num_pages;
+	struct scatterlist *sg;
+
+	/* Array of lli */
+	struct sep_lli_entry *lli_array;
+	/* Map array */
+	struct sep_dma_map *map_array;
+
+	enum dma_data_direction direction;
+
+	lli_array = NULL;
+	map_array = NULL;
+
+	if (in_out_flag == SEP_DRIVER_IN_FLAG) {
+		direction = DMA_TO_DEVICE;
+		sg = dma_ctx->src_sg;
+	} else {
+		direction = DMA_FROM_DEVICE;
+		sg = dma_ctx->dst_sg;
+	}
+
+	num_pages = sep_crypto_lli(sep, sg, &map_array, &lli_array,
+		data_size, direction);
+
+	if (num_pages <= 0) {
+		dev_dbg(&sep->pdev->dev, "sep_crypto_lli returned error %x\n",
+			num_pages);
+		return -ENOMEM;
+	}
+
+	/* Put mapped kernel sg into kernel resource array */
+
+	/* Set output params acording to the in_out flag */
+	if (in_out_flag == SEP_DRIVER_IN_FLAG) {
+		*lli_array_ptr = lli_array;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_num_pages =
+								num_pages;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_page_array =
+								NULL;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_map_array =
+								map_array;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_map_num_entries =
+								num_pages;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].src_sg =
+			dma_ctx->src_sg;
+	} else {
+		*lli_array_ptr = lli_array;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_num_pages =
+								num_pages;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_page_array =
+								NULL;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_map_array =
+								map_array;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].
+					out_map_num_entries = num_pages;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].dst_sg =
+			dma_ctx->dst_sg;
+	}
+
+	return 0;
+}
+
+/**
+ * sep_lock_user_pages - lock and map user pages for DMA
+ * @sep: pointer to struct sep_device
+ * @app_virt_addr: user memory data buffer
+ * @data_size: size of data buffer
+ * @lli_array_ptr: lli array
+ * @in_out_flag: input or output to device
+ *
+ * This function locks all the physical pages of the application
+ * virtual buffer and construct a basic lli  array, where each entry
+ * holds the physical page address and the size that application
+ * data holds in this physical pages
+ */
+static int sep_lock_user_pages(struct sep_device *sep,
+	u32 app_virt_addr,
+	u32 data_size,
+	struct sep_lli_entry **lli_array_ptr,
+	int in_out_flag,
+	struct sep_dma_context *dma_ctx)
+
+{
+	int error = 0;
+	u32 count;
+	int result;
+	/* The the page of the end address of the user space buffer */
+	u32 end_page;
+	/* The page of the start address of the user space buffer */
+	u32 start_page;
+	/* The range in pages */
+	u32 num_pages;
+	/* Array of pointers to page */
+	struct page **page_array;
+	/* Array of lli */
+	struct sep_lli_entry *lli_array;
+	/* Map array */
+	struct sep_dma_map *map_array;
+
+	/* Set start and end pages  and num pages */
+	end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT;
+	start_page = app_virt_addr >> PAGE_SHIFT;
+	num_pages = end_page - start_page + 1;
+
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] lock user pages app_virt_addr is %x\n",
+			current->pid, app_virt_addr);
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] data_size is (hex) %x\n",
+					current->pid, data_size);
+	dev_dbg(&sep->pdev->dev, "[PID%d] start_page is (hex) %x\n",
+					current->pid, start_page);
+	dev_dbg(&sep->pdev->dev, "[PID%d] end_page is (hex) %x\n",
+					current->pid, end_page);
+	dev_dbg(&sep->pdev->dev, "[PID%d] num_pages is (hex) %x\n",
+					current->pid, num_pages);
+
+	/* Allocate array of pages structure pointers */
+	page_array = kmalloc(sizeof(struct page *) * num_pages, GFP_ATOMIC);
+	if (!page_array) {
+		error = -ENOMEM;
+		goto end_function;
+	}
+	map_array = kmalloc(sizeof(struct sep_dma_map) * num_pages, GFP_ATOMIC);
+	if (!map_array) {
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] kmalloc for map_array failed\n",
+				current->pid);
+		error = -ENOMEM;
+		goto end_function_with_error1;
+	}
+
+	lli_array = kmalloc(sizeof(struct sep_lli_entry) * num_pages,
+		GFP_ATOMIC);
+
+	if (!lli_array) {
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] kmalloc for lli_array failed\n",
+				current->pid);
+		error = -ENOMEM;
+		goto end_function_with_error2;
+	}
+
+	/* Convert the application virtual address into a set of physical */
+	down_read(&current->mm->mmap_sem);
+	result = get_user_pages(current, current->mm, app_virt_addr,
+		num_pages,
+		((in_out_flag == SEP_DRIVER_IN_FLAG) ? 0 : 1),
+		0, page_array, NULL);
+
+	up_read(&current->mm->mmap_sem);
+
+	/* Check the number of pages locked - if not all then exit with error */
+	if (result != num_pages) {
+		dev_warn(&sep->pdev->dev,
+			"[PID%d] not all pages locked by get_user_pages, "
+			"result 0x%X, num_pages 0x%X\n",
+				current->pid, result, num_pages);
+		error = -ENOMEM;
+		goto end_function_with_error3;
+	}
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] get_user_pages succeeded\n",
+					current->pid);
+
+	/*
+	 * Fill the array using page array data and
+	 * map the pages - this action will also flush the cache as needed
+	 */
+	for (count = 0; count < num_pages; count++) {
+		/* Fill the map array */
+		map_array[count].dma_addr =
+			dma_map_page(&sep->pdev->dev, page_array[count],
+			0, PAGE_SIZE, DMA_BIDIRECTIONAL);
+
+		map_array[count].size = PAGE_SIZE;
+
+		/* Fill the lli array entry */
+		lli_array[count].bus_address = (u32)map_array[count].dma_addr;
+		lli_array[count].block_size = PAGE_SIZE;
+
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] lli_array[%x].bus_address is %08lx, "
+			"lli_array[%x].block_size is (hex) %x\n", current->pid,
+			count, (unsigned long)lli_array[count].bus_address,
+			count, lli_array[count].block_size);
+	}
+
+	/* Check the offset for the first page */
+	lli_array[0].bus_address =
+		lli_array[0].bus_address + (app_virt_addr & (~PAGE_MASK));
+
+	/* Check that not all the data is in the first page only */
+	if ((PAGE_SIZE - (app_virt_addr & (~PAGE_MASK))) >= data_size)
+		lli_array[0].block_size = data_size;
+	else
+		lli_array[0].block_size =
+			PAGE_SIZE - (app_virt_addr & (~PAGE_MASK));
+
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] After check if page 0 has all data\n",
+			current->pid);
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] lli_array[0].bus_address is (hex) %08lx, "
+			"lli_array[0].block_size is (hex) %x\n",
+			current->pid,
+			(unsigned long)lli_array[0].bus_address,
+			lli_array[0].block_size);
+
+
+	/* Check the size of the last page */
+	if (num_pages > 1) {
+		lli_array[num_pages - 1].block_size =
+			(app_virt_addr + data_size) & (~PAGE_MASK);
+		if (lli_array[num_pages - 1].block_size == 0)
+			lli_array[num_pages - 1].block_size = PAGE_SIZE;
+
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] After last page size adjustment\n",
+			current->pid);
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] lli_array[%x].bus_address is (hex) %08lx, "
+			"lli_array[%x].block_size is (hex) %x\n",
+			current->pid,
+			num_pages - 1,
+			(unsigned long)lli_array[num_pages - 1].bus_address,
+			num_pages - 1,
+			lli_array[num_pages - 1].block_size);
+	}
+
+	/* Set output params acording to the in_out flag */
+	if (in_out_flag == SEP_DRIVER_IN_FLAG) {
+		*lli_array_ptr = lli_array;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_num_pages =
+								num_pages;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_page_array =
+								page_array;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_map_array =
+								map_array;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_map_num_entries =
+								num_pages;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].src_sg = NULL;
+	} else {
+		*lli_array_ptr = lli_array;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_num_pages =
+								num_pages;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_page_array =
+								page_array;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_map_array =
+								map_array;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].
+					out_map_num_entries = num_pages;
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].dst_sg = NULL;
+	}
+	goto end_function;
+
+end_function_with_error3:
+	/* Free lli array */
+	kfree(lli_array);
+
+end_function_with_error2:
+	kfree(map_array);
+
+end_function_with_error1:
+	/* Free page array */
+	kfree(page_array);
+
+end_function:
+	return error;
+}
+
+/**
+ *	sep_lli_table_secure_dma - get lli array for IMR addresses
+ *	@sep: pointer to struct sep_device
+ *	@app_virt_addr: user memory data buffer
+ *	@data_size: size of data buffer
+ *	@lli_array_ptr: lli array
+ *	@in_out_flag: not used
+ *	@dma_ctx: pointer to struct sep_dma_context
+ *
+ *	This function creates lli tables for outputting data to
+ *	IMR memory, which is memory that cannot be accessed by the
+ *	the x86 processor.
+ */
+static int sep_lli_table_secure_dma(struct sep_device *sep,
+	u32 app_virt_addr,
+	u32 data_size,
+	struct sep_lli_entry **lli_array_ptr,
+	int in_out_flag,
+	struct sep_dma_context *dma_ctx)
+
+{
+	int error = 0;
+	u32 count;
+	/* The the page of the end address of the user space buffer */
+	u32 end_page;
+	/* The page of the start address of the user space buffer */
+	u32 start_page;
+	/* The range in pages */
+	u32 num_pages;
+	/* Array of lli */
+	struct sep_lli_entry *lli_array;
+
+	/* Set start and end pages  and num pages */
+	end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT;
+	start_page = app_virt_addr >> PAGE_SHIFT;
+	num_pages = end_page - start_page + 1;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] lock user pages"
+		" app_virt_addr is %x\n", current->pid, app_virt_addr);
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] data_size is (hex) %x\n",
+		current->pid, data_size);
+	dev_dbg(&sep->pdev->dev, "[PID%d] start_page is (hex) %x\n",
+		current->pid, start_page);
+	dev_dbg(&sep->pdev->dev, "[PID%d] end_page is (hex) %x\n",
+		current->pid, end_page);
+	dev_dbg(&sep->pdev->dev, "[PID%d] num_pages is (hex) %x\n",
+		current->pid, num_pages);
+
+	lli_array = kmalloc(sizeof(struct sep_lli_entry) * num_pages,
+		GFP_ATOMIC);
+
+	if (!lli_array) {
+		dev_warn(&sep->pdev->dev,
+			"[PID%d] kmalloc for lli_array failed\n",
+			current->pid);
+		return -ENOMEM;
+	}
+
+	/*
+	 * Fill the lli_array
+	 */
+	start_page = start_page << PAGE_SHIFT;
+	for (count = 0; count < num_pages; count++) {
+		/* Fill the lli array entry */
+		lli_array[count].bus_address = start_page;
+		lli_array[count].block_size = PAGE_SIZE;
+
+		start_page += PAGE_SIZE;
+
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] lli_array[%x].bus_address is %08lx, "
+			"lli_array[%x].block_size is (hex) %x\n",
+			current->pid,
+			count, (unsigned long)lli_array[count].bus_address,
+			count, lli_array[count].block_size);
+	}
+
+	/* Check the offset for the first page */
+	lli_array[0].bus_address =
+		lli_array[0].bus_address + (app_virt_addr & (~PAGE_MASK));
+
+	/* Check that not all the data is in the first page only */
+	if ((PAGE_SIZE - (app_virt_addr & (~PAGE_MASK))) >= data_size)
+		lli_array[0].block_size = data_size;
+	else
+		lli_array[0].block_size =
+			PAGE_SIZE - (app_virt_addr & (~PAGE_MASK));
+
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] After check if page 0 has all data\n"
+		"lli_array[0].bus_address is (hex) %08lx, "
+		"lli_array[0].block_size is (hex) %x\n",
+		current->pid,
+		(unsigned long)lli_array[0].bus_address,
+		lli_array[0].block_size);
+
+	/* Check the size of the last page */
+	if (num_pages > 1) {
+		lli_array[num_pages - 1].block_size =
+			(app_virt_addr + data_size) & (~PAGE_MASK);
+		if (lli_array[num_pages - 1].block_size == 0)
+			lli_array[num_pages - 1].block_size = PAGE_SIZE;
+
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] After last page size adjustment\n"
+			"lli_array[%x].bus_address is (hex) %08lx, "
+			"lli_array[%x].block_size is (hex) %x\n",
+			current->pid, num_pages - 1,
+			(unsigned long)lli_array[num_pages - 1].bus_address,
+			num_pages - 1,
+			lli_array[num_pages - 1].block_size);
+	}
+	*lli_array_ptr = lli_array;
+	dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_num_pages = num_pages;
+	dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_page_array = NULL;
+	dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_map_array = NULL;
+	dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_map_num_entries = 0;
+
+	return error;
+}
+
+/**
+ * sep_calculate_lli_table_max_size - size the LLI table
+ * @sep: pointer to struct sep_device
+ * @lli_in_array_ptr
+ * @num_array_entries
+ * @last_table_flag
+ *
+ * This function calculates the size of data that can be inserted into
+ * the lli table from this array, such that either the table is full
+ * (all entries are entered), or there are no more entries in the
+ * lli array
+ */
+static u32 sep_calculate_lli_table_max_size(struct sep_device *sep,
+	struct sep_lli_entry *lli_in_array_ptr,
+	u32 num_array_entries,
+	u32 *last_table_flag)
+{
+	u32 counter;
+	/* Table data size */
+	u32 table_data_size = 0;
+	/* Data size for the next table */
+	u32 next_table_data_size;
+
+	*last_table_flag = 0;
+
+	/*
+	 * Calculate the data in the out lli table till we fill the whole
+	 * table or till the data has ended
+	 */
+	for (counter = 0;
+		(counter < (SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP - 1)) &&
+			(counter < num_array_entries); counter++)
+		table_data_size += lli_in_array_ptr[counter].block_size;
+
+	/*
+	 * Check if we reached the last entry,
+	 * meaning this ia the last table to build,
+	 * and no need to check the block alignment
+	 */
+	if (counter == num_array_entries) {
+		/* Set the last table flag */
+		*last_table_flag = 1;
+		goto end_function;
+	}
+
+	/*
+	 * Calculate the data size of the next table.
+	 * Stop if no entries left or if data size is more the DMA restriction
+	 */
+	next_table_data_size = 0;
+	for (; counter < num_array_entries; counter++) {
+		next_table_data_size += lli_in_array_ptr[counter].block_size;
+		if (next_table_data_size >= SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE)
+			break;
+	}
+
+	/*
+	 * Check if the next table data size is less then DMA rstriction.
+	 * if it is - recalculate the current table size, so that the next
+	 * table data size will be adaquete for DMA
+	 */
+	if (next_table_data_size &&
+		next_table_data_size < SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE)
+
+		table_data_size -= (SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE -
+			next_table_data_size);
+
+end_function:
+	return table_data_size;
+}
+
+/**
+ * sep_build_lli_table - build an lli array for the given table
+ * @sep: pointer to struct sep_device
+ * @lli_array_ptr: pointer to lli array
+ * @lli_table_ptr: pointer to lli table
+ * @num_processed_entries_ptr: pointer to number of entries
+ * @num_table_entries_ptr: pointer to number of tables
+ * @table_data_size: total data size
+ *
+ * Builds ant lli table from the lli_array according to
+ * the given size of data
+ */
+static void sep_build_lli_table(struct sep_device *sep,
+	struct sep_lli_entry	*lli_array_ptr,
+	struct sep_lli_entry	*lli_table_ptr,
+	u32 *num_processed_entries_ptr,
+	u32 *num_table_entries_ptr,
+	u32 table_data_size)
+{
+	/* Current table data size */
+	u32 curr_table_data_size;
+	/* Counter of lli array entry */
+	u32 array_counter;
+
+	/* Init current table data size and lli array entry counter */
+	curr_table_data_size = 0;
+	array_counter = 0;
+	*num_table_entries_ptr = 1;
+
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] build lli table table_data_size: (hex) %x\n",
+			current->pid, table_data_size);
+
+	/* Fill the table till table size reaches the needed amount */
+	while (curr_table_data_size < table_data_size) {
+		/* Update the number of entries in table */
+		(*num_table_entries_ptr)++;
+
+		lli_table_ptr->bus_address =
+			cpu_to_le32(lli_array_ptr[array_counter].bus_address);
+
+		lli_table_ptr->block_size =
+			cpu_to_le32(lli_array_ptr[array_counter].block_size);
+
+		curr_table_data_size += lli_array_ptr[array_counter].block_size;
+
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] lli_table_ptr is %p\n",
+				current->pid, lli_table_ptr);
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] lli_table_ptr->bus_address: %08lx\n",
+				current->pid,
+				(unsigned long)lli_table_ptr->bus_address);
+
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] lli_table_ptr->block_size is (hex) %x\n",
+				current->pid, lli_table_ptr->block_size);
+
+		/* Check for overflow of the table data */
+		if (curr_table_data_size > table_data_size) {
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] curr_table_data_size too large\n",
+					current->pid);
+
+			/* Update the size of block in the table */
+			lli_table_ptr->block_size =
+				cpu_to_le32(lli_table_ptr->block_size) -
+				(curr_table_data_size - table_data_size);
+
+			/* Update the physical address in the lli array */
+			lli_array_ptr[array_counter].bus_address +=
+			cpu_to_le32(lli_table_ptr->block_size);
+
+			/* Update the block size left in the lli array */
+			lli_array_ptr[array_counter].block_size =
+				(curr_table_data_size - table_data_size);
+		} else
+			/* Advance to the next entry in the lli_array */
+			array_counter++;
+
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] lli_table_ptr->bus_address is %08lx\n",
+				current->pid,
+				(unsigned long)lli_table_ptr->bus_address);
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] lli_table_ptr->block_size is (hex) %x\n",
+				current->pid,
+				lli_table_ptr->block_size);
+
+		/* Move to the next entry in table */
+		lli_table_ptr++;
+	}
+
+	/* Set the info entry to default */
+	lli_table_ptr->bus_address = 0xffffffff;
+	lli_table_ptr->block_size = 0;
+
+	/* Set the output parameter */
+	*num_processed_entries_ptr += array_counter;
+
+}
+
+/**
+ * sep_shared_area_virt_to_bus - map shared area to bus address
+ * @sep: pointer to struct sep_device
+ * @virt_address: virtual address to convert
+ *
+ * This functions returns the physical address inside shared area according
+ * to the virtual address. It can be either on the externa RAM device
+ * (ioremapped), or on the system RAM
+ * This implementation is for the external RAM
+ */
+static dma_addr_t sep_shared_area_virt_to_bus(struct sep_device *sep,
+	void *virt_address)
+{
+	dev_dbg(&sep->pdev->dev, "[PID%d] sh virt to phys v %p\n",
+					current->pid, virt_address);
+	dev_dbg(&sep->pdev->dev, "[PID%d] sh virt to phys p %08lx\n",
+		current->pid,
+		(unsigned long)
+		sep->shared_bus + (virt_address - sep->shared_addr));
+
+	return sep->shared_bus + (size_t)(virt_address - sep->shared_addr);
+}
+
+/**
+ * sep_shared_area_bus_to_virt - map shared area bus address to kernel
+ * @sep: pointer to struct sep_device
+ * @bus_address: bus address to convert
+ *
+ * This functions returns the virtual address inside shared area
+ * according to the physical address. It can be either on the
+ * externa RAM device (ioremapped), or on the system RAM
+ * This implementation is for the external RAM
+ */
+static void *sep_shared_area_bus_to_virt(struct sep_device *sep,
+	dma_addr_t bus_address)
+{
+	dev_dbg(&sep->pdev->dev, "[PID%d] shared bus to virt b=%lx v=%lx\n",
+		current->pid,
+		(unsigned long)bus_address, (unsigned long)(sep->shared_addr +
+			(size_t)(bus_address - sep->shared_bus)));
+
+	return sep->shared_addr	+ (size_t)(bus_address - sep->shared_bus);
+}
+
+/**
+ * sep_debug_print_lli_tables - dump LLI table
+ * @sep: pointer to struct sep_device
+ * @lli_table_ptr: pointer to sep_lli_entry
+ * @num_table_entries: number of entries
+ * @table_data_size: total data size
+ *
+ * Walk the the list of the print created tables and print all the data
+ */
+static void sep_debug_print_lli_tables(struct sep_device *sep,
+	struct sep_lli_entry *lli_table_ptr,
+	unsigned long num_table_entries,
+	unsigned long table_data_size)
+{
+#ifdef DEBUG
+	unsigned long table_count = 1;
+	unsigned long entries_count = 0;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] sep_debug_print_lli_tables start\n",
+					current->pid);
+	if (num_table_entries == 0) {
+		dev_dbg(&sep->pdev->dev, "[PID%d] no table to print\n",
+			current->pid);
+		return;
+	}
+
+	while ((unsigned long) lli_table_ptr->bus_address != 0xffffffff) {
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] lli table %08lx, "
+			"table_data_size is (hex) %lx\n",
+				current->pid, table_count, table_data_size);
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] num_table_entries is (hex) %lx\n",
+				current->pid, num_table_entries);
+
+		/* Print entries of the table (without info entry) */
+		for (entries_count = 0; entries_count < num_table_entries;
+			entries_count++, lli_table_ptr++) {
+
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] lli_table_ptr address is %08lx\n",
+				current->pid,
+				(unsigned long) lli_table_ptr);
+
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] phys address is %08lx "
+				"block size is (hex) %x\n", current->pid,
+				(unsigned long)lli_table_ptr->bus_address,
+				lli_table_ptr->block_size);
+		}
+
+		/* Point to the info entry */
+		lli_table_ptr--;
+
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] phys lli_table_ptr->block_size "
+			"is (hex) %x\n",
+			current->pid,
+			lli_table_ptr->block_size);
+
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] phys lli_table_ptr->physical_address "
+			"is %08lx\n",
+			current->pid,
+			(unsigned long)lli_table_ptr->bus_address);
+
+
+		table_data_size = lli_table_ptr->block_size & 0xffffff;
+		num_table_entries = (lli_table_ptr->block_size >> 24) & 0xff;
+
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] phys table_data_size is "
+			"(hex) %lx num_table_entries is"
+			" %lx bus_address is%lx\n",
+				current->pid,
+				table_data_size,
+				num_table_entries,
+				(unsigned long)lli_table_ptr->bus_address);
+
+		if ((unsigned long)lli_table_ptr->bus_address != 0xffffffff)
+			lli_table_ptr = (struct sep_lli_entry *)
+				sep_shared_bus_to_virt(sep,
+				(unsigned long)lli_table_ptr->bus_address);
+
+		table_count++;
+	}
+	dev_dbg(&sep->pdev->dev, "[PID%d] sep_debug_print_lli_tables end\n",
+					current->pid);
+#endif
+}
+
+
+/**
+ * sep_prepare_empty_lli_table - create a blank LLI table
+ * @sep: pointer to struct sep_device
+ * @lli_table_addr_ptr: pointer to lli table
+ * @num_entries_ptr: pointer to number of entries
+ * @table_data_size_ptr: point to table data size
+ * @dmatables_region: Optional buffer for DMA tables
+ * @dma_ctx: DMA context
+ *
+ * This function creates empty lli tables when there is no data
+ */
+static void sep_prepare_empty_lli_table(struct sep_device *sep,
+		dma_addr_t *lli_table_addr_ptr,
+		u32 *num_entries_ptr,
+		u32 *table_data_size_ptr,
+		void **dmatables_region,
+		struct sep_dma_context *dma_ctx)
+{
+	struct sep_lli_entry *lli_table_ptr;
+
+	/* Find the area for new table */
+	lli_table_ptr =
+		(struct sep_lli_entry *)(sep->shared_addr +
+		SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
+		dma_ctx->num_lli_tables_created * sizeof(struct sep_lli_entry) *
+			SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP);
+
+	if (dmatables_region && *dmatables_region)
+		lli_table_ptr = *dmatables_region;
+
+	lli_table_ptr->bus_address = 0;
+	lli_table_ptr->block_size = 0;
+
+	lli_table_ptr++;
+	lli_table_ptr->bus_address = 0xFFFFFFFF;
+	lli_table_ptr->block_size = 0;
+
+	/* Set the output parameter value */
+	*lli_table_addr_ptr = sep->shared_bus +
+		SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
+		dma_ctx->num_lli_tables_created *
+		sizeof(struct sep_lli_entry) *
+		SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
+
+	/* Set the num of entries and table data size for empty table */
+	*num_entries_ptr = 2;
+	*table_data_size_ptr = 0;
+
+	/* Update the number of created tables */
+	dma_ctx->num_lli_tables_created++;
+}
+
+/**
+ * sep_prepare_input_dma_table - prepare input DMA mappings
+ * @sep: pointer to struct sep_device
+ * @data_size:
+ * @block_size:
+ * @lli_table_ptr:
+ * @num_entries_ptr:
+ * @table_data_size_ptr:
+ * @is_kva: set for kernel data (kernel cryptio call)
+ *
+ * This function prepares only input DMA table for synhronic symmetric
+ * operations (HASH)
+ * Note that all bus addresses that are passed to the SEP
+ * are in 32 bit format; the SEP is a 32 bit device
+ */
+static int sep_prepare_input_dma_table(struct sep_device *sep,
+	unsigned long app_virt_addr,
+	u32 data_size,
+	u32 block_size,
+	dma_addr_t *lli_table_ptr,
+	u32 *num_entries_ptr,
+	u32 *table_data_size_ptr,
+	bool is_kva,
+	void **dmatables_region,
+	struct sep_dma_context *dma_ctx
+)
+{
+	int error = 0;
+	/* Pointer to the info entry of the table - the last entry */
+	struct sep_lli_entry *info_entry_ptr;
+	/* Array of pointers to page */
+	struct sep_lli_entry *lli_array_ptr;
+	/* Points to the first entry to be processed in the lli_in_array */
+	u32 current_entry = 0;
+	/* Num entries in the virtual buffer */
+	u32 sep_lli_entries = 0;
+	/* Lli table pointer */
+	struct sep_lli_entry *in_lli_table_ptr;
+	/* The total data in one table */
+	u32 table_data_size = 0;
+	/* Flag for last table */
+	u32 last_table_flag = 0;
+	/* Number of entries in lli table */
+	u32 num_entries_in_table = 0;
+	/* Next table address */
+	void *lli_table_alloc_addr = NULL;
+	void *dma_lli_table_alloc_addr = NULL;
+	void *dma_in_lli_table_ptr = NULL;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] prepare intput dma "
+				 "tbl data size: (hex) %x\n",
+					current->pid, data_size);
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] block_size is (hex) %x\n",
+					current->pid, block_size);
+
+	/* Initialize the pages pointers */
+	dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_page_array = NULL;
+	dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_num_pages = 0;
+
+	/* Set the kernel address for first table to be allocated */
+	lli_table_alloc_addr = (void *)(sep->shared_addr +
+		SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
+		dma_ctx->num_lli_tables_created * sizeof(struct sep_lli_entry) *
+		SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP);
+
+	if (data_size == 0) {
+		if (dmatables_region) {
+			error = sep_allocate_dmatables_region(sep,
+						dmatables_region,
+						dma_ctx,
+						1);
+			if (error)
+				return error;
+		}
+		/* Special case  - create meptu table - 2 entries, zero data */
+		sep_prepare_empty_lli_table(sep, lli_table_ptr,
+				num_entries_ptr, table_data_size_ptr,
+				dmatables_region, dma_ctx);
+		goto update_dcb_counter;
+	}
+
+	/* Check if the pages are in Kernel Virtual Address layout */
+	if (is_kva == true)
+		error = sep_lock_kernel_pages(sep, app_virt_addr,
+			data_size, &lli_array_ptr, SEP_DRIVER_IN_FLAG,
+			dma_ctx);
+	else
+		/*
+		 * Lock the pages of the user buffer
+		 * and translate them to pages
+		 */
+		error = sep_lock_user_pages(sep, app_virt_addr,
+			data_size, &lli_array_ptr, SEP_DRIVER_IN_FLAG,
+			dma_ctx);
+
+	if (error)
+		goto end_function;
+
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] output sep_in_num_pages is (hex) %x\n",
+		current->pid,
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_num_pages);
+
+	current_entry = 0;
+	info_entry_ptr = NULL;
+
+	sep_lli_entries =
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_num_pages;
+
+	dma_lli_table_alloc_addr = lli_table_alloc_addr;
+	if (dmatables_region) {
+		error = sep_allocate_dmatables_region(sep,
+					dmatables_region,
+					dma_ctx,
+					sep_lli_entries);
+		if (error)
+			return error;
+		lli_table_alloc_addr = *dmatables_region;
+	}
+
+	/* Loop till all the entries in in array are processed */
+	while (current_entry < sep_lli_entries) {
+
+		/* Set the new input and output tables */
+		in_lli_table_ptr =
+			(struct sep_lli_entry *)lli_table_alloc_addr;
+		dma_in_lli_table_ptr =
+			(struct sep_lli_entry *)dma_lli_table_alloc_addr;
+
+		lli_table_alloc_addr += sizeof(struct sep_lli_entry) *
+			SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
+		dma_lli_table_alloc_addr += sizeof(struct sep_lli_entry) *
+			SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
+
+		if (dma_lli_table_alloc_addr >
+			((void *)sep->shared_addr +
+			SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
+			SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES)) {
+
+			error = -ENOMEM;
+			goto end_function_error;
+
+		}
+
+		/* Update the number of created tables */
+		dma_ctx->num_lli_tables_created++;
+
+		/* Calculate the maximum size of data for input table */
+		table_data_size = sep_calculate_lli_table_max_size(sep,
+			&lli_array_ptr[current_entry],
+			(sep_lli_entries - current_entry),
+			&last_table_flag);
+
+		/*
+		 * If this is not the last table -
+		 * then allign it to the block size
+		 */
+		if (!last_table_flag)
+			table_data_size =
+				(table_data_size / block_size) * block_size;
+
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] output table_data_size is (hex) %x\n",
+				current->pid,
+				table_data_size);
+
+		/* Construct input lli table */
+		sep_build_lli_table(sep, &lli_array_ptr[current_entry],
+			in_lli_table_ptr,
+			&current_entry, &num_entries_in_table, table_data_size);
+
+		if (info_entry_ptr == NULL) {
+
+			/* Set the output parameters to physical addresses */
+			*lli_table_ptr = sep_shared_area_virt_to_bus(sep,
+				dma_in_lli_table_ptr);
+			*num_entries_ptr = num_entries_in_table;
+			*table_data_size_ptr = table_data_size;
+
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] output lli_table_in_ptr is %08lx\n",
+				current->pid,
+				(unsigned long)*lli_table_ptr);
+
+		} else {
+			/* Update the info entry of the previous in table */
+			info_entry_ptr->bus_address =
+				sep_shared_area_virt_to_bus(sep,
+							dma_in_lli_table_ptr);
+			info_entry_ptr->block_size =
+				((num_entries_in_table) << 24) |
+				(table_data_size);
+		}
+		/* Save the pointer to the info entry of the current tables */
+		info_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1;
+	}
+	/* Print input tables */
+	if (!dmatables_region) {
+		sep_debug_print_lli_tables(sep, (struct sep_lli_entry *)
+			sep_shared_area_bus_to_virt(sep, *lli_table_ptr),
+			*num_entries_ptr, *table_data_size_ptr);
+	}
+
+	/* The array of the pages */
+	kfree(lli_array_ptr);
+
+update_dcb_counter:
+	/* Update DCB counter */
+	dma_ctx->nr_dcb_creat++;
+	goto end_function;
+
+end_function_error:
+	/* Free all the allocated resources */
+	kfree(dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_map_array);
+	dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_map_array = NULL;
+	kfree(lli_array_ptr);
+	kfree(dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_page_array);
+	dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_page_array = NULL;
+
+end_function:
+	return error;
+
+}
+
+/**
+ * sep_construct_dma_tables_from_lli - prepare AES/DES mappings
+ * @sep: pointer to struct sep_device
+ * @lli_in_array:
+ * @sep_in_lli_entries:
+ * @lli_out_array:
+ * @sep_out_lli_entries
+ * @block_size
+ * @lli_table_in_ptr
+ * @lli_table_out_ptr
+ * @in_num_entries_ptr
+ * @out_num_entries_ptr
+ * @table_data_size_ptr
+ *
+ * This function creates the input and output DMA tables for
+ * symmetric operations (AES/DES) according to the block
+ * size from LLI arays
+ * Note that all bus addresses that are passed to the SEP
+ * are in 32 bit format; the SEP is a 32 bit device
+ */
+static int sep_construct_dma_tables_from_lli(
+	struct sep_device *sep,
+	struct sep_lli_entry *lli_in_array,
+	u32	sep_in_lli_entries,
+	struct sep_lli_entry *lli_out_array,
+	u32	sep_out_lli_entries,
+	u32	block_size,
+	dma_addr_t *lli_table_in_ptr,
+	dma_addr_t *lli_table_out_ptr,
+	u32	*in_num_entries_ptr,
+	u32	*out_num_entries_ptr,
+	u32	*table_data_size_ptr,
+	void	**dmatables_region,
+	struct sep_dma_context *dma_ctx)
+{
+	/* Points to the area where next lli table can be allocated */
+	void *lli_table_alloc_addr = NULL;
+	/*
+	 * Points to the area in shared region where next lli table
+	 * can be allocated
+	 */
+	void *dma_lli_table_alloc_addr = NULL;
+	/* Input lli table in dmatables_region or shared region */
+	struct sep_lli_entry *in_lli_table_ptr = NULL;
+	/* Input lli table location in the shared region */
+	struct sep_lli_entry *dma_in_lli_table_ptr = NULL;
+	/* Output lli table in dmatables_region or shared region */
+	struct sep_lli_entry *out_lli_table_ptr = NULL;
+	/* Output lli table location in the shared region */
+	struct sep_lli_entry *dma_out_lli_table_ptr = NULL;
+	/* Pointer to the info entry of the table - the last entry */
+	struct sep_lli_entry *info_in_entry_ptr = NULL;
+	/* Pointer to the info entry of the table - the last entry */
+	struct sep_lli_entry *info_out_entry_ptr = NULL;
+	/* Points to the first entry to be processed in the lli_in_array */
+	u32 current_in_entry = 0;
+	/* Points to the first entry to be processed in the lli_out_array */
+	u32 current_out_entry = 0;
+	/* Max size of the input table */
+	u32 in_table_data_size = 0;
+	/* Max size of the output table */
+	u32 out_table_data_size = 0;
+	/* Flag te signifies if this is the last tables build */
+	u32 last_table_flag = 0;
+	/* The data size that should be in table */
+	u32 table_data_size = 0;
+	/* Number of etnries in the input table */
+	u32 num_entries_in_table = 0;
+	/* Number of etnries in the output table */
+	u32 num_entries_out_table = 0;
+
+	if (!dma_ctx) {
+		dev_warn(&sep->pdev->dev, "DMA context uninitialized\n");
+		return -EINVAL;
+	}
+
+	/* Initiate to point after the message area */
+	lli_table_alloc_addr = (void *)(sep->shared_addr +
+		SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
+		(dma_ctx->num_lli_tables_created *
+		(sizeof(struct sep_lli_entry) *
+		SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP)));
+	dma_lli_table_alloc_addr = lli_table_alloc_addr;
+
+	if (dmatables_region) {
+		/* 2 for both in+out table */
+		if (sep_allocate_dmatables_region(sep,
+					dmatables_region,
+					dma_ctx,
+					2*sep_in_lli_entries))
+			return -ENOMEM;
+		lli_table_alloc_addr = *dmatables_region;
+	}
+
+	/* Loop till all the entries in in array are not processed */
+	while (current_in_entry < sep_in_lli_entries) {
+		/* Set the new input and output tables */
+		in_lli_table_ptr =
+			(struct sep_lli_entry *)lli_table_alloc_addr;
+		dma_in_lli_table_ptr =
+			(struct sep_lli_entry *)dma_lli_table_alloc_addr;
+
+		lli_table_alloc_addr += sizeof(struct sep_lli_entry) *
+			SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
+		dma_lli_table_alloc_addr += sizeof(struct sep_lli_entry) *
+			SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
+
+		/* Set the first output tables */
+		out_lli_table_ptr =
+			(struct sep_lli_entry *)lli_table_alloc_addr;
+		dma_out_lli_table_ptr =
+			(struct sep_lli_entry *)dma_lli_table_alloc_addr;
+
+		/* Check if the DMA table area limit was overrun */
+		if ((dma_lli_table_alloc_addr + sizeof(struct sep_lli_entry) *
+			SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP) >
+			((void *)sep->shared_addr +
+			SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
+			SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES)) {
+
+			dev_warn(&sep->pdev->dev, "dma table limit overrun\n");
+			return -ENOMEM;
+		}
+
+		/* Update the number of the lli tables created */
+		dma_ctx->num_lli_tables_created += 2;
+
+		lli_table_alloc_addr += sizeof(struct sep_lli_entry) *
+			SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
+		dma_lli_table_alloc_addr += sizeof(struct sep_lli_entry) *
+			SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
+
+		/* Calculate the maximum size of data for input table */
+		in_table_data_size =
+			sep_calculate_lli_table_max_size(sep,
+			&lli_in_array[current_in_entry],
+			(sep_in_lli_entries - current_in_entry),
+			&last_table_flag);
+
+		/* Calculate the maximum size of data for output table */
+		out_table_data_size =
+			sep_calculate_lli_table_max_size(sep,
+			&lli_out_array[current_out_entry],
+			(sep_out_lli_entries - current_out_entry),
+			&last_table_flag);
+
+		if (!last_table_flag) {
+			in_table_data_size = (in_table_data_size /
+				block_size) * block_size;
+			out_table_data_size = (out_table_data_size /
+				block_size) * block_size;
+		}
+
+		table_data_size = in_table_data_size;
+		if (table_data_size > out_table_data_size)
+			table_data_size = out_table_data_size;
+
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] construct tables from lli"
+			" in_table_data_size is (hex) %x\n", current->pid,
+			in_table_data_size);
+
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] construct tables from lli"
+			"out_table_data_size is (hex) %x\n", current->pid,
+			out_table_data_size);
+
+		/* Construct input lli table */
+		sep_build_lli_table(sep, &lli_in_array[current_in_entry],
+			in_lli_table_ptr,
+			&current_in_entry,
+			&num_entries_in_table,
+			table_data_size);
+
+		/* Construct output lli table */
+		sep_build_lli_table(sep, &lli_out_array[current_out_entry],
+			out_lli_table_ptr,
+			&current_out_entry,
+			&num_entries_out_table,
+			table_data_size);
+
+		/* If info entry is null - this is the first table built */
+		if (info_in_entry_ptr == NULL) {
+			/* Set the output parameters to physical addresses */
+			*lli_table_in_ptr =
+			sep_shared_area_virt_to_bus(sep, dma_in_lli_table_ptr);
+
+			*in_num_entries_ptr = num_entries_in_table;
+
+			*lli_table_out_ptr =
+				sep_shared_area_virt_to_bus(sep,
+				dma_out_lli_table_ptr);
+
+			*out_num_entries_ptr = num_entries_out_table;
+			*table_data_size_ptr = table_data_size;
+
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] output lli_table_in_ptr is %08lx\n",
+				current->pid,
+				(unsigned long)*lli_table_in_ptr);
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] output lli_table_out_ptr is %08lx\n",
+				current->pid,
+				(unsigned long)*lli_table_out_ptr);
+		} else {
+			/* Update the info entry of the previous in table */
+			info_in_entry_ptr->bus_address =
+				sep_shared_area_virt_to_bus(sep,
+				dma_in_lli_table_ptr);
+
+			info_in_entry_ptr->block_size =
+				((num_entries_in_table) << 24) |
+				(table_data_size);
+
+			/* Update the info entry of the previous in table */
+			info_out_entry_ptr->bus_address =
+				sep_shared_area_virt_to_bus(sep,
+				dma_out_lli_table_ptr);
+
+			info_out_entry_ptr->block_size =
+				((num_entries_out_table) << 24) |
+				(table_data_size);
+
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] output lli_table_in_ptr:%08lx %08x\n",
+				current->pid,
+				(unsigned long)info_in_entry_ptr->bus_address,
+				info_in_entry_ptr->block_size);
+
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] output lli_table_out_ptr:"
+				"%08lx  %08x\n",
+				current->pid,
+				(unsigned long)info_out_entry_ptr->bus_address,
+				info_out_entry_ptr->block_size);
+		}
+
+		/* Save the pointer to the info entry of the current tables */
+		info_in_entry_ptr = in_lli_table_ptr +
+			num_entries_in_table - 1;
+		info_out_entry_ptr = out_lli_table_ptr +
+			num_entries_out_table - 1;
+
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] output num_entries_out_table is %x\n",
+			current->pid,
+			(u32)num_entries_out_table);
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] output info_in_entry_ptr is %lx\n",
+			current->pid,
+			(unsigned long)info_in_entry_ptr);
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] output info_out_entry_ptr is %lx\n",
+			current->pid,
+			(unsigned long)info_out_entry_ptr);
+	}
+
+	/* Print input tables */
+	if (!dmatables_region) {
+		sep_debug_print_lli_tables(
+			sep,
+			(struct sep_lli_entry *)
+			sep_shared_area_bus_to_virt(sep, *lli_table_in_ptr),
+			*in_num_entries_ptr,
+			*table_data_size_ptr);
+	}
+
+	/* Print output tables */
+	if (!dmatables_region) {
+		sep_debug_print_lli_tables(
+			sep,
+			(struct sep_lli_entry *)
+			sep_shared_area_bus_to_virt(sep, *lli_table_out_ptr),
+			*out_num_entries_ptr,
+			*table_data_size_ptr);
+	}
+
+	return 0;
+}
+
+/**
+ * sep_prepare_input_output_dma_table - prepare DMA I/O table
+ * @app_virt_in_addr:
+ * @app_virt_out_addr:
+ * @data_size:
+ * @block_size:
+ * @lli_table_in_ptr:
+ * @lli_table_out_ptr:
+ * @in_num_entries_ptr:
+ * @out_num_entries_ptr:
+ * @table_data_size_ptr:
+ * @is_kva: set for kernel data; used only for kernel crypto module
+ *
+ * This function builds input and output DMA tables for synhronic
+ * symmetric operations (AES, DES, HASH). It also checks that each table
+ * is of the modular block size
+ * Note that all bus addresses that are passed to the SEP
+ * are in 32 bit format; the SEP is a 32 bit device
+ */
+static int sep_prepare_input_output_dma_table(struct sep_device *sep,
+	unsigned long app_virt_in_addr,
+	unsigned long app_virt_out_addr,
+	u32 data_size,
+	u32 block_size,
+	dma_addr_t *lli_table_in_ptr,
+	dma_addr_t *lli_table_out_ptr,
+	u32 *in_num_entries_ptr,
+	u32 *out_num_entries_ptr,
+	u32 *table_data_size_ptr,
+	bool is_kva,
+	void **dmatables_region,
+	struct sep_dma_context *dma_ctx)
+
+{
+	int error = 0;
+	/* Array of pointers of page */
+	struct sep_lli_entry *lli_in_array;
+	/* Array of pointers of page */
+	struct sep_lli_entry *lli_out_array;
+
+	if (!dma_ctx) {
+		error = -EINVAL;
+		goto end_function;
+	}
+
+	if (data_size == 0) {
+		/* Prepare empty table for input and output */
+		if (dmatables_region) {
+			error = sep_allocate_dmatables_region(
+					sep,
+					dmatables_region,
+					dma_ctx,
+					2);
+		  if (error)
+			goto end_function;
+		}
+		sep_prepare_empty_lli_table(sep, lli_table_in_ptr,
+			in_num_entries_ptr, table_data_size_ptr,
+			dmatables_region, dma_ctx);
+
+		sep_prepare_empty_lli_table(sep, lli_table_out_ptr,
+			out_num_entries_ptr, table_data_size_ptr,
+			dmatables_region, dma_ctx);
+
+		goto update_dcb_counter;
+	}
+
+	/* Initialize the pages pointers */
+	dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_page_array = NULL;
+	dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_page_array = NULL;
+
+	/* Lock the pages of the buffer and translate them to pages */
+	if (is_kva == true) {
+		dev_dbg(&sep->pdev->dev, "[PID%d] Locking kernel input pages\n",
+						current->pid);
+		error = sep_lock_kernel_pages(sep, app_virt_in_addr,
+				data_size, &lli_in_array, SEP_DRIVER_IN_FLAG,
+				dma_ctx);
+		if (error) {
+			dev_warn(&sep->pdev->dev,
+				"[PID%d] sep_lock_kernel_pages for input "
+				"virtual buffer failed\n", current->pid);
+
+			goto end_function;
+		}
+
+		dev_dbg(&sep->pdev->dev, "[PID%d] Locking kernel output pages\n",
+						current->pid);
+		error = sep_lock_kernel_pages(sep, app_virt_out_addr,
+				data_size, &lli_out_array, SEP_DRIVER_OUT_FLAG,
+				dma_ctx);
+
+		if (error) {
+			dev_warn(&sep->pdev->dev,
+				"[PID%d] sep_lock_kernel_pages for output "
+				"virtual buffer failed\n", current->pid);
+
+			goto end_function_free_lli_in;
+		}
+
+	}
+
+	else {
+		dev_dbg(&sep->pdev->dev, "[PID%d] Locking user input pages\n",
+						current->pid);
+		error = sep_lock_user_pages(sep, app_virt_in_addr,
+				data_size, &lli_in_array, SEP_DRIVER_IN_FLAG,
+				dma_ctx);
+		if (error) {
+			dev_warn(&sep->pdev->dev,
+				"[PID%d] sep_lock_user_pages for input "
+				"virtual buffer failed\n", current->pid);
+
+			goto end_function;
+		}
+
+		if (dma_ctx->secure_dma == true) {
+			/* secure_dma requires use of non accessible memory */
+			dev_dbg(&sep->pdev->dev, "[PID%d] in secure_dma\n",
+				current->pid);
+			error = sep_lli_table_secure_dma(sep,
+				app_virt_out_addr, data_size, &lli_out_array,
+				SEP_DRIVER_OUT_FLAG, dma_ctx);
+			if (error) {
+				dev_warn(&sep->pdev->dev,
+					"[PID%d] secure dma table setup "
+					" for output virtual buffer failed\n",
+					current->pid);
+
+				goto end_function_free_lli_in;
+			}
+		} else {
+			/* For normal, non-secure dma */
+			dev_dbg(&sep->pdev->dev, "[PID%d] not in secure_dma\n",
+				current->pid);
+
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] Locking user output pages\n",
+				current->pid);
+
+			error = sep_lock_user_pages(sep, app_virt_out_addr,
+				data_size, &lli_out_array, SEP_DRIVER_OUT_FLAG,
+				dma_ctx);
+
+			if (error) {
+				dev_warn(&sep->pdev->dev,
+					"[PID%d] sep_lock_user_pages"
+					" for output virtual buffer failed\n",
+					current->pid);
+
+				goto end_function_free_lli_in;
+			}
+		}
+	}
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] After lock; prep input output dma "
+		"table sep_in_num_pages is (hex) %x\n", current->pid,
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_num_pages);
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] sep_out_num_pages is (hex) %x\n",
+		current->pid,
+		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_num_pages);
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP"
+		" is (hex) %x\n", current->pid,
+		SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP);
+
+	/* Call the fucntion that creates table from the lli arrays */
+	dev_dbg(&sep->pdev->dev, "[PID%d] calling create table from lli\n",
+					current->pid);
+	error = sep_construct_dma_tables_from_lli(
+			sep, lli_in_array,
+			dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].
+								in_num_pages,
+			lli_out_array,
+			dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].
+								out_num_pages,
+			block_size, lli_table_in_ptr, lli_table_out_ptr,
+			in_num_entries_ptr, out_num_entries_ptr,
+			table_data_size_ptr, dmatables_region, dma_ctx);
+
+	if (error) {
+		dev_warn(&sep->pdev->dev,
+			"[PID%d] sep_construct_dma_tables_from_lli failed\n",
+			current->pid);
+		goto end_function_with_error;
+	}
+
+	kfree(lli_out_array);
+	kfree(lli_in_array);
+
+update_dcb_counter:
+	/* Update DCB counter */
+	dma_ctx->nr_dcb_creat++;
+
+	goto end_function;
+
+end_function_with_error:
+	kfree(dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_map_array);
+	dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_map_array = NULL;
+	kfree(dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_page_array);
+	dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_page_array = NULL;
+	kfree(lli_out_array);
+
+
+end_function_free_lli_in:
+	kfree(dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_map_array);
+	dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_map_array = NULL;
+	kfree(dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_page_array);
+	dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_page_array = NULL;
+	kfree(lli_in_array);
+
+end_function:
+
+	return error;
+
+}
+
+/**
+ * sep_prepare_input_output_dma_table_in_dcb - prepare control blocks
+ * @app_in_address: unsigned long; for data buffer in (user space)
+ * @app_out_address: unsigned long; for data buffer out (user space)
+ * @data_in_size: u32; for size of data
+ * @block_size: u32; for block size
+ * @tail_block_size: u32; for size of tail block
+ * @isapplet: bool; to indicate external app
+ * @is_kva: bool; kernel buffer; only used for kernel crypto module
+ * @secure_dma; indicates whether this is secure_dma using IMR
+ *
+ * This function prepares the linked DMA tables and puts the
+ * address for the linked list of tables inta a DCB (data control
+ * block) the address of which is known by the SEP hardware
+ * Note that all bus addresses that are passed to the SEP
+ * are in 32 bit format; the SEP is a 32 bit device
+ */
+int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep,
+	unsigned long  app_in_address,
+	unsigned long  app_out_address,
+	u32  data_in_size,
+	u32  block_size,
+	u32  tail_block_size,
+	bool isapplet,
+	bool	is_kva,
+	bool	secure_dma,
+	struct sep_dcblock *dcb_region,
+	void **dmatables_region,
+	struct sep_dma_context **dma_ctx,
+	struct scatterlist *src_sg,
+	struct scatterlist *dst_sg)
+{
+	int error = 0;
+	/* Size of tail */
+	u32 tail_size = 0;
+	/* Address of the created DCB table */
+	struct sep_dcblock *dcb_table_ptr = NULL;
+	/* The physical address of the first input DMA table */
+	dma_addr_t in_first_mlli_address = 0;
+	/* Number of entries in the first input DMA table */
+	u32  in_first_num_entries = 0;
+	/* The physical address of the first output DMA table */
+	dma_addr_t  out_first_mlli_address = 0;
+	/* Number of entries in the first output DMA table */
+	u32  out_first_num_entries = 0;
+	/* Data in the first input/output table */
+	u32  first_data_size = 0;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] app_in_address %lx\n",
+		current->pid, app_in_address);
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] app_out_address %lx\n",
+		current->pid, app_out_address);
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] data_in_size %x\n",
+		current->pid, data_in_size);
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] block_size %x\n",
+		current->pid, block_size);
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] tail_block_size %x\n",
+		current->pid, tail_block_size);
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] isapplet %x\n",
+		current->pid, isapplet);
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] is_kva %x\n",
+		current->pid, is_kva);
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] src_sg %p\n",
+		current->pid, src_sg);
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] dst_sg %p\n",
+		current->pid, dst_sg);
+
+	if (!dma_ctx) {
+		dev_warn(&sep->pdev->dev, "[PID%d] no DMA context pointer\n",
+						current->pid);
+		error = -EINVAL;
+		goto end_function;
+	}
+
+	if (*dma_ctx) {
+		/* In case there are multiple DCBs for this transaction */
+		dev_dbg(&sep->pdev->dev, "[PID%d] DMA context already set\n",
+						current->pid);
+	} else {
+		*dma_ctx = kzalloc(sizeof(**dma_ctx), GFP_KERNEL);
+		if (!(*dma_ctx)) {
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] Not enough memory for DMA context\n",
+				current->pid);
+		  error = -ENOMEM;
+		  goto end_function;
+		}
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] Created DMA context addr at 0x%p\n",
+			current->pid, *dma_ctx);
+	}
+
+	(*dma_ctx)->secure_dma = secure_dma;
+
+	/* these are for kernel crypto only */
+	(*dma_ctx)->src_sg = src_sg;
+	(*dma_ctx)->dst_sg = dst_sg;
+
+	if ((*dma_ctx)->nr_dcb_creat == SEP_MAX_NUM_SYNC_DMA_OPS) {
+		/* No more DCBs to allocate */
+		dev_dbg(&sep->pdev->dev, "[PID%d] no more DCBs available\n",
+						current->pid);
+		error = -ENOSPC;
+		goto end_function_error;
+	}
+
+	/* Allocate new DCB */
+	if (dcb_region) {
+		dcb_table_ptr = dcb_region;
+	} else {
+		dcb_table_ptr = (struct sep_dcblock *)(sep->shared_addr +
+			SEP_DRIVER_SYSTEM_DCB_MEMORY_OFFSET_IN_BYTES +
+			((*dma_ctx)->nr_dcb_creat *
+						sizeof(struct sep_dcblock)));
+	}
+
+	/* Set the default values in the DCB */
+	dcb_table_ptr->input_mlli_address = 0;
+	dcb_table_ptr->input_mlli_num_entries = 0;
+	dcb_table_ptr->input_mlli_data_size = 0;
+	dcb_table_ptr->output_mlli_address = 0;
+	dcb_table_ptr->output_mlli_num_entries = 0;
+	dcb_table_ptr->output_mlli_data_size = 0;
+	dcb_table_ptr->tail_data_size = 0;
+	dcb_table_ptr->out_vr_tail_pt = 0;
+
+	if (isapplet == true) {
+
+		/* Check if there is enough data for DMA operation */
+		if (data_in_size < SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE) {
+			if (is_kva == true) {
+				error = -ENODEV;
+				goto end_function_error;
+			} else {
+				if (copy_from_user(dcb_table_ptr->tail_data,
+					(void __user *)app_in_address,
+					data_in_size)) {
+					error = -EFAULT;
+					goto end_function_error;
+				}
+			}
+
+			dcb_table_ptr->tail_data_size = data_in_size;
+
+			/* Set the output user-space address for mem2mem op */
+			if (app_out_address)
+				dcb_table_ptr->out_vr_tail_pt =
+				(aligned_u64)app_out_address;
+
+			/*
+			 * Update both data length parameters in order to avoid
+			 * second data copy and allow building of empty mlli
+			 * tables
+			 */
+			tail_size = 0x0;
+			data_in_size = 0x0;
+
+		} else {
+			if (!app_out_address) {
+				tail_size = data_in_size % block_size;
+				if (!tail_size) {
+					if (tail_block_size == block_size)
+						tail_size = block_size;
+				}
+			} else {
+				tail_size = 0;
+			}
+		}
+		if (tail_size) {
+			if (tail_size > sizeof(dcb_table_ptr->tail_data))
+				return -EINVAL;
+			if (is_kva == true) {
+				error = -ENODEV;
+				goto end_function_error;
+			} else {
+				/* We have tail data - copy it to DCB */
+				if (copy_from_user(dcb_table_ptr->tail_data,
+					(void __user *)(app_in_address +
+					data_in_size - tail_size), tail_size)) {
+					error = -EFAULT;
+					goto end_function_error;
+				}
+			}
+			if (app_out_address)
+				/*
+				 * Calculate the output address
+				 * according to tail data size
+				 */
+				dcb_table_ptr->out_vr_tail_pt =
+					(aligned_u64)app_out_address +
+					data_in_size - tail_size;
+
+			/* Save the real tail data size */
+			dcb_table_ptr->tail_data_size = tail_size;
+			/*
+			 * Update the data size without the tail
+			 * data size AKA data for the dma
+			 */
+			data_in_size = (data_in_size - tail_size);
+		}
+	}
+	/* Check if we need to build only input table or input/output */
+	if (app_out_address) {
+		/* Prepare input/output tables */
+		error = sep_prepare_input_output_dma_table(sep,
+				app_in_address,
+				app_out_address,
+				data_in_size,
+				block_size,
+				&in_first_mlli_address,
+				&out_first_mlli_address,
+				&in_first_num_entries,
+				&out_first_num_entries,
+				&first_data_size,
+				is_kva,
+				dmatables_region,
+				*dma_ctx);
+	} else {
+		/* Prepare input tables */
+		error = sep_prepare_input_dma_table(sep,
+				app_in_address,
+				data_in_size,
+				block_size,
+				&in_first_mlli_address,
+				&in_first_num_entries,
+				&first_data_size,
+				is_kva,
+				dmatables_region,
+				*dma_ctx);
+	}
+
+	if (error) {
+		dev_warn(&sep->pdev->dev,
+			"prepare DMA table call failed "
+			"from prepare DCB call\n");
+		goto end_function_error;
+	}
+
+	/* Set the DCB values */
+	dcb_table_ptr->input_mlli_address = in_first_mlli_address;
+	dcb_table_ptr->input_mlli_num_entries = in_first_num_entries;
+	dcb_table_ptr->input_mlli_data_size = first_data_size;
+	dcb_table_ptr->output_mlli_address = out_first_mlli_address;
+	dcb_table_ptr->output_mlli_num_entries = out_first_num_entries;
+	dcb_table_ptr->output_mlli_data_size = first_data_size;
+
+	goto end_function;
+
+end_function_error:
+	kfree(*dma_ctx);
+	*dma_ctx = NULL;
+
+end_function:
+	return error;
+
+}
+
+
+/**
+ * sep_free_dma_tables_and_dcb - free DMA tables and DCBs
+ * @sep: pointer to struct sep_device
+ * @isapplet: indicates external application (used for kernel access)
+ * @is_kva: indicates kernel addresses (only used for kernel crypto)
+ *
+ * This function frees the DMA tables and DCB
+ */
+static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet,
+	bool is_kva, struct sep_dma_context **dma_ctx)
+{
+	struct sep_dcblock *dcb_table_ptr;
+	unsigned long pt_hold;
+	void *tail_pt;
+
+	int i = 0;
+	int error = 0;
+	int error_temp = 0;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] sep_free_dma_tables_and_dcb\n",
+					current->pid);
+
+	if (((*dma_ctx)->secure_dma == false) && (isapplet == true)) {
+		dev_dbg(&sep->pdev->dev, "[PID%d] handling applet\n",
+			current->pid);
+
+		/* Tail stuff is only for non secure_dma */
+		/* Set pointer to first DCB table */
+		dcb_table_ptr = (struct sep_dcblock *)
+			(sep->shared_addr +
+			SEP_DRIVER_SYSTEM_DCB_MEMORY_OFFSET_IN_BYTES);
+
+		/**
+		 * Go over each DCB and see if
+		 * tail pointer must be updated
+		 */
+		for (i = 0; dma_ctx && *dma_ctx &&
+			i < (*dma_ctx)->nr_dcb_creat; i++, dcb_table_ptr++) {
+			if (dcb_table_ptr->out_vr_tail_pt) {
+				pt_hold = (unsigned long)dcb_table_ptr->
+					out_vr_tail_pt;
+				tail_pt = (void *)pt_hold;
+				if (is_kva == true) {
+					error = -ENODEV;
+					break;
+				} else {
+					error_temp = copy_to_user(
+						(void __user *)tail_pt,
+						dcb_table_ptr->tail_data,
+						dcb_table_ptr->tail_data_size);
+				}
+				if (error_temp) {
+					/* Release the DMA resource */
+					error = -EFAULT;
+					break;
+				}
+			}
+		}
+	}
+
+	/* Free the output pages, if any */
+	sep_free_dma_table_data_handler(sep, dma_ctx);
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] sep_free_dma_tables_and_dcb end\n",
+					current->pid);
+
+	return error;
+}
+
+/**
+ * sep_prepare_dcb_handler - prepare a control block
+ * @sep: pointer to struct sep_device
+ * @arg: pointer to user parameters
+ * @secure_dma: indicate whether we are using secure_dma on IMR
+ *
+ * This function will retrieve the RAR buffer physical addresses, type
+ * & size corresponding to the RAR handles provided in the buffers vector.
+ */
+static int sep_prepare_dcb_handler(struct sep_device *sep, unsigned long arg,
+				   bool secure_dma,
+				   struct sep_dma_context **dma_ctx)
+{
+	int error;
+	/* Command arguments */
+	static struct build_dcb_struct command_args;
+
+	/* Get the command arguments */
+	if (copy_from_user(&command_args, (void __user *)arg,
+					sizeof(struct build_dcb_struct))) {
+		error = -EFAULT;
+		goto end_function;
+	}
+
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] prep dcb handler app_in_address is %08llx\n",
+			current->pid, command_args.app_in_address);
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] app_out_address is %08llx\n",
+			current->pid, command_args.app_out_address);
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] data_size is %x\n",
+			current->pid, command_args.data_in_size);
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] block_size is %x\n",
+			current->pid, command_args.block_size);
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] tail block_size is %x\n",
+			current->pid, command_args.tail_block_size);
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] is_applet is %x\n",
+			current->pid, command_args.is_applet);
+
+	if (!command_args.app_in_address) {
+		dev_warn(&sep->pdev->dev,
+			"[PID%d] null app_in_address\n", current->pid);
+		error = -EINVAL;
+		goto end_function;
+	}
+
+	error = sep_prepare_input_output_dma_table_in_dcb(sep,
+			(unsigned long)command_args.app_in_address,
+			(unsigned long)command_args.app_out_address,
+			command_args.data_in_size, command_args.block_size,
+			command_args.tail_block_size,
+			command_args.is_applet, false,
+			secure_dma, NULL, NULL, dma_ctx, NULL, NULL);
+
+end_function:
+	return error;
+
+}
+
+/**
+ * sep_free_dcb_handler - free control block resources
+ * @sep: pointer to struct sep_device
+ *
+ * This function frees the DCB resources and updates the needed
+ * user-space buffers.
+ */
+static int sep_free_dcb_handler(struct sep_device *sep,
+				struct sep_dma_context **dma_ctx)
+{
+	if (!dma_ctx || !(*dma_ctx)) {
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] no dma context defined, nothing to free\n",
+			current->pid);
+		return -EINVAL;
+	}
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] free dcbs num of DCBs %x\n",
+		current->pid,
+		(*dma_ctx)->nr_dcb_creat);
+
+	return sep_free_dma_tables_and_dcb(sep, false, false, dma_ctx);
+}
+
+/**
+ * sep_ioctl - ioctl handler for sep device
+ * @filp: pointer to struct file
+ * @cmd: command
+ * @arg: pointer to argument structure
+ *
+ * Implement the ioctl methods availble on the SEP device.
+ */
+static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct sep_private_data * const private_data = filp->private_data;
+	struct sep_call_status *call_status = &private_data->call_status;
+	struct sep_device *sep = private_data->device;
+	struct sep_dma_context **dma_ctx = &private_data->dma_ctx;
+	struct sep_queue_info **my_queue_elem = &private_data->my_queue_elem;
+	int error = 0;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] ioctl cmd 0x%x\n",
+		current->pid, cmd);
+	dev_dbg(&sep->pdev->dev, "[PID%d] dma context addr 0x%p\n",
+		current->pid, *dma_ctx);
+
+	/* Make sure we own this device */
+	error = sep_check_transaction_owner(sep);
+	if (error) {
+		dev_dbg(&sep->pdev->dev, "[PID%d] ioctl pid is not owner\n",
+			current->pid);
+		goto end_function;
+	}
+
+	/* Check that sep_mmap has been called before */
+	if (0 == test_bit(SEP_LEGACY_MMAP_DONE_OFFSET,
+				&call_status->status)) {
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] mmap not called\n", current->pid);
+		error = -EPROTO;
+		goto end_function;
+	}
+
+	/* Check that the command is for SEP device */
+	if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER) {
+		error = -ENOTTY;
+		goto end_function;
+	}
+
+	switch (cmd) {
+	case SEP_IOCSENDSEPCOMMAND:
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] SEP_IOCSENDSEPCOMMAND start\n",
+			current->pid);
+		if (1 == test_bit(SEP_LEGACY_SENDMSG_DONE_OFFSET,
+				  &call_status->status)) {
+			dev_warn(&sep->pdev->dev,
+				"[PID%d] send msg already done\n",
+				current->pid);
+			error = -EPROTO;
+			goto end_function;
+		}
+		/* Send command to SEP */
+		error = sep_send_command_handler(sep);
+		if (!error)
+			set_bit(SEP_LEGACY_SENDMSG_DONE_OFFSET,
+				&call_status->status);
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] SEP_IOCSENDSEPCOMMAND end\n",
+			current->pid);
+		break;
+	case SEP_IOCENDTRANSACTION:
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] SEP_IOCENDTRANSACTION start\n",
+			current->pid);
+		error = sep_end_transaction_handler(sep, dma_ctx, call_status,
+						    my_queue_elem);
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] SEP_IOCENDTRANSACTION end\n",
+			current->pid);
+		break;
+	case SEP_IOCPREPAREDCB:
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] SEP_IOCPREPAREDCB start\n",
+			current->pid);
+	case SEP_IOCPREPAREDCB_SECURE_DMA:
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] SEP_IOCPREPAREDCB_SECURE_DMA start\n",
+			current->pid);
+		if (1 == test_bit(SEP_LEGACY_SENDMSG_DONE_OFFSET,
+				  &call_status->status)) {
+			dev_warn(&sep->pdev->dev,
+				"[PID%d] dcb prep needed before send msg\n",
+				current->pid);
+			error = -EPROTO;
+			goto end_function;
+		}
+
+		if (!arg) {
+			dev_warn(&sep->pdev->dev,
+				"[PID%d] dcb null arg\n", current->pid);
+			error = EINVAL;
+			goto end_function;
+		}
+
+		if (cmd == SEP_IOCPREPAREDCB) {
+			/* No secure dma */
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] SEP_IOCPREPAREDCB (no secure_dma)\n",
+				current->pid);
+
+			error = sep_prepare_dcb_handler(sep, arg, false,
+				dma_ctx);
+		} else {
+			/* Secure dma */
+			dev_dbg(&sep->pdev->dev,
+				"[PID%d] SEP_IOC_POC (with secure_dma)\n",
+				current->pid);
+
+			error = sep_prepare_dcb_handler(sep, arg, true,
+				dma_ctx);
+		}
+		dev_dbg(&sep->pdev->dev, "[PID%d] dcb's end\n",
+			current->pid);
+		break;
+	case SEP_IOCFREEDCB:
+		dev_dbg(&sep->pdev->dev, "[PID%d] SEP_IOCFREEDCB start\n",
+			current->pid);
+	case SEP_IOCFREEDCB_SECURE_DMA:
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] SEP_IOCFREEDCB_SECURE_DMA start\n",
+			current->pid);
+		error = sep_free_dcb_handler(sep, dma_ctx);
+		dev_dbg(&sep->pdev->dev, "[PID%d] SEP_IOCFREEDCB end\n",
+			current->pid);
+		break;
+	default:
+		error = -ENOTTY;
+		dev_dbg(&sep->pdev->dev, "[PID%d] default end\n",
+			current->pid);
+		break;
+	}
+
+end_function:
+	dev_dbg(&sep->pdev->dev, "[PID%d] ioctl end\n", current->pid);
+
+	return error;
+}
+
+/**
+ * sep_inthandler - interrupt handler for sep device
+ * @irq: interrupt
+ * @dev_id: device id
+ */
+static irqreturn_t sep_inthandler(int irq, void *dev_id)
+{
+	unsigned long lock_irq_flag;
+	u32 reg_val, reg_val2 = 0;
+	struct sep_device *sep = dev_id;
+	irqreturn_t int_error = IRQ_HANDLED;
+
+	/* Are we in power save? */
+#if defined(CONFIG_PM_RUNTIME) && defined(SEP_ENABLE_RUNTIME_PM)
+	if (sep->pdev->dev.power.runtime_status != RPM_ACTIVE) {
+		dev_dbg(&sep->pdev->dev, "interrupt during pwr save\n");
+		return IRQ_NONE;
+	}
+#endif
+
+	if (test_bit(SEP_WORKING_LOCK_BIT, &sep->in_use_flags) == 0) {
+		dev_dbg(&sep->pdev->dev, "interrupt while nobody using sep\n");
+		return IRQ_NONE;
+	}
+
+	/* Read the IRR register to check if this is SEP interrupt */
+	reg_val = sep_read_reg(sep, HW_HOST_IRR_REG_ADDR);
+
+	dev_dbg(&sep->pdev->dev, "sep int: IRR REG val: %x\n", reg_val);
+
+	if (reg_val & (0x1 << 13)) {
+
+		/* Lock and update the counter of reply messages */
+		spin_lock_irqsave(&sep->snd_rply_lck, lock_irq_flag);
+		sep->reply_ct++;
+		spin_unlock_irqrestore(&sep->snd_rply_lck, lock_irq_flag);
+
+		dev_dbg(&sep->pdev->dev, "sep int: send_ct %lx reply_ct %lx\n",
+					sep->send_ct, sep->reply_ct);
+
+		/* Is this a kernel client request */
+		if (sep->in_kernel) {
+			tasklet_schedule(&sep->finish_tasklet);
+			goto finished_interrupt;
+		}
+
+		/* Is this printf or daemon request? */
+		reg_val2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
+		dev_dbg(&sep->pdev->dev,
+			"SEP Interrupt - GPR2 is %08x\n", reg_val2);
+
+		clear_bit(SEP_WORKING_LOCK_BIT, &sep->in_use_flags);
+
+		if ((reg_val2 >> 30) & 0x1) {
+			dev_dbg(&sep->pdev->dev, "int: printf request\n");
+		} else if (reg_val2 >> 31) {
+			dev_dbg(&sep->pdev->dev, "int: daemon request\n");
+		} else {
+			dev_dbg(&sep->pdev->dev, "int: SEP reply\n");
+			wake_up(&sep->event_interrupt);
+		}
+	} else {
+		dev_dbg(&sep->pdev->dev, "int: not SEP interrupt\n");
+		int_error = IRQ_NONE;
+	}
+
+finished_interrupt:
+
+	if (int_error == IRQ_HANDLED)
+		sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, reg_val);
+
+	return int_error;
+}
+
+/**
+ * sep_reconfig_shared_area - reconfigure shared area
+ * @sep: pointer to struct sep_device
+ *
+ * Reconfig the shared area between HOST and SEP - needed in case
+ * the DX_CC_Init function was called before OS loading.
+ */
+static int sep_reconfig_shared_area(struct sep_device *sep)
+{
+	int ret_val;
+
+	/* use to limit waiting for SEP */
+	unsigned long end_time;
+
+	/* Send the new SHARED MESSAGE AREA to the SEP */
+	dev_dbg(&sep->pdev->dev, "reconfig shared; sending %08llx to sep\n",
+				(unsigned long long)sep->shared_bus);
+
+	sep_write_reg(sep, HW_HOST_HOST_SEP_GPR1_REG_ADDR, sep->shared_bus);
+
+	/* Poll for SEP response */
+	ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR);
+
+	end_time = jiffies + (WAIT_TIME * HZ);
+
+	while ((time_before(jiffies, end_time)) && (ret_val != 0xffffffff) &&
+		(ret_val != sep->shared_bus))
+		ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR);
+
+	/* Check the return value (register) */
+	if (ret_val != sep->shared_bus) {
+		dev_warn(&sep->pdev->dev, "could not reconfig shared area\n");
+		dev_warn(&sep->pdev->dev, "result was %x\n", ret_val);
+		ret_val = -ENOMEM;
+	} else
+		ret_val = 0;
+
+	dev_dbg(&sep->pdev->dev, "reconfig shared area end\n");
+
+	return ret_val;
+}
+
+/**
+ *	sep_activate_dcb_dmatables_context - Takes DCB & DMA tables
+ *						contexts into use
+ *	@sep: SEP device
+ *	@dcb_region: DCB region copy
+ *	@dmatables_region: MLLI/DMA tables copy
+ *	@dma_ctx: DMA context for current transaction
+ */
+ssize_t sep_activate_dcb_dmatables_context(struct sep_device *sep,
+					struct sep_dcblock **dcb_region,
+					void **dmatables_region,
+					struct sep_dma_context *dma_ctx)
+{
+	void *dmaregion_free_start = NULL;
+	void *dmaregion_free_end = NULL;
+	void *dcbregion_free_start = NULL;
+	void *dcbregion_free_end = NULL;
+	ssize_t error = 0;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] activating dcb/dma region\n",
+		current->pid);
+
+	if (1 > dma_ctx->nr_dcb_creat) {
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] invalid number of dcbs to activate 0x%08X\n",
+			 current->pid, dma_ctx->nr_dcb_creat);
+		error = -EINVAL;
+		goto end_function;
+	}
+
+	dmaregion_free_start = sep->shared_addr
+				+ SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES;
+	dmaregion_free_end = dmaregion_free_start
+				+ SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES - 1;
+
+	if (dmaregion_free_start
+	     + dma_ctx->dmatables_len > dmaregion_free_end) {
+		error = -ENOMEM;
+		goto end_function;
+	}
+	memcpy(dmaregion_free_start,
+	       *dmatables_region,
+	       dma_ctx->dmatables_len);
+	/* Free MLLI table copy */
+	kfree(*dmatables_region);
+	*dmatables_region = NULL;
+
+	/* Copy thread's DCB  table copy to DCB table region */
+	dcbregion_free_start = sep->shared_addr +
+				SEP_DRIVER_SYSTEM_DCB_MEMORY_OFFSET_IN_BYTES;
+	dcbregion_free_end = dcbregion_free_start +
+				(SEP_MAX_NUM_SYNC_DMA_OPS *
+					sizeof(struct sep_dcblock)) - 1;
+
+	if (dcbregion_free_start
+	     + (dma_ctx->nr_dcb_creat * sizeof(struct sep_dcblock))
+	     > dcbregion_free_end) {
+		error = -ENOMEM;
+		goto end_function;
+	}
+
+	memcpy(dcbregion_free_start,
+	       *dcb_region,
+	       dma_ctx->nr_dcb_creat * sizeof(struct sep_dcblock));
+
+	/* Print the tables */
+	dev_dbg(&sep->pdev->dev, "activate: input table\n");
+	sep_debug_print_lli_tables(sep,
+		(struct sep_lli_entry *)sep_shared_area_bus_to_virt(sep,
+		(*dcb_region)->input_mlli_address),
+		(*dcb_region)->input_mlli_num_entries,
+		(*dcb_region)->input_mlli_data_size);
+
+	dev_dbg(&sep->pdev->dev, "activate: output table\n");
+	sep_debug_print_lli_tables(sep,
+		(struct sep_lli_entry *)sep_shared_area_bus_to_virt(sep,
+		(*dcb_region)->output_mlli_address),
+		(*dcb_region)->output_mlli_num_entries,
+		(*dcb_region)->output_mlli_data_size);
+
+	dev_dbg(&sep->pdev->dev,
+		 "[PID%d] printing activated tables\n", current->pid);
+
+end_function:
+	kfree(*dmatables_region);
+	*dmatables_region = NULL;
+
+	kfree(*dcb_region);
+	*dcb_region = NULL;
+
+	return error;
+}
+
+/**
+ *	sep_create_dcb_dmatables_context - Creates DCB & MLLI/DMA table context
+ *	@sep: SEP device
+ *	@dcb_region: DCB region buf to create for current transaction
+ *	@dmatables_region: MLLI/DMA tables buf to create for current transaction
+ *	@dma_ctx: DMA context buf to create for current transaction
+ *	@user_dcb_args: User arguments for DCB/MLLI creation
+ *	@num_dcbs: Number of DCBs to create
+ *	@secure_dma: Indicate use of IMR restricted memory secure dma
+ */
+static ssize_t sep_create_dcb_dmatables_context(struct sep_device *sep,
+			struct sep_dcblock **dcb_region,
+			void **dmatables_region,
+			struct sep_dma_context **dma_ctx,
+			const struct build_dcb_struct __user *user_dcb_args,
+			const u32 num_dcbs, bool secure_dma)
+{
+	int error = 0;
+	int i = 0;
+	struct build_dcb_struct *dcb_args = NULL;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] creating dcb/dma region\n",
+		current->pid);
+
+	if (!dcb_region || !dma_ctx || !dmatables_region || !user_dcb_args) {
+		error = -EINVAL;
+		goto end_function;
+	}
+
+	if (SEP_MAX_NUM_SYNC_DMA_OPS < num_dcbs) {
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] invalid number of dcbs 0x%08X\n",
+			 current->pid, num_dcbs);
+		error = -EINVAL;
+		goto end_function;
+	}
+
+	dcb_args = kzalloc(num_dcbs * sizeof(struct build_dcb_struct),
+			   GFP_KERNEL);
+	if (!dcb_args) {
+		dev_warn(&sep->pdev->dev, "[PID%d] no memory for dcb args\n",
+			 current->pid);
+		error = -ENOMEM;
+		goto end_function;
+	}
+
+	if (copy_from_user(dcb_args,
+			user_dcb_args,
+			num_dcbs * sizeof(struct build_dcb_struct))) {
+		error = -EINVAL;
+		goto end_function;
+	}
+
+	/* Allocate thread-specific memory for DCB */
+	*dcb_region = kzalloc(num_dcbs * sizeof(struct sep_dcblock),
+			      GFP_KERNEL);
+	if (!(*dcb_region)) {
+		error = -ENOMEM;
+		goto end_function;
+	}
+
+	/* Prepare DCB and MLLI table into the allocated regions */
+	for (i = 0; i < num_dcbs; i++) {
+		error = sep_prepare_input_output_dma_table_in_dcb(sep,
+				(unsigned long)dcb_args[i].app_in_address,
+				(unsigned long)dcb_args[i].app_out_address,
+				dcb_args[i].data_in_size,
+				dcb_args[i].block_size,
+				dcb_args[i].tail_block_size,
+				dcb_args[i].is_applet,
+				false, secure_dma,
+				*dcb_region, dmatables_region,
+				dma_ctx,
+				NULL,
+				NULL);
+		if (error) {
+			dev_warn(&sep->pdev->dev,
+				 "[PID%d] dma table creation failed\n",
+				 current->pid);
+			goto end_function;
+		}
+
+		if (dcb_args[i].app_in_address != 0)
+			(*dma_ctx)->input_data_len += dcb_args[i].data_in_size;
+	}
+
+end_function:
+	kfree(dcb_args);
+	return error;
+
+}
+
+/**
+ *	sep_create_dcb_dmatables_context_kernel - Creates DCB & MLLI/DMA table context
+ *      for kernel crypto
+ *	@sep: SEP device
+ *	@dcb_region: DCB region buf to create for current transaction
+ *	@dmatables_region: MLLI/DMA tables buf to create for current transaction
+ *	@dma_ctx: DMA context buf to create for current transaction
+ *	@user_dcb_args: User arguments for DCB/MLLI creation
+ *	@num_dcbs: Number of DCBs to create
+ *	This does that same thing as sep_create_dcb_dmatables_context
+ *	except that it is used only for the kernel crypto operation. It is
+ *	separate because there is no user data involved; the dcb data structure
+ *	is specific for kernel crypto (build_dcb_struct_kernel)
+ */
+int sep_create_dcb_dmatables_context_kernel(struct sep_device *sep,
+			struct sep_dcblock **dcb_region,
+			void **dmatables_region,
+			struct sep_dma_context **dma_ctx,
+			const struct build_dcb_struct_kernel *dcb_data,
+			const u32 num_dcbs)
+{
+	int error = 0;
+	int i = 0;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] creating dcb/dma region\n",
+		current->pid);
+
+	if (!dcb_region || !dma_ctx || !dmatables_region || !dcb_data) {
+		error = -EINVAL;
+		goto end_function;
+	}
+
+	if (SEP_MAX_NUM_SYNC_DMA_OPS < num_dcbs) {
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] invalid number of dcbs 0x%08X\n",
+			 current->pid, num_dcbs);
+		error = -EINVAL;
+		goto end_function;
+	}
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] num_dcbs is %d\n",
+		current->pid, num_dcbs);
+
+	/* Allocate thread-specific memory for DCB */
+	*dcb_region = kzalloc(num_dcbs * sizeof(struct sep_dcblock),
+			      GFP_KERNEL);
+	if (!(*dcb_region)) {
+		error = -ENOMEM;
+		goto end_function;
+	}
+
+	/* Prepare DCB and MLLI table into the allocated regions */
+	for (i = 0; i < num_dcbs; i++) {
+		error = sep_prepare_input_output_dma_table_in_dcb(sep,
+				(unsigned long)dcb_data->app_in_address,
+				(unsigned long)dcb_data->app_out_address,
+				dcb_data->data_in_size,
+				dcb_data->block_size,
+				dcb_data->tail_block_size,
+				dcb_data->is_applet,
+				true,
+				false,
+				*dcb_region, dmatables_region,
+				dma_ctx,
+				dcb_data->src_sg,
+				dcb_data->dst_sg);
+		if (error) {
+			dev_warn(&sep->pdev->dev,
+				 "[PID%d] dma table creation failed\n",
+				 current->pid);
+			goto end_function;
+		}
+	}
+
+end_function:
+	return error;
+
+}
+
+/**
+ *	sep_activate_msgarea_context - Takes the message area context into use
+ *	@sep: SEP device
+ *	@msg_region: Message area context buf
+ *	@msg_len: Message area context buffer size
+ */
+static ssize_t sep_activate_msgarea_context(struct sep_device *sep,
+					    void **msg_region,
+					    const size_t msg_len)
+{
+	dev_dbg(&sep->pdev->dev, "[PID%d] activating msg region\n",
+		current->pid);
+
+	if (!msg_region || !(*msg_region) ||
+	    SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES < msg_len) {
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] invalid act msgarea len 0x%08zX\n",
+			 current->pid, msg_len);
+		return -EINVAL;
+	}
+
+	memcpy(sep->shared_addr, *msg_region, msg_len);
+
+	return 0;
+}
+
+/**
+ *	sep_create_msgarea_context - Creates message area context
+ *	@sep: SEP device
+ *	@msg_region: Msg area region buf to create for current transaction
+ *	@msg_user: Content for msg area region from user
+ *	@msg_len: Message area size
+ */
+static ssize_t sep_create_msgarea_context(struct sep_device *sep,
+					  void **msg_region,
+					  const void __user *msg_user,
+					  const size_t msg_len)
+{
+	int error = 0;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] creating msg region\n",
+		current->pid);
+
+	if (!msg_region ||
+	    !msg_user ||
+	    SEP_DRIVER_MAX_MESSAGE_SIZE_IN_BYTES < msg_len ||
+	    SEP_DRIVER_MIN_MESSAGE_SIZE_IN_BYTES > msg_len) {
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] invalid creat msgarea len 0x%08zX\n",
+			 current->pid, msg_len);
+		error = -EINVAL;
+		goto end_function;
+	}
+
+	/* Allocate thread-specific memory for message buffer */
+	*msg_region = kzalloc(msg_len, GFP_KERNEL);
+	if (!(*msg_region)) {
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] no mem for msgarea context\n",
+			 current->pid);
+		error = -ENOMEM;
+		goto end_function;
+	}
+
+	/* Copy input data to write() to allocated message buffer */
+	if (copy_from_user(*msg_region, msg_user, msg_len)) {
+		error = -EINVAL;
+		goto end_function;
+	}
+
+end_function:
+	if (error && msg_region) {
+		kfree(*msg_region);
+		*msg_region = NULL;
+	}
+
+	return error;
+}
+
+
+/**
+ *	sep_read - Returns results of an operation for fastcall interface
+ *	@filp: File pointer
+ *	@buf_user: User buffer for storing results
+ *	@count_user: User buffer size
+ *	@offset: File offset, not supported
+ *
+ *	The implementation does not support reading in chunks, all data must be
+ *	consumed during a single read system call.
+ */
+static ssize_t sep_read(struct file *filp,
+			char __user *buf_user, size_t count_user,
+			loff_t *offset)
+{
+	struct sep_private_data * const private_data = filp->private_data;
+	struct sep_call_status *call_status = &private_data->call_status;
+	struct sep_device *sep = private_data->device;
+	struct sep_dma_context **dma_ctx = &private_data->dma_ctx;
+	struct sep_queue_info **my_queue_elem = &private_data->my_queue_elem;
+	ssize_t error = 0, error_tmp = 0;
+
+	/* Am I the process that owns the transaction? */
+	error = sep_check_transaction_owner(sep);
+	if (error) {
+		dev_dbg(&sep->pdev->dev, "[PID%d] read pid is not owner\n",
+			current->pid);
+		goto end_function;
+	}
+
+	/* Checks that user has called necessarry apis */
+	if (0 == test_bit(SEP_FASTCALL_WRITE_DONE_OFFSET,
+			&call_status->status)) {
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] fastcall write not called\n",
+			 current->pid);
+		error = -EPROTO;
+		goto end_function_error;
+	}
+
+	if (!buf_user) {
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] null user buffer\n",
+			 current->pid);
+		error = -EINVAL;
+		goto end_function_error;
+	}
+
+
+	/* Wait for SEP to finish */
+	wait_event(sep->event_interrupt,
+		   test_bit(SEP_WORKING_LOCK_BIT,
+			    &sep->in_use_flags) == 0);
+
+	sep_dump_message(sep);
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] count_user = 0x%08zX\n",
+		current->pid, count_user);
+
+	/* In case user has allocated bigger buffer */
+	if (count_user > SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES)
+		count_user = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES;
+
+	if (copy_to_user(buf_user, sep->shared_addr, count_user)) {
+		error = -EFAULT;
+		goto end_function_error;
+	}
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] read succeeded\n", current->pid);
+	error = count_user;
+
+end_function_error:
+	/* Copy possible tail data to user and free DCB and MLLIs */
+	error_tmp = sep_free_dcb_handler(sep, dma_ctx);
+	if (error_tmp)
+		dev_warn(&sep->pdev->dev, "[PID%d] dcb free failed\n",
+			current->pid);
+
+	/* End the transaction, wakeup pending ones */
+	error_tmp = sep_end_transaction_handler(sep, dma_ctx, call_status,
+		my_queue_elem);
+	if (error_tmp)
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] ending transaction failed\n",
+			 current->pid);
+
+end_function:
+	return error;
+}
+
+/**
+ *	sep_fastcall_args_get - Gets fastcall params from user
+ *	sep: SEP device
+ *	@args: Parameters buffer
+ *	@buf_user: User buffer for operation parameters
+ *	@count_user: User buffer size
+ */
+static inline ssize_t sep_fastcall_args_get(struct sep_device *sep,
+					    struct sep_fastcall_hdr *args,
+					    const char __user *buf_user,
+					    const size_t count_user)
+{
+	ssize_t error = 0;
+	size_t actual_count = 0;
+
+	if (!buf_user) {
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] null user buffer\n",
+			 current->pid);
+		error = -EINVAL;
+		goto end_function;
+	}
+
+	if (count_user < sizeof(struct sep_fastcall_hdr)) {
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] too small message size 0x%08zX\n",
+			 current->pid, count_user);
+		error = -EINVAL;
+		goto end_function;
+	}
+
+
+	if (copy_from_user(args, buf_user, sizeof(struct sep_fastcall_hdr))) {
+		error = -EFAULT;
+		goto end_function;
+	}
+
+	if (SEP_FC_MAGIC != args->magic) {
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] invalid fastcall magic 0x%08X\n",
+			 current->pid, args->magic);
+		error = -EINVAL;
+		goto end_function;
+	}
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] fastcall hdr num of DCBs 0x%08X\n",
+		current->pid, args->num_dcbs);
+	dev_dbg(&sep->pdev->dev, "[PID%d] fastcall hdr msg len 0x%08X\n",
+		current->pid, args->msg_len);
+
+	if (SEP_DRIVER_MAX_MESSAGE_SIZE_IN_BYTES < args->msg_len ||
+	    SEP_DRIVER_MIN_MESSAGE_SIZE_IN_BYTES > args->msg_len) {
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] invalid message length\n",
+			 current->pid);
+		error = -EINVAL;
+		goto end_function;
+	}
+
+	actual_count = sizeof(struct sep_fastcall_hdr)
+			+ args->msg_len
+			+ (args->num_dcbs * sizeof(struct build_dcb_struct));
+
+	if (actual_count != count_user) {
+		dev_warn(&sep->pdev->dev,
+			 "[PID%d] inconsistent message "
+			 "sizes 0x%08zX vs 0x%08zX\n",
+			 current->pid, actual_count, count_user);
+		error = -EMSGSIZE;
+		goto end_function;
+	}
+
+end_function:
+	return error;
+}
+
+/**
+ *	sep_write - Starts an operation for fastcall interface
+ *	@filp: File pointer
+ *	@buf_user: User buffer for operation parameters
+ *	@count_user: User buffer size
+ *	@offset: File offset, not supported
+ *
+ *	The implementation does not support writing in chunks,
+ *	all data must be given during a single write system call.
+ */
+static ssize_t sep_write(struct file *filp,
+			 const char __user *buf_user, size_t count_user,
+			 loff_t *offset)
+{
+	struct sep_private_data * const private_data = filp->private_data;
+	struct sep_call_status *call_status = &private_data->call_status;
+	struct sep_device *sep = private_data->device;
+	struct sep_dma_context *dma_ctx = NULL;
+	struct sep_fastcall_hdr call_hdr = {0};
+	void *msg_region = NULL;
+	void *dmatables_region = NULL;
+	struct sep_dcblock *dcb_region = NULL;
+	ssize_t error = 0;
+	struct sep_queue_info *my_queue_elem = NULL;
+	bool my_secure_dma; /* are we using secure_dma (IMR)? */
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] sep dev is 0x%p\n",
+		current->pid, sep);
+	dev_dbg(&sep->pdev->dev, "[PID%d] private_data is 0x%p\n",
+		current->pid, private_data);
+
+	error = sep_fastcall_args_get(sep, &call_hdr, buf_user, count_user);
+	if (error)
+		goto end_function;
+
+	buf_user += sizeof(struct sep_fastcall_hdr);
+
+	if (call_hdr.secure_dma == 0)
+		my_secure_dma = false;
+	else
+		my_secure_dma = true;
+
+	/*
+	 * Controlling driver memory usage by limiting amount of
+	 * buffers created. Only SEP_DOUBLEBUF_USERS_LIMIT number
+	 * of threads can progress further at a time
+	 */
+	dev_dbg(&sep->pdev->dev, "[PID%d] waiting for double buffering "
+				 "region access\n", current->pid);
+	error = down_interruptible(&sep->sep_doublebuf);
+	dev_dbg(&sep->pdev->dev, "[PID%d] double buffering region start\n",
+					current->pid);
+	if (error) {
+		/* Signal received */
+		goto end_function_error;
+	}
+
+
+	/*
+	 * Prepare contents of the shared area regions for
+	 * the operation into temporary buffers
+	 */
+	if (0 < call_hdr.num_dcbs) {
+		error = sep_create_dcb_dmatables_context(sep,
+				&dcb_region,
+				&dmatables_region,
+				&dma_ctx,
+				(const struct build_dcb_struct __user *)
+					buf_user,
+				call_hdr.num_dcbs, my_secure_dma);
+		if (error)
+			goto end_function_error_doublebuf;
+
+		buf_user += call_hdr.num_dcbs * sizeof(struct build_dcb_struct);
+	}
+
+	error = sep_create_msgarea_context(sep,
+					   &msg_region,
+					   buf_user,
+					   call_hdr.msg_len);
+	if (error)
+		goto end_function_error_doublebuf;
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] updating queue status\n",
+							current->pid);
+	my_queue_elem = sep_queue_status_add(sep,
+				((struct sep_msgarea_hdr *)msg_region)->opcode,
+				(dma_ctx) ? dma_ctx->input_data_len : 0,
+				     current->pid,
+				     current->comm, sizeof(current->comm));
+
+	if (!my_queue_elem) {
+		dev_dbg(&sep->pdev->dev, "[PID%d] updating queue"
+					"status error\n", current->pid);
+		error = -ENOMEM;
+		goto end_function_error_doublebuf;
+	}
+
+	/* Wait until current process gets the transaction */
+	error = sep_wait_transaction(sep);
+
+	if (error) {
+		/* Interrupted by signal, don't clear transaction */
+		dev_dbg(&sep->pdev->dev, "[PID%d] interrupted by signal\n",
+			current->pid);
+		sep_queue_status_remove(sep, &my_queue_elem);
+		goto end_function_error_doublebuf;
+	}
+
+	dev_dbg(&sep->pdev->dev, "[PID%d] saving queue element\n",
+		current->pid);
+	private_data->my_queue_elem = my_queue_elem;
+
+	/* Activate shared area regions for the transaction */
+	error = sep_activate_msgarea_context(sep, &msg_region,
+					     call_hdr.msg_len);
+	if (error)
+		goto end_function_error_clear_transact;
+
+	sep_dump_message(sep);
+
+	if (0 < call_hdr.num_dcbs) {
+		error = sep_activate_dcb_dmatables_context(sep,
+				&dcb_region,
+				&dmatables_region,
+				dma_ctx);
+		if (error)
+			goto end_function_error_clear_transact;
+	}
+
+	/* Send command to SEP */
+	error = sep_send_command_handler(sep);
+	if (error)
+		goto end_function_error_clear_transact;
+
+	/* Store DMA context for the transaction */
+	private_data->dma_ctx = dma_ctx;
+	/* Update call status */
+	set_bit(SEP_FASTCALL_WRITE_DONE_OFFSET, &call_status->status);
+	error = count_user;
+
+	up(&sep->sep_doublebuf);
+	dev_dbg(&sep->pdev->dev, "[PID%d] double buffering region end\n",
+		current->pid);
+
+	goto end_function;
+
+end_function_error_clear_transact:
+	sep_end_transaction_handler(sep, &dma_ctx, call_status,
+						&private_data->my_queue_elem);
+
+end_function_error_doublebuf:
+	up(&sep->sep_doublebuf);
+	dev_dbg(&sep->pdev->dev, "[PID%d] double buffering region end\n",
+		current->pid);
+
+end_function_error:
+	if (dma_ctx)
+		sep_free_dma_table_data_handler(sep, &dma_ctx);
+
+end_function:
+	kfree(dcb_region);
+	kfree(dmatables_region);
+	kfree(msg_region);
+
+	return error;
+}
+/**
+ *	sep_seek - Handler for seek system call
+ *	@filp: File pointer
+ *	@offset: File offset
+ *	@origin: Options for offset
+ *
+ *	Fastcall interface does not support seeking, all reads
+ *	and writes are from/to offset zero
+ */
+static loff_t sep_seek(struct file *filp, loff_t offset, int origin)
+{
+	return -ENOSYS;
+}
+
+
+
+/**
+ * sep_file_operations - file operation on sep device
+ * @sep_ioctl:	ioctl handler from user space call
+ * @sep_poll:	poll handler
+ * @sep_open:	handles sep device open request
+ * @sep_release:handles sep device release request
+ * @sep_mmap:	handles memory mapping requests
+ * @sep_read:	handles read request on sep device
+ * @sep_write:	handles write request on sep device
+ * @sep_seek:	handles seek request on sep device
+ */
+static const struct file_operations sep_file_operations = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = sep_ioctl,
+	.poll = sep_poll,
+	.open = sep_open,
+	.release = sep_release,
+	.mmap = sep_mmap,
+	.read = sep_read,
+	.write = sep_write,
+	.llseek = sep_seek,
+};
+
+/**
+ * sep_sysfs_read - read sysfs entry per gives arguments
+ * @filp: file pointer
+ * @kobj: kobject pointer
+ * @attr: binary file attributes
+ * @buf: read to this buffer
+ * @pos: offset to read
+ * @count: amount of data to read
+ *
+ * This function is to read sysfs entries for sep driver per given arguments.
+ */
+static ssize_t
+sep_sysfs_read(struct file *filp, struct kobject *kobj,
+		struct bin_attribute *attr,
+		char *buf, loff_t pos, size_t count)
+{
+	unsigned long lck_flags;
+	size_t nleft = count;
+	struct sep_device *sep = sep_dev;
+	struct sep_queue_info *queue_elem = NULL;
+	u32 queue_num = 0;
+	u32 i = 1;
+
+	spin_lock_irqsave(&sep->sep_queue_lock, lck_flags);
+
+	queue_num = sep->sep_queue_num;
+	if (queue_num > SEP_DOUBLEBUF_USERS_LIMIT)
+		queue_num = SEP_DOUBLEBUF_USERS_LIMIT;
+
+
+	if (count < sizeof(queue_num)
+			+ (queue_num * sizeof(struct sep_queue_data))) {
+		spin_unlock_irqrestore(&sep->sep_queue_lock, lck_flags);
+		return -EINVAL;
+	}
+
+	memcpy(buf, &queue_num, sizeof(queue_num));
+	buf += sizeof(queue_num);
+	nleft -= sizeof(queue_num);
+
+	list_for_each_entry(queue_elem, &sep->sep_queue_status, list) {
+		if (i++ > queue_num)
+			break;
+
+		memcpy(buf, &queue_elem->data, sizeof(queue_elem->data));
+		nleft -= sizeof(queue_elem->data);
+		buf += sizeof(queue_elem->data);
+	}
+	spin_unlock_irqrestore(&sep->sep_queue_lock, lck_flags);
+
+	return count - nleft;
+}
+
+/**
+ * bin_attributes - defines attributes for queue_status
+ * @attr: attributes (name & permissions)
+ * @read: function pointer to read this file
+ * @size: maxinum size of binary attribute
+ */
+static const struct bin_attribute queue_status = {
+	.attr = {.name = "queue_status", .mode = 0444},
+	.read = sep_sysfs_read,
+	.size = sizeof(u32)
+		+ (SEP_DOUBLEBUF_USERS_LIMIT * sizeof(struct sep_queue_data)),
+};
+
+/**
+ * sep_register_driver_with_fs - register misc devices
+ * @sep: pointer to struct sep_device
+ *
+ * This function registers the driver with the file system
+ */
+static int sep_register_driver_with_fs(struct sep_device *sep)
+{
+	int ret_val;
+
+	sep->miscdev_sep.minor = MISC_DYNAMIC_MINOR;
+	sep->miscdev_sep.name = SEP_DEV_NAME;
+	sep->miscdev_sep.fops = &sep_file_operations;
+
+	ret_val = misc_register(&sep->miscdev_sep);
+	if (ret_val) {
+		dev_warn(&sep->pdev->dev, "misc reg fails for SEP %x\n",
+			ret_val);
+		return ret_val;
+	}
+
+	ret_val = device_create_bin_file(sep->miscdev_sep.this_device,
+								&queue_status);
+	if (ret_val) {
+		dev_warn(&sep->pdev->dev, "sysfs attribute1 fails for SEP %x\n",
+			ret_val);
+		return ret_val;
+	}
+
+	return ret_val;
+}
+
+
+/**
+ *sep_probe - probe a matching PCI device
+ *@pdev:	pci_device
+ *@ent:	pci_device_id
+ *
+ *Attempt to set up and configure a SEP device that has been
+ *discovered by the PCI layer. Allocates all required resources.
+ */
+static int __devinit sep_probe(struct pci_dev *pdev,
+	const struct pci_device_id *ent)
+{
+	int error = 0;
+	struct sep_device *sep = NULL;
+
+	if (sep_dev != NULL) {
+		dev_dbg(&pdev->dev, "only one SEP supported.\n");
+		return -EBUSY;
+	}
+
+	/* Enable the device */
+	error = pci_enable_device(pdev);
+	if (error) {
+		dev_warn(&pdev->dev, "error enabling pci device\n");
+		goto end_function;
+	}
+
+	/* Allocate the sep_device structure for this device */
+	sep_dev = kzalloc(sizeof(struct sep_device), GFP_ATOMIC);
+	if (sep_dev == NULL) {
+		dev_warn(&pdev->dev,
+			"can't kmalloc the sep_device structure\n");
+		error = -ENOMEM;
+		goto end_function_disable_device;
+	}
+
+	/*
+	 * We're going to use another variable for actually
+	 * working with the device; this way, if we have
+	 * multiple devices in the future, it would be easier
+	 * to make appropriate changes
+	 */
+	sep = sep_dev;
+
+	sep->pdev = pci_dev_get(pdev);
+
+	init_waitqueue_head(&sep->event_transactions);
+	init_waitqueue_head(&sep->event_interrupt);
+	spin_lock_init(&sep->snd_rply_lck);
+	spin_lock_init(&sep->sep_queue_lock);
+	sema_init(&sep->sep_doublebuf, SEP_DOUBLEBUF_USERS_LIMIT);
+
+	INIT_LIST_HEAD(&sep->sep_queue_status);
+
+	dev_dbg(&sep->pdev->dev, "sep probe: PCI obtained, "
+		"device being prepared\n");
+
+	/* Set up our register area */
+	sep->reg_physical_addr = pci_resource_start(sep->pdev, 0);
+	if (!sep->reg_physical_addr) {
+		dev_warn(&sep->pdev->dev, "Error getting register start\n");
+		error = -ENODEV;
+		goto end_function_free_sep_dev;
+	}
+
+	sep->reg_physical_end = pci_resource_end(sep->pdev, 0);
+	if (!sep->reg_physical_end) {
+		dev_warn(&sep->pdev->dev, "Error getting register end\n");
+		error = -ENODEV;
+		goto end_function_free_sep_dev;
+	}
+
+	sep->reg_addr = ioremap_nocache(sep->reg_physical_addr,
+		(size_t)(sep->reg_physical_end - sep->reg_physical_addr + 1));
+	if (!sep->reg_addr) {
+		dev_warn(&sep->pdev->dev, "Error getting register virtual\n");
+		error = -ENODEV;
+		goto end_function_free_sep_dev;
+	}
+
+	dev_dbg(&sep->pdev->dev,
+		"Register area start %llx end %llx virtual %p\n",
+		(unsigned long long)sep->reg_physical_addr,
+		(unsigned long long)sep->reg_physical_end,
+		sep->reg_addr);
+
+	/* Allocate the shared area */
+	sep->shared_size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES +
+		SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES +
+		SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES +
+		SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES +
+		SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES;
+
+	if (sep_map_and_alloc_shared_area(sep)) {
+		error = -ENOMEM;
+		/* Allocation failed */
+		goto end_function_error;
+	}
+
+	/* Clear ICR register */
+	sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, 0xFFFFFFFF);
+
+	/* Set the IMR register - open only GPR 2 */
+	sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13)));
+
+	/* Read send/receive counters from SEP */
+	sep->reply_ct = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
+	sep->reply_ct &= 0x3FFFFFFF;
+	sep->send_ct = sep->reply_ct;
+
+	/* Get the interrupt line */
+	error = request_irq(pdev->irq, sep_inthandler, IRQF_SHARED,
+		"sep_driver", sep);
+
+	if (error)
+		goto end_function_deallocate_sep_shared_area;
+
+	/* The new chip requires a shared area reconfigure */
+	error = sep_reconfig_shared_area(sep);
+	if (error)
+		goto end_function_free_irq;
+
+	sep->in_use = 1;
+
+	/* Finally magic up the device nodes */
+	/* Register driver with the fs */
+	error = sep_register_driver_with_fs(sep);
+
+	if (error) {
+		dev_err(&sep->pdev->dev, "error registering dev file\n");
+		goto end_function_free_irq;
+	}
+
+	sep->in_use = 0; /* through touching the device */
+#ifdef SEP_ENABLE_RUNTIME_PM
+	pm_runtime_put_noidle(&sep->pdev->dev);
+	pm_runtime_allow(&sep->pdev->dev);
+	pm_runtime_set_autosuspend_delay(&sep->pdev->dev,
+		SUSPEND_DELAY);
+	pm_runtime_use_autosuspend(&sep->pdev->dev);
+	pm_runtime_mark_last_busy(&sep->pdev->dev);
+	sep->power_save_setup = 1;
+#endif
+	/* register kernel crypto driver */
+#if defined(CONFIG_CRYPTO) || defined(CONFIG_CRYPTO_MODULE)
+	error = sep_crypto_setup();
+	if (error) {
+		dev_err(&sep->pdev->dev, "crypto setup failed\n");
+		goto end_function_free_irq;
+	}
+#endif
+	goto end_function;
+
+end_function_free_irq:
+	free_irq(pdev->irq, sep);
+
+end_function_deallocate_sep_shared_area:
+	/* De-allocate shared area */
+	sep_unmap_and_free_shared_area(sep);
+
+end_function_error:
+	iounmap(sep->reg_addr);
+
+end_function_free_sep_dev:
+	pci_dev_put(sep_dev->pdev);
+	kfree(sep_dev);
+	sep_dev = NULL;
+
+end_function_disable_device:
+	pci_disable_device(pdev);
+
+end_function:
+	return error;
+}
+
+/**
+ * sep_remove -	handles removing device from pci subsystem
+ * @pdev:	pointer to pci device
+ *
+ * This function will handle removing our sep device from pci subsystem on exit
+ * or unloading this module. It should free up all used resources, and unmap if
+ * any memory regions mapped.
+ */
+static void sep_remove(struct pci_dev *pdev)
+{
+	struct sep_device *sep = sep_dev;
+
+	/* Unregister from fs */
+	misc_deregister(&sep->miscdev_sep);
+
+	/* Unregister from kernel crypto */
+#if defined(CONFIG_CRYPTO) || defined(CONFIG_CRYPTO_MODULE)
+	sep_crypto_takedown();
+#endif
+	/* Free the irq */
+	free_irq(sep->pdev->irq, sep);
+
+	/* Free the shared area  */
+	sep_unmap_and_free_shared_area(sep_dev);
+	iounmap(sep_dev->reg_addr);
+
+#ifdef SEP_ENABLE_RUNTIME_PM
+	if (sep->in_use) {
+		sep->in_use = 0;
+		pm_runtime_forbid(&sep->pdev->dev);
+		pm_runtime_get_noresume(&sep->pdev->dev);
+	}
+#endif
+	pci_dev_put(sep_dev->pdev);
+	kfree(sep_dev);
+	sep_dev = NULL;
+}
+
+/* Initialize struct pci_device_id for our driver */
+static DEFINE_PCI_DEVICE_TABLE(sep_pci_id_tbl) = {
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0826)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08e9)},
+ 	{0}
+};
+
+/* Export our pci_device_id structure to user space */
+MODULE_DEVICE_TABLE(pci, sep_pci_id_tbl);
+
+#ifdef SEP_ENABLE_RUNTIME_PM
+
+/**
+ * sep_pm_resume - rsume routine while waking up from S3 state
+ * @dev:	pointer to sep device
+ *
+ * This function is to be used to wake up sep driver while system awakes from S3
+ * state i.e. suspend to ram. The RAM in intact.
+ * Notes - revisit with more understanding of pm, ICR/IMR & counters.
+ */
+static int sep_pci_resume(struct device *dev)
+{
+	struct sep_device *sep = sep_dev;
+
+	dev_dbg(&sep->pdev->dev, "pci resume called\n");
+
+	if (sep->power_state == SEP_DRIVER_POWERON)
+		return 0;
+
+	/* Clear ICR register */
+	sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, 0xFFFFFFFF);
+
+	/* Set the IMR register - open only GPR 2 */
+	sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13)));
+
+	/* Read send/receive counters from SEP */
+	sep->reply_ct = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
+	sep->reply_ct &= 0x3FFFFFFF;
+	sep->send_ct = sep->reply_ct;
+
+	sep->power_state = SEP_DRIVER_POWERON;
+
+	return 0;
+}
+
+/**
+ * sep_pm_suspend - suspend routine while going to S3 state
+ * @dev:	pointer to sep device
+ *
+ * This function is to be used to suspend sep driver while system goes to S3
+ * state i.e. suspend to ram. The RAM in intact and ON during this suspend.
+ * Notes - revisit with more understanding of pm, ICR/IMR
+ */
+static int sep_pci_suspend(struct device *dev)
+{
+	struct sep_device *sep = sep_dev;
+
+	dev_dbg(&sep->pdev->dev, "pci suspend called\n");
+	if (sep->in_use == 1)
+		return -EAGAIN;
+
+	sep->power_state = SEP_DRIVER_POWEROFF;
+
+	/* Clear ICR register */
+	sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, 0xFFFFFFFF);
+
+	/* Set the IMR to block all */
+	sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, 0xFFFFFFFF);
+
+	return 0;
+}
+
+/**
+ * sep_pm_runtime_resume - runtime resume routine
+ * @dev:	pointer to sep device
+ *
+ * Notes - revisit with more understanding of pm, ICR/IMR & counters
+ */
+static int sep_pm_runtime_resume(struct device *dev)
+{
+
+	u32 retval2;
+	u32 delay_count;
+	struct sep_device *sep = sep_dev;
+
+	dev_dbg(&sep->pdev->dev, "pm runtime resume called\n");
+
+	/**
+	 * Wait until the SCU boot is ready
+	 * This is done by iterating SCU_DELAY_ITERATION (10
+	 * microseconds each) up to SCU_DELAY_MAX (50) times.
+	 * This bit can be set in a random time that is less
+	 * than 500 microseconds after each power resume
+	 */
+	retval2 = 0;
+	delay_count = 0;
+	while ((!retval2) && (delay_count < SCU_DELAY_MAX)) {
+		retval2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
+		retval2 &= 0x00000008;
+		if (!retval2) {
+			udelay(SCU_DELAY_ITERATION);
+			delay_count += 1;
+		}
+	}
+
+	if (!retval2) {
+		dev_warn(&sep->pdev->dev, "scu boot bit not set at resume\n");
+		return -EINVAL;
+	}
+
+	/* Clear ICR register */
+	sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, 0xFFFFFFFF);
+
+	/* Set the IMR register - open only GPR 2 */
+	sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13)));
+
+	/* Read send/receive counters from SEP */
+	sep->reply_ct = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
+	sep->reply_ct &= 0x3FFFFFFF;
+	sep->send_ct = sep->reply_ct;
+
+	return 0;
+}
+
+/**
+ * sep_pm_runtime_suspend - runtime suspend routine
+ * @dev:	pointer to sep device
+ *
+ * Notes - revisit with more understanding of pm
+ */
+static int sep_pm_runtime_suspend(struct device *dev)
+{
+	struct sep_device *sep = sep_dev;
+
+	dev_dbg(&sep->pdev->dev, "pm runtime suspend called\n");
+
+	/* Clear ICR register */
+	sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, 0xFFFFFFFF);
+	return 0;
+}
+
+/**
+ * sep_pm - power management for sep driver
+ * @sep_pm_runtime_resume:	resume- no communication with cpu & main memory
+ * @sep_pm_runtime_suspend:	suspend- no communication with cpu & main memory
+ * @sep_pci_suspend:		suspend - main memory is still ON
+ * @sep_pci_resume:		resume - main meory is still ON
+ */
+static const struct dev_pm_ops sep_pm = {
+	.runtime_resume = sep_pm_runtime_resume,
+	.runtime_suspend = sep_pm_runtime_suspend,
+	.resume = sep_pci_resume,
+	.suspend = sep_pci_suspend,
+};
+#endif /* SEP_ENABLE_RUNTIME_PM */
+
+/**
+ * sep_pci_driver - registers this device with pci subsystem
+ * @name:	name identifier for this driver
+ * @sep_pci_id_tbl:	pointer to struct pci_device_id table
+ * @sep_probe:	pointer to probe function in PCI driver
+ * @sep_remove:	pointer to remove function in PCI driver
+ */
+static struct pci_driver sep_pci_driver = {
+#ifdef SEP_ENABLE_RUNTIME_PM
+	.driver = {
+		.pm = &sep_pm,
+	},
+#endif
+	.name = "sep_sec_driver",
+	.id_table = sep_pci_id_tbl,
+	.probe = sep_probe,
+	.remove = sep_remove
+};
+
+/**
+ * sep_init - init function
+ *
+ * Module load time. Register the PCI device driver.
+ */
+
+static int __init sep_init(void)
+{
+	return pci_register_driver(&sep_pci_driver);
+}
+
+
+/**
+ * sep_exit - called to unload driver
+ *
+ * Unregister the driver The device will perform all the cleanup required.
+ */
+static void __exit sep_exit(void)
+{
+	pci_unregister_driver(&sep_pci_driver);
+}
+
+
+module_init(sep_init);
+module_exit(sep_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/sep/sep_trace_events.h b/drivers/staging/sep/sep_trace_events.h
new file mode 100644
index 0000000..2b053a9
--- /dev/null
+++ b/drivers/staging/sep/sep_trace_events.h
@@ -0,0 +1,188 @@
+/*
+ * If TRACE_SYSTEM is defined, that will be the directory created
+ * in the ftrace directory under /sys/kernel/debug/tracing/events/<system>
+ *
+ * The define_trace.h below will also look for a file name of
+ * TRACE_SYSTEM.h where TRACE_SYSTEM is what is defined here.
+ * In this case, it would look for sample.h
+ *
+ * If the header name will be different than the system name
+ * (as in this case), then you can override the header name that
+ * define_trace.h will look up by defining TRACE_INCLUDE_FILE
+ *
+ * This file is called trace-events-sample.h but we want the system
+ * to be called "sample". Therefore we must define the name of this
+ * file:
+ *
+ * #define TRACE_INCLUDE_FILE trace-events-sample
+ *
+ * As we do an the bottom of this file.
+ *
+ * Notice that TRACE_SYSTEM should be defined outside of #if
+ * protection, just like TRACE_INCLUDE_FILE.
+ */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM sep
+
+/*
+ * Notice that this file is not protected like a normal header.
+ * We also must allow for rereading of this file. The
+ *
+ *  || defined(TRACE_HEADER_MULTI_READ)
+ *
+ * serves this purpose.
+ */
+#if !defined(_TRACE_SEP_EVENTS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_SEP_EVENTS_H
+
+#ifdef SEP_PERF_DEBUG
+#define SEP_TRACE_FUNC_IN() trace_sep_func_start(__func__, 0)
+#define SEP_TRACE_FUNC_OUT(branch) trace_sep_func_end(__func__, branch)
+#define SEP_TRACE_EVENT(branch) trace_sep_misc_event(__func__, branch)
+#else
+#define SEP_TRACE_FUNC_IN()
+#define SEP_TRACE_FUNC_OUT(branch)
+#define SEP_TRACE_EVENT(branch)
+#endif
+
+
+/*
+ * All trace headers should include tracepoint.h, until we finally
+ * make it into a standard header.
+ */
+#include <linux/tracepoint.h>
+
+/*
+ * The TRACE_EVENT macro is broken up into 5 parts.
+ *
+ * name: name of the trace point. This is also how to enable the tracepoint.
+ *   A function called trace_foo_bar() will be created.
+ *
+ * proto: the prototype of the function trace_foo_bar()
+ *   Here it is trace_foo_bar(char *foo, int bar).
+ *
+ * args:  must match the arguments in the prototype.
+ *    Here it is simply "foo, bar".
+ *
+ * struct:  This defines the way the data will be stored in the ring buffer.
+ *    There are currently two types of elements. __field and __array.
+ *    a __field is broken up into (type, name). Where type can be any
+ *    type but an array.
+ *    For an array. there are three fields. (type, name, size). The
+ *    type of elements in the array, the name of the field and the size
+ *    of the array.
+ *
+ *    __array( char, foo, 10) is the same as saying   char foo[10].
+ *
+ * fast_assign: This is a C like function that is used to store the items
+ *    into the ring buffer.
+ *
+ * printk: This is a way to print out the data in pretty print. This is
+ *    useful if the system crashes and you are logging via a serial line,
+ *    the data can be printed to the console using this "printk" method.
+ *
+ * Note, that for both the assign and the printk, __entry is the handler
+ * to the data structure in the ring buffer, and is defined by the
+ * TP_STRUCT__entry.
+ */
+TRACE_EVENT(sep_func_start,
+
+	TP_PROTO(const char *name, int branch),
+
+	TP_ARGS(name, branch),
+
+	TP_STRUCT__entry(
+		__array(char,	name,    20)
+		__field(int,	branch)
+	),
+
+	TP_fast_assign(
+		strncpy(__entry->name, name, 20);
+		__entry->branch	= branch;
+	),
+
+	TP_printk("func_start %s %d", __entry->name, __entry->branch)
+);
+
+TRACE_EVENT(sep_func_end,
+
+	TP_PROTO(const char *name, int branch),
+
+	TP_ARGS(name, branch),
+
+	TP_STRUCT__entry(
+		__array(char,	name,    20)
+		__field(int,	branch)
+	),
+
+	TP_fast_assign(
+		strncpy(__entry->name, name, 20);
+		__entry->branch	= branch;
+	),
+
+	TP_printk("func_end %s %d", __entry->name, __entry->branch)
+);
+
+TRACE_EVENT(sep_misc_event,
+
+	TP_PROTO(const char *name, int branch),
+
+	TP_ARGS(name, branch),
+
+	TP_STRUCT__entry(
+		__array(char,	name,    20)
+		__field(int,	branch)
+	),
+
+	TP_fast_assign(
+		strncpy(__entry->name, name, 20);
+		__entry->branch	= branch;
+	),
+
+	TP_printk("misc_event %s %d", __entry->name, __entry->branch)
+);
+
+
+#endif
+
+/***** NOTICE! The #if protection ends here. *****/
+
+
+/*
+ * There are several ways I could have done this. If I left out the
+ * TRACE_INCLUDE_PATH, then it would default to the kernel source
+ * include/trace/events directory.
+ *
+ * I could specify a path from the define_trace.h file back to this
+ * file.
+ *
+ * #define TRACE_INCLUDE_PATH ../../samples/trace_events
+ *
+ * But the safest and easiest way to simply make it use the directory
+ * that the file is in is to add in the Makefile:
+ *
+ * CFLAGS_trace-events-sample.o := -I$(src)
+ *
+ * This will make sure the current path is part of the include
+ * structure for our file so that define_trace.h can find it.
+ *
+ * I could have made only the top level directory the include:
+ *
+ * CFLAGS_trace-events-sample.o := -I$(PWD)
+ *
+ * And then let the path to this directory be the TRACE_INCLUDE_PATH:
+ *
+ * #define TRACE_INCLUDE_PATH samples/trace_events
+ *
+ * But then if something defines "samples" or "trace_events" as a macro
+ * then we could risk that being converted too, and give us an unexpected
+ * result.
+ */
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH .
+/*
+ * TRACE_INCLUDE_FILE is not needed if the filename and TRACE_SYSTEM are equal
+ */
+#define TRACE_INCLUDE_FILE sep_trace_events
+#include <trace/define_trace.h>
diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c
index 1c5780f..ae1d815 100644
--- a/drivers/staging/serqt_usb2/serqt_usb2.c
+++ b/drivers/staging/serqt_usb2/serqt_usb2.c
@@ -200,7 +200,6 @@
 	.probe = usb_serial_probe,
 	.disconnect = usb_serial_disconnect,
 	.id_table = serqt_id_table,
-	.no_dynamic_id = 1,
 };
 
 static int port_paranoia_check(struct usb_serial_port *port,
@@ -1590,7 +1589,6 @@
 		   .name = "serqt",
 		   },
 	.description = DRIVER_DESC,
-	.usb_driver = &serqt_usb_driver,
 	.id_table = serqt_id_table,
 	.num_ports = 8,
 	.open = qt_open,
@@ -1610,41 +1608,11 @@
 	.release = qt_release,
 };
 
-static int __init serqt_usb_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&quatech_device, NULL
+};
 
-	dbg("%s\n", __func__);
-
-	/* register with usb-serial */
-	retval = usb_serial_register(&quatech_device);
-
-	if (retval)
-		goto failed_usb_serial_register;
-
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-
-	/* register with usb */
-
-	retval = usb_register(&serqt_usb_driver);
-	if (retval == 0)
-		return 0;
-
-	/* if we're here, usb_register() failed */
-	usb_serial_deregister(&quatech_device);
-failed_usb_serial_register:
-	return retval;
-}
-
-static void __exit serqt_usb_exit(void)
-{
-	usb_deregister(&serqt_usb_driver);
-	usb_serial_deregister(&quatech_device);
-}
-
-module_init(serqt_usb_init);
-module_exit(serqt_usb_exit);
+module_usb_serial_driver(serqt_usb_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/staging/slicoss/README b/drivers/staging/slicoss/README
index b83bba1..cb04a87 100644
--- a/drivers/staging/slicoss/README
+++ b/drivers/staging/slicoss/README
@@ -42,7 +42,7 @@
 
 
 Please send patches to:
-        Greg Kroah-Hartman <gregkh@suse.de>
+        Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 and Cc: Lior Dotan <liodot@gmail.com> and Christopher Harrer
 <charrer@alacritech.com> as well as they are also able to test out any
 changes.
diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c
index ae0035f..83c582e 100644
--- a/drivers/staging/sm7xx/smtcfb.c
+++ b/drivers/staging/sm7xx/smtcfb.c
@@ -41,7 +41,6 @@
 
 #ifdef CONFIG_PM
 #include <linux/pm.h>
-#include <linux/module.h>
 #endif
 
 #include "smtcfb.h"
@@ -443,7 +442,7 @@
 }
 
 #ifdef __BIG_ENDIAN
-static ssize_t smtcfb_read(struct fb_info *info, char __user * buf, size_t
+static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, size_t
 				count, loff_t *ppos)
 {
 	unsigned long p = *ppos;
diff --git a/drivers/staging/sm7xx/smtcfb.h b/drivers/staging/sm7xx/smtcfb.h
index c5e6989..ab95af2 100644
--- a/drivers/staging/sm7xx/smtcfb.h
+++ b/drivers/staging/sm7xx/smtcfb.h
@@ -38,7 +38,7 @@
 #define dac_reg	(0x3c8)
 #define dac_val	(0x3c9)
 
-extern char *smtc_RegBaseAddress;
+extern char __iomem *smtc_RegBaseAddress;
 #define smtc_mmiowb(dat, reg)	writeb(dat, smtc_RegBaseAddress + reg)
 #define smtc_mmioww(dat, reg)	writew(dat, smtc_RegBaseAddress + reg)
 #define smtc_mmiowl(dat, reg)	writel(dat, smtc_RegBaseAddress + reg)
diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c
index c7b03f0..92b34e2 100644
--- a/drivers/staging/speakup/main.c
+++ b/drivers/staging/speakup/main.c
@@ -1731,15 +1731,15 @@
 	switch (value) {
 	case KVAL(K_CAPS):
 		label = msg_get(MSG_KEYNAME_CAPSLOCK);
-		on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_CAPSLOCK));
+		on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
 		break;
 	case KVAL(K_NUM):
 		label = msg_get(MSG_KEYNAME_NUMLOCK);
-		on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_NUMLOCK));
+		on_off = vt_get_leds(fg_console, VC_NUMLOCK);
 		break;
 	case KVAL(K_HOLD):
 		label = msg_get(MSG_KEYNAME_SCROLLLOCK);
-		on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_SCROLLOCK));
+		on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
 		if (speakup_console[vc->vc_num])
 			speakup_console[vc->vc_num]->tty_stopped = on_off;
 		break;
@@ -2020,7 +2020,7 @@
 	if (type >= 0xf0)
 		type -= 0xf0;
 	if (type == KT_PAD
-		&& (vc_kbd_led(kbd_table + fg_console, VC_NUMLOCK))) {
+		&& (vt_get_leds(fg_console, VC_NUMLOCK))) {
 		if (up_flag) {
 			spk_keydown = 0;
 			goto out;
diff --git a/drivers/staging/speakup/serialio.c b/drivers/staging/speakup/serialio.c
index 7f3d87b..a97d3d5 100644
--- a/drivers/staging/speakup/serialio.c
+++ b/drivers/staging/speakup/serialio.c
@@ -8,21 +8,20 @@
 
 static void start_serial_interrupt(int irq);
 
-static struct serial_state rs_table[] = {
+static const struct old_serial_port rs_table[] = {
 	SERIAL_PORT_DFNS
 };
-static struct serial_state *serstate;
+static const struct old_serial_port *serstate;
 static int timeouts;
 
-struct serial_state *spk_serial_init(int index)
+const struct old_serial_port *spk_serial_init(int index)
 {
 	int baud = 9600, quot = 0;
 	unsigned int cval = 0;
 	int cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8;
-	struct serial_state *ser = NULL;
+	const struct old_serial_port *ser = rs_table + index;
 	int err;
 
-	ser = rs_table + index;
 	/*	Divisor, bytesize and parity */
 	quot = ser->baud_base / baud;
 	cval = cflag & (CSIZE | CSTOPB);
@@ -41,7 +40,7 @@
 		__release_region(&ioport_resource, ser->port, 8);
 		err = synth_request_region(ser->port, 8);
 		if (err) {
-			pr_warn("Unable to allocate port at %lx, errno %i",
+			pr_warn("Unable to allocate port at %x, errno %i",
 				ser->port, err);
 			return NULL;
 		}
diff --git a/drivers/staging/speakup/serialio.h b/drivers/staging/speakup/serialio.h
index d785b1f..614271f 100644
--- a/drivers/staging/speakup/serialio.h
+++ b/drivers/staging/speakup/serialio.h
@@ -4,11 +4,22 @@
 #include <linux/serial.h>	/* for rs_table, serial constants &
 				   serial_uart_config */
 #include <linux/serial_reg.h>	/* for more serial constants */
-#include <linux/serialP.h>	/* for struct serial_state */
 #ifndef __sparc__
 #include <asm/serial.h>
 #endif
 
+/*
+ * this is cut&paste from 8250.h. Get rid of the structure, the definitions
+ * and this whole broken driver.
+ */
+struct old_serial_port {
+	unsigned int uart; /* unused */
+	unsigned int baud_base;
+	unsigned int port;
+	unsigned int irq;
+	unsigned int flags; /* unused */
+};
+
 /* countdown values for serial timeouts in us */
 #define SPK_SERIAL_TIMEOUT 100000
 /* countdown values transmitter/dsr timeouts in us */
diff --git a/drivers/staging/speakup/spk_priv.h b/drivers/staging/speakup/spk_priv.h
index 16ace4a..a47c5b7 100644
--- a/drivers/staging/speakup/spk_priv.h
+++ b/drivers/staging/speakup/spk_priv.h
@@ -44,7 +44,7 @@
 
 #define KT_SPKUP 15
 
-extern struct serial_state *spk_serial_init(int index);
+extern const struct old_serial_port *spk_serial_init(int index);
 extern void stop_serial_interrupt(void);
 extern int wait_for_xmitr(void);
 extern unsigned char spk_serial_in(void);
diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c
index 2222d69..331eae7 100644
--- a/drivers/staging/speakup/synth.c
+++ b/drivers/staging/speakup/synth.c
@@ -34,7 +34,7 @@
 
 int serial_synth_probe(struct spk_synth *synth)
 {
-	struct serial_state *ser;
+	const struct old_serial_port *ser;
 	int failed = 0;
 
 	if ((synth->ser >= SPK_LO_TTY) && (synth->ser <= SPK_HI_TTY)) {
diff --git a/drivers/telephony/Kconfig b/drivers/staging/telephony/Kconfig
similarity index 100%
rename from drivers/telephony/Kconfig
rename to drivers/staging/telephony/Kconfig
diff --git a/drivers/telephony/Makefile b/drivers/staging/telephony/Makefile
similarity index 100%
rename from drivers/telephony/Makefile
rename to drivers/staging/telephony/Makefile
diff --git a/drivers/staging/telephony/TODO b/drivers/staging/telephony/TODO
new file mode 100644
index 0000000..d47dec3
--- /dev/null
+++ b/drivers/staging/telephony/TODO
@@ -0,0 +1,10 @@
+TODO
+. Determine if the boards are still in use
+  and move this module back to drivers/telephony if necessary
+. Coding style cleanups
+
+Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
+cc Joe Perches <joe@perches.com> if the module should be reactivated.
+
+If no module activity occurs before version 3.6 is released, this
+module should be removed.
diff --git a/drivers/telephony/ixj-ver.h b/drivers/staging/telephony/ixj-ver.h
similarity index 100%
rename from drivers/telephony/ixj-ver.h
rename to drivers/staging/telephony/ixj-ver.h
diff --git a/drivers/telephony/ixj.c b/drivers/staging/telephony/ixj.c
similarity index 100%
rename from drivers/telephony/ixj.c
rename to drivers/staging/telephony/ixj.c
diff --git a/drivers/telephony/ixj.h b/drivers/staging/telephony/ixj.h
similarity index 100%
rename from drivers/telephony/ixj.h
rename to drivers/staging/telephony/ixj.h
diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/staging/telephony/ixj_pcmcia.c
similarity index 100%
rename from drivers/telephony/ixj_pcmcia.c
rename to drivers/staging/telephony/ixj_pcmcia.c
diff --git a/drivers/telephony/phonedev.c b/drivers/staging/telephony/phonedev.c
similarity index 100%
rename from drivers/telephony/phonedev.c
rename to drivers/staging/telephony/phonedev.c
diff --git a/drivers/staging/tidspbridge/Kconfig b/drivers/staging/tidspbridge/Kconfig
index 21a559e..0dd479f 100644
--- a/drivers/staging/tidspbridge/Kconfig
+++ b/drivers/staging/tidspbridge/Kconfig
@@ -31,12 +31,6 @@
 	  Allocate specified size of memory at booting time to avoid allocation
 	  failure under heavy memory fragmentation after some use time.
 
-config TIDSPBRIDGE_DEBUG
-	bool "Debug Support"
-	depends on TIDSPBRIDGE
-	help
-	  Say Y to enable Bridge debugging capabilities
-
 config TIDSPBRIDGE_RECOVERY
 	bool "Recovery Support"
 	depends on TIDSPBRIDGE
@@ -58,22 +52,6 @@
 	  This can lead to heap corruption. Say Y, to enforce the check for 128
 	  byte alignment, buffers failing this check will be rejected.
 
-config TIDSPBRIDGE_WDT3
-	bool "Enable watchdog timer"
-	depends on TIDSPBRIDGE
-	help
-	  WTD3 is managed by DSP and once it is enabled, DSP side bridge is in
-	  charge of refreshing the timer before overflow, if the DSP hangs MPU
-	  will caught the interrupt and try to recover DSP.
-
-config TIDSPBRIDGE_WDT_TIMEOUT
-	int "Watchdog timer timeout (in secs)"
-	depends on TIDSPBRIDGE && TIDSPBRIDGE_WDT3
-	default 5
-	help
-	   Watchdog timer timeout value, after that time if the watchdog timer
-	   counter is not reset the wdt overflow interrupt will be triggered
-
 config TIDSPBRIDGE_NTFY_PWRERR
 	bool "Notify power errors"
 	depends on TIDSPBRIDGE
diff --git a/drivers/staging/tidspbridge/Makefile b/drivers/staging/tidspbridge/Makefile
index fd6a276..8c8c92a 100644
--- a/drivers/staging/tidspbridge/Makefile
+++ b/drivers/staging/tidspbridge/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_TIDSPBRIDGE)	+= bridgedriver.o
+obj-$(CONFIG_TIDSPBRIDGE)	+= tidspbridge.o
 
 libgen = gen/gh.o gen/uuidutil.o
 libcore = core/chnl_sm.o core/msg_sm.o core/io_sm.o core/tiomap3430.o \
@@ -13,7 +13,7 @@
 		 dynload/tramp.o
 libhw = hw/hw_mmu.o
 
-bridgedriver-y := $(libgen) $(libservices) $(libcore) $(libpmgr) $(librmgr) \
+tidspbridge-y := $(libgen) $(libservices) $(libcore) $(libpmgr) $(librmgr) \
 			$(libdload) $(libhw)
 
 #Machine dependent
diff --git a/drivers/staging/tidspbridge/core/chnl_sm.c b/drivers/staging/tidspbridge/core/chnl_sm.c
index 6d66e7d..e0c7e4c 100644
--- a/drivers/staging/tidspbridge/core/chnl_sm.c
+++ b/drivers/staging/tidspbridge/core/chnl_sm.c
@@ -50,9 +50,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- OS Adaptation Layer */
 #include <dspbridge/sync.h>
 
@@ -123,7 +120,6 @@
 				CHNL_IS_OUTPUT(pchnl->chnl_mode))
 			return -EPIPE;
 		/* No other possible states left */
-		DBC_ASSERT(0);
 	}
 
 	dev_obj = dev_get_first();
@@ -190,7 +186,6 @@
 	 * Note: for dma chans dw_dsp_addr contains dsp address
 	 * of SM buffer.
 	 */
-	DBC_ASSERT(chnl_mgr_obj->word_size != 0);
 	/* DSP address */
 	chnl_packet_obj->dsp_tx_addr = dw_dsp_addr / chnl_mgr_obj->word_size;
 	chnl_packet_obj->byte_size = byte_size;
@@ -201,7 +196,6 @@
 			CHNL_IOCSTATCOMPLETE);
 	list_add_tail(&chnl_packet_obj->link, &pchnl->io_requests);
 	pchnl->cio_reqs++;
-	DBC_ASSERT(pchnl->cio_reqs <= pchnl->chnl_packets);
 	/*
 	 * If end of stream, update the channel state to prevent
 	 * more IOR's.
@@ -209,8 +203,6 @@
 	if (is_eos)
 		pchnl->state |= CHNL_STATEEOS;
 
-	/* Legacy DSM Processor-Copy */
-	DBC_ASSERT(pchnl->chnl_type == CHNL_PCPY);
 	/* Request IO from the DSP */
 	io_request_chnl(chnl_mgr_obj->iomgr, pchnl,
 			(CHNL_IS_INPUT(pchnl->chnl_mode) ? IO_INPUT :
@@ -283,7 +275,6 @@
 		list_add_tail(&chirp->link, &pchnl->io_completions);
 		pchnl->cio_cs++;
 		pchnl->cio_reqs--;
-		DBC_ASSERT(pchnl->cio_reqs >= 0);
 	}
 
 	spin_unlock_bh(&chnl_mgr_obj->chnl_mgr_lock);
@@ -311,8 +302,6 @@
 	status = bridge_chnl_cancel_io(chnl_obj);
 	if (status)
 		return status;
-	/* Assert I/O on this channel is now cancelled: Protects from io_dpc */
-	DBC_ASSERT((pchnl->state & CHNL_STATECANCEL));
 	/* Invalidate channel object: Protects from CHNL_GetIOCompletion() */
 	/* Free the slot in the channel manager: */
 	pchnl->chnl_mgr_obj->channels[pchnl->chnl_id] = NULL;
@@ -358,13 +347,6 @@
 	struct chnl_mgr *chnl_mgr_obj = NULL;
 	u8 max_channels;
 
-	/* Check DBC requirements: */
-	DBC_REQUIRE(channel_mgr != NULL);
-	DBC_REQUIRE(mgr_attrts != NULL);
-	DBC_REQUIRE(mgr_attrts->max_channels > 0);
-	DBC_REQUIRE(mgr_attrts->max_channels <= CHNL_MAXCHANNELS);
-	DBC_REQUIRE(mgr_attrts->word_size != 0);
-
 	/* Allocate channel manager object */
 	chnl_mgr_obj = kzalloc(sizeof(struct chnl_mgr), GFP_KERNEL);
 	if (chnl_mgr_obj) {
@@ -374,7 +356,6 @@
 		 *      mgr_attrts->max_channels = CHNL_MAXCHANNELS =
 		 *                       DDMA_MAXDDMACHNLS = DDMA_MAXZCPYCHNLS.
 		 */
-		DBC_ASSERT(mgr_attrts->max_channels == CHNL_MAXCHANNELS);
 		max_channels = CHNL_MAXCHANNELS + CHNL_MAXCHANNELS * CHNL_PCPY;
 		/* Create array of channels */
 		chnl_mgr_obj->channels = kzalloc(sizeof(struct chnl_object *)
@@ -491,7 +472,6 @@
 			pchnl->state &= ~CHNL_STATECANCEL;
 		}
 	}
-	DBC_ENSURE(status || list_empty(&pchnl->io_requests));
 	return status;
 }
 
@@ -592,7 +572,6 @@
 	omap_mbox_disable_irq(dev_ctxt->mbox, IRQ_RX);
 	if (dequeue_ioc) {
 		/* Dequeue IOC and set chan_ioc; */
-		DBC_ASSERT(!list_empty(&pchnl->io_completions));
 		chnl_packet_obj = list_first_entry(&pchnl->io_completions,
 				struct chnl_irp, link);
 		list_del(&chnl_packet_obj->link);
@@ -705,8 +684,6 @@
 	struct chnl_mgr *chnl_mgr_obj;
 	int status = 0;
 
-	DBC_REQUIRE(chnl_obj);
-
 	chnl_mode = chnl_obj->chnl_mode;
 	chnl_mgr_obj = chnl_obj->chnl_mgr_obj;
 
@@ -736,10 +713,7 @@
 	struct chnl_mgr *chnl_mgr_obj = hchnl_mgr;
 	struct chnl_object *pchnl = NULL;
 	struct sync_object *sync_event = NULL;
-	/* Ensure DBC requirements: */
-	DBC_REQUIRE(chnl != NULL);
-	DBC_REQUIRE(pattrs != NULL);
-	DBC_REQUIRE(hchnl_mgr != NULL);
+
 	*chnl = NULL;
 
 	/* Validate Args: */
@@ -761,7 +735,6 @@
 			return status;
 	}
 
-	DBC_ASSERT(ch_id < chnl_mgr_obj->max_channels);
 
 	/* Create channel object: */
 	pchnl = kzalloc(sizeof(struct chnl_object), GFP_KERNEL);
@@ -850,7 +823,6 @@
 {
 	int status = 0;
 
-	DBC_ASSERT(!(event_mask & ~(DSP_STREAMDONE | DSP_STREAMIOCOMPLETION)));
 
 	if (event_mask)
 		status = ntfy_register(chnl_obj->ntfy_obj, hnotification,
@@ -906,8 +878,6 @@
 {
 	struct chnl_irp *chirp, *tmp;
 
-	DBC_REQUIRE(chirp_list != NULL);
-
 	list_for_each_entry_safe(chirp, tmp, chirp_list, link) {
 		list_del(&chirp->link);
 		kfree(chirp);
@@ -924,8 +894,6 @@
 	int status = -ENOSR;
 	u32 i;
 
-	DBC_REQUIRE(chnl_mgr_obj);
-
 	for (i = 0; i < chnl_mgr_obj->max_channels; i++) {
 		if (chnl_mgr_obj->channels[i] == NULL) {
 			status = 0;
diff --git a/drivers/staging/tidspbridge/core/dsp-clock.c b/drivers/staging/tidspbridge/core/dsp-clock.c
index 7eb5617..c7df34e 100644
--- a/drivers/staging/tidspbridge/core/dsp-clock.c
+++ b/drivers/staging/tidspbridge/core/dsp-clock.c
@@ -29,9 +29,6 @@
 #include <dspbridge/dev.h>
 #include "_tiomap.h"
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- This */
 #include <dspbridge/clk.h>
 
diff --git a/drivers/staging/tidspbridge/core/io_sm.c b/drivers/staging/tidspbridge/core/io_sm.c
index 694c0e5..9b50b5b 100644
--- a/drivers/staging/tidspbridge/core/io_sm.c
+++ b/drivers/staging/tidspbridge/core/io_sm.c
@@ -33,9 +33,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/* Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /* Services Layer */
 #include <dspbridge/ntfy.h>
 #include <dspbridge/sync.h>
@@ -114,7 +111,7 @@
 	struct mgr_processorextinfo ext_proc_info;
 	struct cmm_object *cmm_mgr;	/* Shared Mem Mngr */
 	struct work_struct io_workq;	/* workqueue */
-#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) || defined(CONFIG_TIDSPBRIDGE_DEBUG)
+#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE)
 	u32 trace_buffer_begin;	/* Trace message start address */
 	u32 trace_buffer_end;	/* Trace message end address */
 	u32 trace_buffer_current;	/* Trace message current address */
@@ -246,7 +243,7 @@
 		/* Free IO DPC object */
 		tasklet_kill(&hio_mgr->dpc_tasklet);
 
-#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) || defined(CONFIG_TIDSPBRIDGE_DEBUG)
+#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE)
 		kfree(hio_mgr->msg);
 #endif
 		dsp_wdt_exit();
@@ -386,7 +383,7 @@
 		status = -EFAULT;
 	}
 	if (!status) {
-#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) || defined(CONFIG_TIDSPBRIDGE_DEBUG)
+#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE)
 		status =
 		    cod_get_sym_value(cod_man, DSP_TRACESEC_END, &shm0_end);
 #else
@@ -731,7 +728,7 @@
 		hmsg_mgr->max_msgs);
 	memset((void *)hio_mgr->shared_mem, 0, sizeof(struct shm));
 
-#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) || defined(CONFIG_TIDSPBRIDGE_DEBUG)
+#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE)
 	/* Get the start address of trace buffer */
 	status = cod_get_sym_value(cod_man, SYS_PUTCBEG,
 				   &hio_mgr->trace_buffer_begin);
@@ -910,7 +907,7 @@
 		}
 
 #endif
-#ifdef CONFIG_TIDSPBRIDGE_DEBUG
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
 		if (pio_mgr->intr_val & MBX_DBG_SYSPRINTF) {
 			/* Notify DSP Trace message */
 			print_dsp_debug_trace(pio_mgr);
@@ -973,29 +970,16 @@
 	chnl_mgr_obj = io_manager->chnl_mgr;
 	sm = io_manager->shared_mem;
 	if (io_mode == IO_INPUT) {
-		/*
-		 * Assertion fires if CHNL_AddIOReq() called on a stream
-		 * which was cancelled, or attached to a dead board.
-		 */
-		DBC_ASSERT((pchnl->state == CHNL_STATEREADY) ||
-			   (pchnl->state == CHNL_STATEEOS));
 		/* Indicate to the DSP we have a buffer available for input */
 		set_chnl_busy(sm, pchnl->chnl_id);
 		*mbx_val = MBX_PCPY_CLASS;
 	} else if (io_mode == IO_OUTPUT) {
 		/*
-		 * This assertion fails if CHNL_AddIOReq() was called on a
-		 * stream which was cancelled, or attached to a dead board.
-		 */
-		DBC_ASSERT((pchnl->state & ~CHNL_STATEEOS) ==
-			   CHNL_STATEREADY);
-		/*
 		 * Record the fact that we have a buffer available for
 		 * output.
 		 */
 		chnl_mgr_obj->output_mask |= (1 << pchnl->chnl_id);
 	} else {
-		DBC_ASSERT(io_mode);	/* Shouldn't get here. */
 	}
 func_end:
 	return;
@@ -1087,7 +1071,6 @@
 	dw_arg = sm->arg;
 	if (chnl_id >= CHNL_MAXCHANNELS) {
 		/* Shouldn't be here: would indicate corrupted shm. */
-		DBC_ASSERT(chnl_id);
 		goto func_end;
 	}
 	pchnl = chnl_mgr_obj->channels[chnl_id];
@@ -1683,7 +1666,7 @@
 }
 
 
-#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) || defined(CONFIG_TIDSPBRIDGE_DEBUG)
+#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE)
 void print_dsp_debug_trace(struct io_mgr *hio_mgr)
 {
 	u32 ul_new_message_length = 0, ul_gpp_cur_pointer;
diff --git a/drivers/staging/tidspbridge/core/msg_sm.c b/drivers/staging/tidspbridge/core/msg_sm.c
index 94d9e04..ce9557e 100644
--- a/drivers/staging/tidspbridge/core/msg_sm.c
+++ b/drivers/staging/tidspbridge/core/msg_sm.c
@@ -20,9 +20,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- OS Adaptation Layer */
 #include <dspbridge/sync.h>
 
diff --git a/drivers/staging/tidspbridge/core/tiomap3430.c b/drivers/staging/tidspbridge/core/tiomap3430.c
index dde559d..7862513 100644
--- a/drivers/staging/tidspbridge/core/tiomap3430.c
+++ b/drivers/staging/tidspbridge/core/tiomap3430.c
@@ -27,9 +27,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- OS Adaptation Layer */
 #include <dspbridge/drv.h>
 #include <dspbridge/sync.h>
@@ -256,9 +253,6 @@
 void bridge_drv_entry(struct bridge_drv_interface **drv_intf,
 		   const char *driver_file_name)
 {
-
-	DBC_REQUIRE(driver_file_name != NULL);
-
 	if (strcmp(driver_file_name, "UMA") == 0)
 		*drv_intf = &drv_interface_fxns;
 	else
@@ -389,6 +383,7 @@
 	u32 clk_cmd;
 	struct io_mgr *hio_mgr;
 	u32 ul_load_monitor_timer;
+	u32 wdt_en = 0;
 	struct omap_dsp_platform_data *pdata =
 		omap_dspbridge_dev->dev.platform_data;
 
@@ -399,16 +394,13 @@
 	(void)dev_get_symbol(dev_context->dev_obj, SHMBASENAME,
 			     &ul_shm_base_virt);
 	ul_shm_base_virt *= DSPWORDSIZE;
-	DBC_ASSERT(ul_shm_base_virt != 0);
 	/* DSP Virtual address */
 	ul_tlb_base_virt = dev_context->atlb_entry[0].dsp_va;
-	DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt);
 	ul_shm_offset_virt =
 	    ul_shm_base_virt - (ul_tlb_base_virt * DSPWORDSIZE);
 	/* Kernel logical address */
 	ul_shm_base = dev_context->atlb_entry[0].gpp_va + ul_shm_offset_virt;
 
-	DBC_ASSERT(ul_shm_base != 0);
 	/* 2nd wd is used as sync field */
 	dw_sync_addr = ul_shm_base + SHMSYNCOFFSET;
 	/* Write a signature into the shm base + offset; this will
@@ -603,9 +595,12 @@
 		if (!wait_for_start(dev_context, dw_sync_addr))
 			status = -ETIMEDOUT;
 
-		/* Start wdt */
-		dsp_wdt_sm_set((void *)ul_shm_base);
-		dsp_wdt_enable(true);
+		dev_get_symbol(dev_context->dev_obj, "_WDT_enable", &wdt_en);
+		if (wdt_en) {
+			/* Start wdt */
+			dsp_wdt_sm_set((void *)ul_shm_base);
+			dsp_wdt_enable(true);
+		}
 
 		status = dev_get_io_mgr(dev_context->dev_obj, &hio_mgr);
 		if (hio_mgr) {
diff --git a/drivers/staging/tidspbridge/core/tiomap3430_pwr.c b/drivers/staging/tidspbridge/core/tiomap3430_pwr.c
index 02dd439..16a4aaf 100644
--- a/drivers/staging/tidspbridge/core/tiomap3430_pwr.c
+++ b/drivers/staging/tidspbridge/core/tiomap3430_pwr.c
@@ -303,7 +303,6 @@
 	}
 	/* TODO -- Assert may be a too hard restriction here.. May be we should
 	 * just return with failure when the CLK ID does not match */
-	/* DBC_ASSERT(clk_id_index < MBX_PM_MAX_RESOURCES); */
 	if (clk_id_index == MBX_PM_MAX_RESOURCES) {
 		/* return with a more meaningfull error code */
 		return -EPERM;
diff --git a/drivers/staging/tidspbridge/core/tiomap_io.c b/drivers/staging/tidspbridge/core/tiomap_io.c
index dfb356e..7fda10c 100644
--- a/drivers/staging/tidspbridge/core/tiomap_io.c
+++ b/drivers/staging/tidspbridge/core/tiomap_io.c
@@ -21,9 +21,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- Platform Manager */
 #include <dspbridge/dev.h>
 #include <dspbridge/drv.h>
@@ -68,20 +65,17 @@
 		status = dev_get_symbol(dev_context->dev_obj,
 					SHMBASENAME, &ul_shm_base_virt);
 	}
-	DBC_ASSERT(ul_shm_base_virt != 0);
 
 	/* Check if it is a read of Trace section */
 	if (!status && !ul_trace_sec_beg) {
 		status = dev_get_symbol(dev_context->dev_obj,
 					DSP_TRACESEC_BEG, &ul_trace_sec_beg);
 	}
-	DBC_ASSERT(ul_trace_sec_beg != 0);
 
 	if (!status && !ul_trace_sec_end) {
 		status = dev_get_symbol(dev_context->dev_obj,
 					DSP_TRACESEC_END, &ul_trace_sec_end);
 	}
-	DBC_ASSERT(ul_trace_sec_end != 0);
 
 	if (!status) {
 		if ((dsp_addr <= ul_trace_sec_end) &&
@@ -105,19 +99,16 @@
 			status = dev_get_symbol(dev_context->dev_obj,
 						DYNEXTBASE, &ul_dyn_ext_base);
 		}
-		DBC_ASSERT(ul_dyn_ext_base != 0);
 
 		if (!status) {
 			status = dev_get_symbol(dev_context->dev_obj,
 						EXTBASE, &ul_ext_base);
 		}
-		DBC_ASSERT(ul_ext_base != 0);
 
 		if (!status) {
 			status = dev_get_symbol(dev_context->dev_obj,
 						EXTEND, &ul_ext_end);
 		}
-		DBC_ASSERT(ul_ext_end != 0);
 
 		/* Trace buffer is right after the shm SEG0,
 		 *  so set the base address to SHMBASE */
@@ -126,8 +117,6 @@
 			ul_ext_end = ul_trace_sec_end;
 		}
 
-		DBC_ASSERT(ul_ext_end != 0);
-		DBC_ASSERT(ul_ext_end > ul_ext_base);
 
 		if (ul_ext_end < ul_ext_base)
 			status = -EPERM;
@@ -135,7 +124,6 @@
 		if (!status) {
 			ul_tlb_base_virt =
 			    dev_context->atlb_entry[0].dsp_va * DSPWORDSIZE;
-			DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt);
 			dw_ext_prog_virt_mem =
 			    dev_context->atlb_entry[0].gpp_va;
 
@@ -271,7 +259,6 @@
 			/* Get SHM_BEG  EXT_BEG and EXT_END. */
 			ret = dev_get_symbol(dev_context->dev_obj,
 					     SHMBASENAME, &ul_shm_base_virt);
-		DBC_ASSERT(ul_shm_base_virt != 0);
 		if (dynamic_load) {
 			if (!ret) {
 				if (symbols_reloaded)
@@ -280,7 +267,6 @@
 					    (dev_context->dev_obj, DYNEXTBASE,
 					     &ul_ext_base);
 			}
-			DBC_ASSERT(ul_ext_base != 0);
 			if (!ret) {
 				/* DR  OMAPS00013235 : DLModules array may be
 				 * in EXTMEM. It is expected that DYNEXTMEM and
@@ -299,7 +285,6 @@
 					    dev_get_symbol
 					    (dev_context->dev_obj, EXTBASE,
 					     &ul_ext_base);
-				DBC_ASSERT(ul_ext_base != 0);
 				if (!ret)
 					ret =
 					    dev_get_symbol
@@ -312,15 +297,12 @@
 		if (trace_load)
 			ul_ext_base = ul_shm_base_virt;
 
-		DBC_ASSERT(ul_ext_end != 0);
-		DBC_ASSERT(ul_ext_end > ul_ext_base);
 		if (ul_ext_end < ul_ext_base)
 			ret = -EPERM;
 
 		if (!ret) {
 			ul_tlb_base_virt =
 			    dev_context->atlb_entry[0].dsp_va * DSPWORDSIZE;
-			DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt);
 
 			if (symbols_reloaded) {
 				ret = dev_get_symbol
diff --git a/drivers/staging/tidspbridge/core/wdt.c b/drivers/staging/tidspbridge/core/wdt.c
index 2126f59..70055c8 100644
--- a/drivers/staging/tidspbridge/core/wdt.c
+++ b/drivers/staging/tidspbridge/core/wdt.c
@@ -25,8 +25,6 @@
 #include <dspbridge/host_os.h>
 
 
-#ifdef CONFIG_TIDSPBRIDGE_WDT3
-
 #define OMAP34XX_WDT3_BASE 		(L4_PER_34XX_BASE + 0x30000)
 
 static struct dsp_wdt_setting dsp_wdt;
@@ -84,7 +82,7 @@
 void dsp_wdt_sm_set(void *data)
 {
 	dsp_wdt.sm_wdt = data;
-	dsp_wdt.sm_wdt->wdt_overflow = CONFIG_TIDSPBRIDGE_WDT_TIMEOUT;
+	dsp_wdt.sm_wdt->wdt_overflow = 5;	/* in seconds */
 }
 
 
@@ -128,23 +126,3 @@
 		clk_disable(dsp_wdt.fclk);
 	}
 }
-
-#else
-void dsp_wdt_enable(bool enable)
-{
-}
-
-void dsp_wdt_sm_set(void *data)
-{
-}
-
-int dsp_wdt_init(void)
-{
-	return 0;
-}
-
-void dsp_wdt_exit(void)
-{
-}
-#endif
-
diff --git a/drivers/staging/tidspbridge/gen/gh.c b/drivers/staging/tidspbridge/gen/gh.c
index 60aa7b0..25eaef7 100644
--- a/drivers/staging/tidspbridge/gen/gh.c
+++ b/drivers/staging/tidspbridge/gen/gh.c
@@ -95,15 +95,6 @@
 }
 
 /*
- *  ======== gh_exit ========
- */
-
-void gh_exit(void)
-{
-	/* Do nothing */
-}
-
-/*
  *  ======== gh_find ========
  */
 
@@ -122,15 +113,6 @@
 }
 
 /*
- *  ======== gh_init ========
- */
-
-void gh_init(void)
-{
-	/* Do nothing */
-}
-
-/*
  *  ======== gh_insert ========
  */
 
diff --git a/drivers/staging/tidspbridge/gen/uuidutil.c b/drivers/staging/tidspbridge/gen/uuidutil.c
index ff6ebad..b44656c 100644
--- a/drivers/staging/tidspbridge/gen/uuidutil.c
+++ b/drivers/staging/tidspbridge/gen/uuidutil.c
@@ -23,9 +23,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- This */
 #include <dspbridge/uuidutil.h>
 
@@ -41,8 +38,6 @@
 {
 	s32 i;			/* return result from snprintf. */
 
-	DBC_REQUIRE(uuid_obj && sz_uuid);
-
 	i = snprintf(sz_uuid, size,
 		     "%.8X_%.4X_%.4X_%.2X%.2X_%.2X%.2X%.2X%.2X%.2X%.2X",
 		     uuid_obj->data1, uuid_obj->data2, uuid_obj->data3,
@@ -50,8 +45,6 @@
 		     uuid_obj->data6[0], uuid_obj->data6[1],
 		     uuid_obj->data6[2], uuid_obj->data6[3],
 		     uuid_obj->data6[4], uuid_obj->data6[5]);
-
-	DBC_ENSURE(i != -1);
 }
 
 static s32 uuid_hex_to_bin(char *buf, s32 len)
diff --git a/drivers/staging/tidspbridge/include/dspbridge/_chnl_sm.h b/drivers/staging/tidspbridge/include/dspbridge/_chnl_sm.h
index 6e7ab4f..cc95a18 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/_chnl_sm.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/_chnl_sm.h
@@ -99,14 +99,10 @@
 	struct opp_rqst_struct opp_request;
 	/* load monitor information structure */
 	struct load_mon_struct load_mon_info;
-#ifdef CONFIG_TIDSPBRIDGE_WDT3
 	/* Flag for WDT enable/disable F/I clocks */
 	u32 wdt_setclocks;
 	u32 wdt_overflow;	/* WDT overflow time */
 	char dummy[176];	/* padding to 256 byte boundary */
-#else
-	char dummy[184];	/* padding to 256 byte boundary */
-#endif
 	u32 shm_dbg_var[64];	/* shared memory debug variables */
 };
 
diff --git a/drivers/staging/tidspbridge/include/dspbridge/chnl.h b/drivers/staging/tidspbridge/include/dspbridge/chnl.h
index 92f6a13..9b018b1 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/chnl.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/chnl.h
@@ -48,7 +48,6 @@
  *      -ECHRNG:     This manager cannot handle this many channels.
  *      -EEXIST:       Channel manager already exists for this device.
  *  Requires:
- *      chnl_init(void) called.
  *      channel_mgr != NULL.
  *      mgr_attrts != NULL.
  *  Ensures:
@@ -70,7 +69,6 @@
  *      0:            Success.
  *      -EFAULT:        hchnl_mgr was invalid.
  *  Requires:
- *      chnl_init(void) called.
  *  Ensures:
  *      0:            Cancels I/O on each open channel.
  *                          Closes each open channel.
@@ -79,31 +77,4 @@
  */
 extern int chnl_destroy(struct chnl_mgr *hchnl_mgr);
 
-/*
- *  ======== chnl_exit ========
- *  Purpose:
- *      Discontinue usage of the CHNL module.
- *  Parameters:
- *  Returns:
- *  Requires:
- *      chnl_init(void) previously called.
- *  Ensures:
- *      Resources, if any acquired in chnl_init(void), are freed when the last
- *      client of CHNL calls chnl_exit(void).
- */
-extern void chnl_exit(void);
-
-/*
- *  ======== chnl_init ========
- *  Purpose:
- *      Initialize the CHNL module's private state.
- *  Parameters:
- *  Returns:
- *      TRUE if initialized; FALSE if error occurred.
- *  Requires:
- *  Ensures:
- *      A requirement for each of the other public CHNL functions.
- */
-extern bool chnl_init(void);
-
 #endif /* CHNL_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/cmm.h b/drivers/staging/tidspbridge/include/dspbridge/cmm.h
index aff2205..c66bcf7 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/cmm.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/cmm.h
@@ -79,7 +79,6 @@
  *      -EPERM:      Failed to initialize critical sect sync object.
  *
  *  Requires:
- *      cmm_init(void) called.
  *      ph_cmm_mgr != NULL.
  *      mgr_attrts->min_block_size >= 4 bytes.
  *  Ensures:
@@ -111,20 +110,6 @@
 extern int cmm_destroy(struct cmm_object *hcmm_mgr, bool force);
 
 /*
- *  ======== cmm_exit ========
- *  Purpose:
- *     Discontinue usage of module. Cleanup CMM module if CMM cRef reaches zero.
- *  Parameters:
- *     n/a
- *  Returns:
- *     n/a
- *  Requires:
- *     CMM is initialized.
- *  Ensures:
- */
-extern void cmm_exit(void);
-
-/*
  *  ======== cmm_free_buf ========
  *  Purpose:
  *      Free the given buffer.
@@ -185,19 +170,6 @@
 			       struct cmm_info *cmm_info_obj);
 
 /*
- *  ======== cmm_init ========
- *  Purpose:
- *      Initializes private state of CMM module.
- *  Parameters:
- *  Returns:
- *      TRUE if initialized; FALSE if error occurred.
- *  Requires:
- *  Ensures:
- *      CMM initialized.
- */
-extern bool cmm_init(void);
-
-/*
  *  ======== cmm_register_gppsm_seg ========
  *  Purpose:
  *      Register a block of SM with the CMM.
@@ -333,7 +305,6 @@
  *      0:        Success.
  *      -EFAULT:    Bad translator handle.
  *  Requires:
- *      (refs > 0)
  *      (paddr != NULL)
  *      (ul_size > 0)
  *  Ensures:
@@ -355,7 +326,6 @@
  *  Returns:
  *     Valid address on success, else NULL.
  *  Requires:
- *      refs > 0
  *      paddr != NULL
  *      xtype >= CMM_VA2PA) && (xtype <= CMM_DSPPA2PA)
  *  Ensures:
diff --git a/drivers/staging/tidspbridge/include/dspbridge/cod.h b/drivers/staging/tidspbridge/include/dspbridge/cod.h
index cb684c1..ba2005d 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/cod.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/cod.h
@@ -100,21 +100,6 @@
 extern void cod_delete(struct cod_manager *cod_mgr_obj);
 
 /*
- *  ======== cod_exit ========
- *  Purpose:
- *      Discontinue usage of the COD module.
- *  Parameters:
- *      None.
- *  Returns:
- *      None.
- *  Requires:
- *      COD initialized.
- *  Ensures:
- *      Resources acquired in cod_init(void) are freed.
- */
-extern void cod_exit(void);
-
-/*
  *  ======== cod_get_base_lib ========
  *  Purpose:
  *      Get handle to the base image DBL library.
@@ -243,20 +228,6 @@
 				    char *str_sym, u32 * pul_value);
 
 /*
- *  ======== cod_init ========
- *  Purpose:
- *      Initialize the COD module's private state.
- *  Parameters:
- *      None.
- *  Returns:
- *      TRUE if initialized; FALSE if error occurred.
- *  Requires:
- *  Ensures:
- *      A requirement for each of the other public COD functions.
- */
-extern bool cod_init(void);
-
-/*
  *  ======== cod_load_base ========
  *  Purpose:
  *      Load the initial program image, optionally with command-line arguments,
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dbc.h b/drivers/staging/tidspbridge/include/dspbridge/dbc.h
deleted file mode 100644
index 463760f..0000000
--- a/drivers/staging/tidspbridge/include/dspbridge/dbc.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * dbc.h
- *
- * DSP-BIOS Bridge driver support functions for TI OMAP processors.
- *
- * "Design by Contract" programming macros.
- *
- * Notes:
- *   Requires that the GT->ERROR function has been defaulted to a valid
- *   error handler for the given execution environment.
- *
- *   Does not require that GT_init() be called.
- *
- * Copyright (C) 2008 Texas Instruments, Inc.
- *
- * This package 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.
- *
- * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#ifndef DBC_
-#define DBC_
-
-/* Assertion Macros: */
-#ifdef CONFIG_TIDSPBRIDGE_DEBUG
-
-#define DBC_ASSERT(exp) \
-    if (!(exp)) \
-	pr_err("%s, line %d: Assertion (" #exp ") failed.\n", \
-	__FILE__, __LINE__)
-#define DBC_REQUIRE DBC_ASSERT	/* Function Precondition. */
-#define DBC_ENSURE  DBC_ASSERT	/* Function Postcondition. */
-
-#else
-
-#define DBC_ASSERT(exp) {}
-#define DBC_REQUIRE(exp) {}
-#define DBC_ENSURE(exp) {}
-
-#endif /* DEBUG */
-
-#endif /* DBC_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dev.h b/drivers/staging/tidspbridge/include/dspbridge/dev.h
index f92b4be..fa2d79e 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/dev.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/dev.h
@@ -478,33 +478,6 @@
 				      **phbridge_context);
 
 /*
- *  ======== dev_exit ========
- *  Purpose:
- *      Decrement reference count, and free resources when reference count is
- *      0.
- *  Parameters:
- *  Returns:
- *  Requires:
- *      DEV is initialized.
- *  Ensures:
- *      When reference count == 0, DEV's private resources are freed.
- */
-extern void dev_exit(void);
-
-/*
- *  ======== dev_init ========
- *  Purpose:
- *      Initialize DEV's private state, keeping a reference count on each call.
- *  Parameters:
- *  Returns:
- *      TRUE if initialized; FALSE if error occurred.
- *  Requires:
- *  Ensures:
- *      TRUE: A requirement for the other public DEV functions.
- */
-extern bool dev_init(void);
-
-/*
  *  ======== dev_insert_proc_object ========
  *  Purpose:
  *      Inserts the Processor Object into the List of PROC Objects
diff --git a/drivers/staging/tidspbridge/include/dspbridge/disp.h b/drivers/staging/tidspbridge/include/dspbridge/disp.h
index 5dfdc8c..39d3cea 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/disp.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/disp.h
@@ -53,7 +53,6 @@
  *      -ENOMEM:            Insufficient memory for requested resources.
  *      -EPERM:              Unable to create dispatcher.
  *  Requires:
- *      disp_init(void) called.
  *      disp_attrs != NULL.
  *      hdev_obj != NULL.
  *      dispatch_obj != NULL.
@@ -73,7 +72,6 @@
  *      disp_obj:  Node Dispatcher object.
  *  Returns:
  *  Requires:
- *      disp_init(void) called.
  *      Valid disp_obj.
  *  Ensures:
  *      disp_obj is invalid.
@@ -81,31 +79,6 @@
 extern void disp_delete(struct disp_object *disp_obj);
 
 /*
- *  ======== disp_exit ========
- *  Discontinue usage of DISP module.
- *
- *  Parameters:
- *  Returns:
- *  Requires:
- *      disp_init(void) previously called.
- *  Ensures:
- *      Any resources acquired in disp_init(void) will be freed when last DISP
- *      client calls disp_exit(void).
- */
-extern void disp_exit(void);
-
-/*
- *  ======== disp_init ========
- *  Initialize the DISP module.
- *
- *  Parameters:
- *  Returns:
- *      TRUE if initialization succeeded, FALSE otherwise.
- *  Ensures:
- */
-extern bool disp_init(void);
-
-/*
  *  ======== disp_node_change_priority ========
  *  Change the priority of a node currently running on the target.
  *
@@ -120,7 +93,6 @@
  *      0:                Success.
  *      -ETIME:           A timeout occurred before the DSP responded.
  *  Requires:
- *      disp_init(void) called.
  *      Valid disp_obj.
  *      hnode != NULL.
  *  Ensures:
@@ -148,7 +120,6 @@
  *      -ETIME:   A timeout occurred before the DSP responded.
  *      -EPERM:      A failure occurred, unable to create node.
  *  Requires:
- *      disp_init(void) called.
  *      Valid disp_obj.
  *      pargs != NULL.
  *      hnode != NULL.
@@ -178,7 +149,6 @@
  *      0:        Success.
  *      -ETIME:   A timeout occurred before the DSP responded.
  *  Requires:
- *      disp_init(void) called.
  *      Valid disp_obj.
  *      hnode != NULL.
  *  Ensures:
@@ -204,7 +174,6 @@
  *      0:        Success.
  *      -ETIME:   A timeout occurred before the DSP responded.
  *  Requires:
- *      disp_init(void) called.
  *      Valid disp_obj.
  *      hnode != NULL.
  *  Ensures:
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dmm.h b/drivers/staging/tidspbridge/include/dspbridge/dmm.h
index 6c58335..c3487be 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/dmm.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/dmm.h
@@ -61,10 +61,6 @@
 			     struct dev_object *hdev_obj,
 			     const struct dmm_mgrattrs *mgr_attrts);
 
-extern bool dmm_init(void);
-
-extern void dmm_exit(void);
-
 extern int dmm_create_tables(struct dmm_object *dmm_mgr,
 				    u32 addr, u32 size);
 
diff --git a/drivers/staging/tidspbridge/include/dspbridge/drv.h b/drivers/staging/tidspbridge/include/dspbridge/drv.h
index 9cdbd95..b0c7708 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/drv.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/drv.h
@@ -199,17 +199,6 @@
 extern int drv_destroy(struct drv_object *driver_obj);
 
 /*
- *  ======== drv_exit ========
- *  Purpose:
- *      Exit the DRV module, freeing any modules initialized in drv_init.
- *  Parameters:
- *  Returns:
- *  Requires:
- *  Ensures:
- */
-extern void drv_exit(void);
-
-/*
  *  ======== drv_get_first_dev_object ========
  *  Purpose:
  *      Returns the Ptr to the FirstDev Object in the List
@@ -294,18 +283,6 @@
 extern u32 drv_get_next_dev_extension(u32 dev_extension);
 
 /*
- *  ======== drv_init ========
- *  Purpose:
- *      Initialize the DRV module.
- *  Parameters:
- *  Returns:
- *      TRUE if success; FALSE otherwise.
- *  Requires:
- *  Ensures:
- */
-extern int drv_init(void);
-
-/*
  *  ======== drv_insert_dev_object ========
  *  Purpose:
  *      Insert a DeviceObject into the list of Driver object.
diff --git a/drivers/staging/tidspbridge/include/dspbridge/gh.h b/drivers/staging/tidspbridge/include/dspbridge/gh.h
index 9de291d..da85079 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/gh.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/gh.h
@@ -23,9 +23,7 @@
 				       bool(*match) (void *, void *),
 				       void (*delete) (void *));
 extern void gh_delete(struct gh_t_hash_tab *hash_tab);
-extern void gh_exit(void);
 extern void *gh_find(struct gh_t_hash_tab *hash_tab, void *key);
-extern void gh_init(void);
 extern void *gh_insert(struct gh_t_hash_tab *hash_tab, void *key, void *value);
 #ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
 void gh_iterate(struct gh_t_hash_tab *hash_tab,
diff --git a/drivers/staging/tidspbridge/include/dspbridge/io.h b/drivers/staging/tidspbridge/include/dspbridge/io.h
index 500bbd7..7505718 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/io.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/io.h
@@ -55,7 +55,6 @@
  *      -EINVAL: Invalid DSP word size (must be > 0).
  *               Invalid base address for DSP communications.
  *  Requires:
- *      io_init(void) called.
  *      io_man != NULL.
  *      mgr_attrts != NULL.
  *  Ensures:
@@ -74,36 +73,8 @@
  *      0:        Success.
  *      -EFAULT:    hio_mgr was invalid.
  *  Requires:
- *      io_init(void) called.
  *  Ensures:
  */
 extern int io_destroy(struct io_mgr *hio_mgr);
 
-/*
- *  ======== io_exit ========
- *  Purpose:
- *      Discontinue usage of the IO module.
- *  Parameters:
- *  Returns:
- *  Requires:
- *      io_init(void) previously called.
- *  Ensures:
- *      Resources, if any acquired in io_init(void), are freed when the last
- *      client of IO calls io_exit(void).
- */
-extern void io_exit(void);
-
-/*
- *  ======== io_init ========
- *  Purpose:
- *      Initialize the IO module's private state.
- *  Parameters:
- *  Returns:
- *      TRUE if initialized; FALSE if error occurred.
- *  Requires:
- *  Ensures:
- *      A requirement for each of the other public CHNL functions.
- */
-extern bool io_init(void);
-
 #endif /* CHNL_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/io_sm.h b/drivers/staging/tidspbridge/include/dspbridge/io_sm.h
index a054dad..903ff12 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/io_sm.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/io_sm.h
@@ -154,8 +154,6 @@
 
 void dump_dl_modules(struct bridge_dev_context *bridge_context);
 
-#endif
-#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) || defined(CONFIG_TIDSPBRIDGE_DEBUG)
 void print_dsp_debug_trace(struct io_mgr *hio_mgr);
 #endif
 
diff --git a/drivers/staging/tidspbridge/include/dspbridge/msg.h b/drivers/staging/tidspbridge/include/dspbridge/msg.h
index 95778bc..2c8712c 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/msg.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/msg.h
@@ -34,7 +34,6 @@
  *      msg_callback:        Called whenever an RMS_EXIT message is received.
  *  Returns:
  *  Requires:
- *      msg_mod_init(void) called.
  *      msg_man != NULL.
  *      hdev_obj != NULL.
  *      msg_callback != NULL.
@@ -52,35 +51,9 @@
  *      hmsg_mgr:            Handle returned from msg_create().
  *  Returns:
  *  Requires:
- *      msg_mod_init(void) called.
  *      Valid hmsg_mgr.
  *  Ensures:
  */
 extern void msg_delete(struct msg_mgr *hmsg_mgr);
 
-/*
- *  ======== msg_exit ========
- *  Purpose:
- *      Discontinue usage of msg_ctrl module.
- *  Parameters:
- *  Returns:
- *  Requires:
- *      msg_mod_init(void) successfully called before.
- *  Ensures:
- *      Any resources acquired in msg_mod_init(void) will be freed when last
- *      msg_ctrl client calls msg_exit(void).
- */
-extern void msg_exit(void);
-
-/*
- *  ======== msg_mod_init ========
- *  Purpose:
- *      Initialize the msg_ctrl module.
- *  Parameters:
- *  Returns:
- *      TRUE if initialization succeeded, FALSE otherwise.
- *  Ensures:
- */
-extern bool msg_mod_init(void);
-
 #endif /* MSG_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/nldr.h b/drivers/staging/tidspbridge/include/dspbridge/nldr.h
index d9653ee..c5e48ca 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/nldr.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/nldr.h
@@ -36,7 +36,6 @@
 			      const struct nldr_attrs *pattrs);
 
 extern void nldr_delete(struct nldr_object *nldr_obj);
-extern void nldr_exit(void);
 
 extern int nldr_get_fxn_addr(struct nldr_nodeobject *nldr_node_obj,
 				    char *str_fxn, u32 * addr);
@@ -44,7 +43,6 @@
 extern int nldr_get_rmm_manager(struct nldr_object *nldr,
 				       struct rmm_target_obj **rmm_mgr);
 
-extern bool nldr_init(void);
 extern int nldr_load(struct nldr_nodeobject *nldr_node_obj,
 			    enum nldr_phase phase);
 extern int nldr_unload(struct nldr_nodeobject *nldr_node_obj,
diff --git a/drivers/staging/tidspbridge/include/dspbridge/nldrdefs.h b/drivers/staging/tidspbridge/include/dspbridge/nldrdefs.h
index ee3a85f..7e3c7f5 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/nldrdefs.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/nldrdefs.h
@@ -119,7 +119,6 @@
  *      0:        Success.
  *      -ENOMEM:    Insufficient memory on GPP.
  *  Requires:
- *      nldr_init(void) called.
  *      Valid nldr_obj.
  *      node_props != NULL.
  *      nldr_nodeobj != NULL.
@@ -148,7 +147,6 @@
  *      0:        Success;
  *      -ENOMEM:    Insufficient memory for requested resources.
  *  Requires:
- *      nldr_init(void) called.
  *      nldr != NULL.
  *      hdev_obj != NULL.
  *	pattrs != NULL.
@@ -168,7 +166,6 @@
  *      nldr_obj:          Node manager object.
  *  Returns:
  *  Requires:
- *      nldr_init(void) called.
  *      Valid nldr_obj.
  *  Ensures:
  *	nldr_obj invalid
@@ -176,20 +173,6 @@
 typedef void (*nldr_deletefxn) (struct nldr_object *nldr_obj);
 
 /*
- *  ======== nldr_exit ========
- *  Discontinue usage of NLDR module.
- *
- *  Parameters:
- *  Returns:
- *  Requires:
- *      nldr_init(void) successfully called before.
- *  Ensures:
- *      Any resources acquired in nldr_init(void) will be freed when last NLDR
- *      client calls nldr_exit(void).
- */
-typedef void (*nldr_exitfxn) (void);
-
-/*
  *  ======== NLDR_Free ========
  *  Free resources allocated in nldr_allocate.
  *
@@ -197,7 +180,6 @@
  *      nldr_node_obj:      Handle returned from nldr_allocate().
  *  Returns:
  *  Requires:
- *      nldr_init(void) called.
  *      Valid nldr_node_obj.
  *  Ensures:
  */
@@ -216,7 +198,6 @@
  *      0:        Success.
  *      -ESPIPE:    Address of function not found.
  *  Requires:
- *      nldr_init(void) called.
  *      Valid nldr_node_obj.
  *      addr != NULL;
  *      str_fxn != NULL;
@@ -227,17 +208,6 @@
 					 char *str_fxn, u32 * addr);
 
 /*
- *  ======== nldr_init ========
- *  Initialize the NLDR module.
- *
- *  Parameters:
- *  Returns:
- *      TRUE if initialization succeeded, FALSE otherwise.
- *  Ensures:
- */
-typedef bool(*nldr_initfxn) (void);
-
-/*
  *  ======== nldr_load ========
  *  Load create, delete, or execute phase function of a node on the DSP.
  *
@@ -251,7 +221,6 @@
  *                              is already in use.
  *      -EILSEQ:           Failure in dynamic loader library.
  *  Requires:
- *      nldr_init(void) called.
  *      Valid nldr_node_obj.
  *  Ensures:
  */
@@ -269,7 +238,6 @@
  *      0:        Success.
  *      -ENOMEM:    Insufficient memory on GPP.
  *  Requires:
- *      nldr_init(void) called.
  *      Valid nldr_node_obj.
  *  Ensures:
  */
@@ -283,9 +251,7 @@
 	nldr_allocatefxn allocate;
 	nldr_createfxn create;
 	nldr_deletefxn delete;
-	nldr_exitfxn exit;
 	nldr_getfxnaddrfxn get_fxn_addr;
-	nldr_initfxn init;
 	nldr_loadfxn load;
 	nldr_unloadfxn unload;
 };
diff --git a/drivers/staging/tidspbridge/include/dspbridge/node.h b/drivers/staging/tidspbridge/include/dspbridge/node.h
index 16371d8..7397b7a 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/node.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/node.h
@@ -47,7 +47,6 @@
  *      -EPERM:          A failure occurred, unable to allocate node.
  *      -EBADR:    Proccessor is not in the running state.
  *  Requires:
- *      node_init(void) called.
  *      hprocessor != NULL.
  *      node_uuid != NULL.
  *      noderes != NULL.
@@ -81,7 +80,6 @@
  *      -EPERM:      General Failure.
  *      -EINVAL:      Invalid Size.
  *  Requires:
- *      node_init(void) called.
  *      pbuffer != NULL.
  *  Ensures:
  */
@@ -106,7 +104,6 @@
  *                          or NODE_RUNNING state.
  *      -ETIME:       A timeout occurred before the DSP responded.
  *  Requires:
- *      node_init(void) called.
  *  Ensures:
  *      0 && (Node's current priority == prio)
  */
@@ -157,7 +154,6 @@
  *                              Device node to device node, or device node to
  *                              GPP), the two nodes are on different DSPs.
  *  Requires:
- *      node_init(void) called.
  *  Ensures:
  */
 extern int node_connect(struct node_object *node1,
@@ -185,7 +181,6 @@
  *      -ETIME:       A timeout occurred before the DSP responded.
  *      -EPERM:          A failure occurred, unable to create node.
  *  Requires:
- *      node_init(void) called.
  *  Ensures:
  */
 extern int node_create(struct node_object *hnode);
@@ -206,7 +201,6 @@
  *      -ENOMEM:    Insufficient memory for requested resources.
  *      -EPERM:      General failure.
  *  Requires:
- *      node_init(void) called.
  *      node_man != NULL.
  *      hdev_obj != NULL.
  *  Ensures:
@@ -234,7 +228,6 @@
  *      -EPERM:          A failure occurred in deleting the node.
  *      -ESPIPE:        Delete function not found in the COFF file.
  *  Requires:
- *      node_init(void) called.
  *  Ensures:
  *      0:            hnode is invalid.
  */
@@ -250,7 +243,6 @@
  *  Returns:
  *      0:        Success.
  *  Requires:
- *      node_init(void) called.
  *      Valid hnode_mgr.
  *  Ensures:
  */
@@ -287,20 +279,6 @@
 				  u32 *pu_allocated);
 
 /*
- *  ======== node_exit ========
- *  Purpose:
- *      Discontinue usage of NODE module.
- *  Parameters:
- *  Returns:
- *  Requires:
- *      node_init(void) successfully called before.
- *  Ensures:
- *      Any resources acquired in node_init(void) will be freed when last NODE
- *      client calls node_exit(void).
- */
-extern void node_exit(void);
-
-/*
  *  ======== node_free_msg_buf ========
  *  Purpose:
  *      Free a message buffer previously allocated with node_alloc_msg_buf.
@@ -313,7 +291,6 @@
  *      -EFAULT:    Invalid node handle.
  *      -EPERM:      Failure to free the buffer.
  *  Requires:
- *      node_init(void) called.
  *      pbuffer != NULL.
  *  Ensures:
  */
@@ -336,7 +313,6 @@
  *      0:        Success.
  *      -EFAULT:    Invalid hnode.
  *  Requires:
- *      node_init(void) called.
  *      pattr != NULL.
  *  Ensures:
  *      0:        *pattrs contains the node's current attributes.
@@ -363,7 +339,6 @@
  *              Error occurred while trying to retrieve a message.
  *      -ETIME:   Timeout occurred and no message is available.
  *  Requires:
- *      node_init(void) called.
  *      message != NULL.
  *  Ensures:
  */
@@ -386,17 +361,6 @@
 				    struct nldr_object **nldr_ovlyobj);
 
 /*
- *  ======== node_init ========
- *  Purpose:
- *      Initialize the NODE module.
- *  Parameters:
- *  Returns:
- *      TRUE if initialization succeeded, FALSE otherwise.
- *  Ensures:
- */
-extern bool node_init(void);
-
-/*
  *  ======== node_on_exit ========
  *  Purpose:
  *      Gets called when RMS_EXIT is received for a node. PROC needs to pass
@@ -425,7 +389,6 @@
  *      -ETIME:       A timeout occurred before the DSP responded.
  *      DSP_EWRONGSTSATE:   Node is not in NODE_RUNNING state.
  *  Requires:
- *      node_init(void) called.
  *  Ensures:
  */
 extern int node_pause(struct node_object *hnode);
@@ -449,7 +412,6 @@
  *      -ETIME:       Timeout occurred before message could be set.
  *      -EBADR:    Node is in invalid state for sending messages.
  *  Requires:
- *      node_init(void) called.
  *      pmsg != NULL.
  *  Ensures:
  */
@@ -473,7 +435,6 @@
  *      -ENOSYS:   Notification type specified by notify_type is not
  *                      supported.
  *  Requires:
- *      node_init(void) called.
  *      hnotification != NULL.
  *  Ensures:
  */
@@ -500,7 +461,6 @@
  *      DSP_EWRONGSTSATE:   Node is not in NODE_PAUSED or NODE_CREATED state.
  *      -ESPIPE:        Execute function not found in the COFF file.
  *  Requires:
- *      node_init(void) called.
  *  Ensures:
  */
 extern int node_run(struct node_object *hnode);
@@ -523,7 +483,6 @@
  *              Unable to terminate the node.
  *      -EBADR:    Operation not valid for the current node state.
  *  Requires:
- *      node_init(void) called.
  *      pstatus != NULL.
  *  Ensures:
  */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/nodepriv.h b/drivers/staging/tidspbridge/include/dspbridge/nodepriv.h
index 9c1e067..d5b54bb 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/nodepriv.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/nodepriv.h
@@ -96,7 +96,6 @@
  *      -EINVAL:     The node's stream corresponding to index and dir
  *                      is not a stream to or from the host.
  *  Requires:
- *      node_init(void) called.
  *      Valid dir.
  *      chan_id != NULL.
  *  Ensures:
diff --git a/drivers/staging/tidspbridge/include/dspbridge/proc.h b/drivers/staging/tidspbridge/include/dspbridge/proc.h
index f00dffd..a82380e 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/proc.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/proc.h
@@ -189,20 +189,6 @@
 					 u32 resource_info_size);
 
 /*
- *  ======== proc_exit ========
- *  Purpose:
- *      Decrement reference count, and free resources when reference count is
- *      0.
- *  Parameters:
- *  Returns:
- *  Requires:
- *      PROC is initialized.
- *  Ensures:
- *      When reference count == 0, PROC's private resources are freed.
- */
-extern void proc_exit(void);
-
-/*
  * ======== proc_get_dev_object =========
  *  Purpose:
  *      Returns the DEV Hanlde for a given Processor handle
@@ -223,20 +209,6 @@
 				      struct dev_object **device_obj);
 
 /*
- *  ======== proc_init ========
- *  Purpose:
- *      Initialize PROC's private state, keeping a reference count on each
- *      call.
- *  Parameters:
- *  Returns:
- *      TRUE if initialized; FALSE if error occurred.
- *  Requires:
- *  Ensures:
- *      TRUE: A requirement for the other public PROC functions.
- */
-extern bool proc_init(void);
-
-/*
  *  ======== proc_get_state ========
  *  Purpose:
  *      Report the state of the specified DSP processor.
diff --git a/drivers/staging/tidspbridge/include/dspbridge/rmm.h b/drivers/staging/tidspbridge/include/dspbridge/rmm.h
index baea536..f7a4dc8 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/rmm.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/rmm.h
@@ -115,18 +115,6 @@
 extern void rmm_delete(struct rmm_target_obj *target);
 
 /*
- *  ======== rmm_exit ========
- *  Exit the RMM module
- *
- *  Parameters:
- *  Returns:
- *  Requires:
- *      rmm_init successfully called.
- *  Ensures:
- */
-extern void rmm_exit(void);
-
-/*
  *  ======== rmm_free ========
  *  Free or unreserve memory allocated through rmm_alloc().
  *
@@ -148,19 +136,6 @@
 		     u32 size, bool reserved);
 
 /*
- *  ======== rmm_init ========
- *  Initialize the RMM module
- *
- *  Parameters:
- *  Returns:
- *      TRUE:   Success.
- *      FALSE:  Failure.
- *  Requires:
- *  Ensures:
- */
-extern bool rmm_init(void);
-
-/*
  *  ======== rmm_stat ========
  *  Obtain  memory segment status
  *
diff --git a/drivers/staging/tidspbridge/include/dspbridge/strm.h b/drivers/staging/tidspbridge/include/dspbridge/strm.h
index 613fe53..dacf0c2 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/strm.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/strm.h
@@ -40,7 +40,6 @@
  *      -EPERM:      Failure occurred, unable to allocate buffers.
  *      -EINVAL:      usize must be > 0 bytes.
  *  Requires:
- *      strm_init(void) called.
  *      ap_buffer != NULL.
  *  Ensures:
  */
@@ -63,7 +62,6 @@
  *                      been reclaimed.
  *      -EPERM:      Failure to close stream.
  *  Requires:
- *      strm_init(void) called.
  *  Ensures:
  */
 extern int strm_close(struct strm_res_object *strmres,
@@ -83,7 +81,6 @@
  *      -ENOMEM:    Insufficient memory for requested resources.
  *      -EPERM:      General failure.
  *  Requires:
- *      strm_init(void) called.
  *      strm_man != NULL.
  *      dev_obj != NULL.
  *  Ensures:
@@ -101,7 +98,6 @@
  *      strm_mgr_obj:       Handle to STRM manager object from strm_create.
  *  Returns:
  *  Requires:
- *      strm_init(void) called.
  *      Valid strm_mgr_obj.
  *  Ensures:
  *      strm_mgr_obj is not valid.
@@ -109,18 +105,6 @@
 extern void strm_delete(struct strm_mgr *strm_mgr_obj);
 
 /*
- *  ======== strm_exit ========
- *  Purpose:
- *      Discontinue usage of STRM module.
- *  Parameters:
- *  Returns:
- *  Requires:
- *      strm_init(void) successfully called before.
- *  Ensures:
- */
-extern void strm_exit(void);
-
-/*
  *  ======== strm_free_buffer ========
  *  Purpose:
  *      Free buffer(s) allocated with strm_allocate_buffer.
@@ -133,7 +117,6 @@
  *      -EFAULT:    Invalid stream handle.
  *      -EPERM:      Failure occurred, unable to free buffers.
  *  Requires:
- *      strm_init(void) called.
  *      ap_buffer != NULL.
  *  Ensures:
  */
@@ -156,7 +139,6 @@
  *      -EINVAL:          stream_info_size < sizeof(dsp_streaminfo).
  *      -EPERM:          Unable to get stream info.
  *  Requires:
- *      strm_init(void) called.
  *      stream_info != NULL.
  *  Ensures:
  */
@@ -184,24 +166,11 @@
  *      -ETIME:   A timeout occurred before the stream could be idled.
  *      -EPERM:      Unable to idle stream.
  *  Requires:
- *      strm_init(void) called.
  *  Ensures:
  */
 extern int strm_idle(struct strm_object *stream_obj, bool flush_data);
 
 /*
- *  ======== strm_init ========
- *  Purpose:
- *      Initialize the STRM module.
- *  Parameters:
- *  Returns:
- *      TRUE if initialization succeeded, FALSE otherwise.
- *  Requires:
- *  Ensures:
- */
-extern bool strm_init(void);
-
-/*
  *  ======== strm_issue ========
  *  Purpose:
  *      Send a buffer of data to a stream.
@@ -217,8 +186,7 @@
  *      -ENOSR:    The stream is full.
  *      -EPERM:          Failure occurred, unable to issue buffer.
  *  Requires:
- *      strm_init(void) called.
- *      pbuf != NULL.
+*      pbuf != NULL.
  *  Ensures:
  */
 extern int strm_issue(struct strm_object *stream_obj, u8 * pbuf,
@@ -244,7 +212,6 @@
  *              Unable to open stream.
  *      -EINVAL:     Invalid index.
  *  Requires:
- *      strm_init(void) called.
  *      strmres != NULL.
  *      pattr != NULL.
  *  Ensures:
@@ -275,7 +242,6 @@
  *                      retrieved.
  *      -EPERM:      Failure occurred, unable to reclaim buffer.
  *  Requires:
- *      strm_init(void) called.
  *      buf_ptr != NULL.
  *      nbytes != NULL.
  *      pdw_arg != NULL.
@@ -302,7 +268,6 @@
  *      -ENOSYS:   Notification type specified by notify_type is not
  *                      supported.
  *  Requires:
- *      strm_init(void) called.
  *      hnotification != NULL.
  *  Ensures:
  */
@@ -328,7 +293,6 @@
  *      -ETIME:   A timeout occurred before a stream became ready.
  *      -EPERM:      Failure occurred, unable to select a stream.
  *  Requires:
- *      strm_init(void) called.
  *      strm_tab != NULL.
  *      strms > 0.
  *      pmask != NULL.
diff --git a/drivers/staging/tidspbridge/pmgr/chnl.c b/drivers/staging/tidspbridge/pmgr/chnl.c
index 245de82..4bd8686 100644
--- a/drivers/staging/tidspbridge/pmgr/chnl.c
+++ b/drivers/staging/tidspbridge/pmgr/chnl.c
@@ -24,9 +24,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- OS Adaptation Layer */
 #include <dspbridge/sync.h>
 
@@ -41,9 +38,6 @@
 /*  ----------------------------------- This */
 #include <dspbridge/chnl.h>
 
-/*  ----------------------------------- Globals */
-static u32 refs;
-
 /*
  *  ======== chnl_create ========
  *  Purpose:
@@ -58,10 +52,6 @@
 	struct chnl_mgr *hchnl_mgr;
 	struct chnl_mgr_ *chnl_mgr_obj = NULL;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(channel_mgr != NULL);
-	DBC_REQUIRE(mgr_attrts != NULL);
-
 	*channel_mgr = NULL;
 
 	/* Validate args: */
@@ -99,8 +89,6 @@
 		}
 	}
 
-	DBC_ENSURE(status || chnl_mgr_obj);
-
 	return status;
 }
 
@@ -115,8 +103,6 @@
 	struct bridge_drv_interface *intf_fxns;
 	int status;
 
-	DBC_REQUIRE(refs > 0);
-
 	if (chnl_mgr_obj) {
 		intf_fxns = chnl_mgr_obj->intf_fxns;
 		/* Let Bridge channel module destroy the chnl_mgr: */
@@ -127,36 +113,3 @@
 
 	return status;
 }
-
-/*
- *  ======== chnl_exit ========
- *  Purpose:
- *      Discontinue usage of the CHNL module.
- */
-void chnl_exit(void)
-{
-	DBC_REQUIRE(refs > 0);
-
-	refs--;
-
-	DBC_ENSURE(refs >= 0);
-}
-
-/*
- *  ======== chnl_init ========
- *  Purpose:
- *      Initialize the CHNL module's private state.
- */
-bool chnl_init(void)
-{
-	bool ret = true;
-
-	DBC_REQUIRE(refs >= 0);
-
-	if (ret)
-		refs++;
-
-	DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
-
-	return ret;
-}
diff --git a/drivers/staging/tidspbridge/pmgr/cmm.c b/drivers/staging/tidspbridge/pmgr/cmm.c
index e6b2c89..4a800da 100644
--- a/drivers/staging/tidspbridge/pmgr/cmm.c
+++ b/drivers/staging/tidspbridge/pmgr/cmm.c
@@ -35,9 +35,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- OS Adaptation Layer */
 #include <dspbridge/sync.h>
 
@@ -134,9 +131,6 @@
 	u32 client_proc;	/* Process that allocated this mem block */
 };
 
-/*  ----------------------------------- Globals */
-static u32 refs;		/* module reference count */
-
 /*  ----------------------------------- Function Prototypes */
 static void add_to_free_list(struct cmm_allocator *allocator,
 			     struct cmm_mnode *pnode);
@@ -244,9 +238,6 @@
 	struct cmm_object *cmm_obj = NULL;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(ph_cmm_mgr != NULL);
-
 	*ph_cmm_mgr = NULL;
 	/* create, zero, and tag a cmm mgr object */
 	cmm_obj = kzalloc(sizeof(struct cmm_object), GFP_KERNEL);
@@ -256,8 +247,6 @@
 	if (mgr_attrts == NULL)
 		mgr_attrts = &cmm_dfltmgrattrs;	/* set defaults */
 
-	/* 4 bytes minimum */
-	DBC_ASSERT(mgr_attrts->min_block_size >= 4);
 	/* save away smallest block allocation for this cmm mgr */
 	cmm_obj->min_block_size = mgr_attrts->min_block_size;
 	cmm_obj->page_size = PAGE_SIZE;
@@ -283,7 +272,6 @@
 	s32 slot_seg;
 	struct cmm_mnode *node, *tmp;
 
-	DBC_REQUIRE(refs > 0);
 	if (!hcmm_mgr) {
 		status = -EFAULT;
 		return status;
@@ -326,19 +314,6 @@
 }
 
 /*
- *  ======== cmm_exit ========
- *  Purpose:
- *      Discontinue usage of module; free resources when reference count
- *      reaches 0.
- */
-void cmm_exit(void)
-{
-	DBC_REQUIRE(refs > 0);
-
-	refs--;
-}
-
-/*
  *  ======== cmm_free_buf ========
  *  Purpose:
  *      Free the given buffer.
@@ -351,9 +326,6 @@
 	struct cmm_allocator *allocator;
 	struct cmm_attrs *pattrs;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(buf_pa != NULL);
-
 	if (ul_seg_id == 0) {
 		pattrs = &cmm_dfltalctattrs;
 		ul_seg_id = pattrs->seg_id;
@@ -392,8 +364,6 @@
 	int status = 0;
 	struct dev_object *hdev_obj;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(ph_cmm_mgr != NULL);
 	if (hprocessor != NULL)
 		status = proc_get_dev_object(hprocessor, &hdev_obj);
 	else
@@ -419,8 +389,6 @@
 	struct cmm_allocator *altr;
 	struct cmm_mnode *curr;
 
-	DBC_REQUIRE(cmm_info_obj != NULL);
-
 	if (!hcmm_mgr) {
 		status = -EFAULT;
 		return status;
@@ -464,24 +432,6 @@
 }
 
 /*
- *  ======== cmm_init ========
- *  Purpose:
- *      Initializes private state of CMM module.
- */
-bool cmm_init(void)
-{
-	bool ret = true;
-
-	DBC_REQUIRE(refs >= 0);
-	if (ret)
-		refs++;
-
-	DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
-
-	return ret;
-}
-
-/*
  *  ======== cmm_register_gppsm_seg ========
  *  Purpose:
  *      Register a block of SM with the CMM to be used for later GPP SM
@@ -499,13 +449,6 @@
 	struct cmm_mnode *new_node;
 	s32 slot_seg;
 
-	DBC_REQUIRE(ul_size > 0);
-	DBC_REQUIRE(sgmt_id != NULL);
-	DBC_REQUIRE(dw_gpp_base_pa != 0);
-	DBC_REQUIRE(gpp_base_va != 0);
-	DBC_REQUIRE((c_factor <= CMM_ADDTODSPPA) &&
-			(c_factor >= CMM_SUBFROMDSPPA));
-
 	dev_dbg(bridge, "%s: dw_gpp_base_pa %x ul_size %x dsp_addr_offset %x "
 			"dw_dsp_base %x ul_dsp_size %x gpp_base_va %x\n",
 			__func__, dw_gpp_base_pa, ul_size, dsp_addr_offset,
@@ -589,7 +532,6 @@
 	struct cmm_allocator *psma;
 	u32 ul_id = ul_seg_id;
 
-	DBC_REQUIRE(ul_seg_id > 0);
 	if (!hcmm_mgr)
 		return -EFAULT;
 
@@ -635,8 +577,6 @@
 {
 	struct cmm_mnode *curr, *tmp;
 
-	DBC_REQUIRE(psma != NULL);
-
 	/* free nodes on free list */
 	list_for_each_entry_safe(curr, tmp, &psma->free_list, link) {
 		list_del(&curr->link);
@@ -664,7 +604,6 @@
 static s32 get_slot(struct cmm_object *cmm_mgr_obj)
 {
 	s32 slot_seg = -1;	/* neg on failure */
-	DBC_REQUIRE(cmm_mgr_obj != NULL);
 	/* get first available slot in cmm mgr SMSegTab[] */
 	for (slot_seg = 0; slot_seg < CMM_MAXGPPSEGS; slot_seg++) {
 		if (cmm_mgr_obj->pa_gppsm_seg_tab[slot_seg] == NULL)
@@ -687,11 +626,6 @@
 {
 	struct cmm_mnode *pnode;
 
-	DBC_REQUIRE(cmm_mgr_obj != NULL);
-	DBC_REQUIRE(dw_pa != 0);
-	DBC_REQUIRE(dw_va != 0);
-	DBC_REQUIRE(ul_size != 0);
-
 	/* Check cmm mgr's node freelist */
 	if (list_empty(&cmm_mgr_obj->node_free_list)) {
 		pnode = kzalloc(sizeof(struct cmm_mnode), GFP_KERNEL);
@@ -719,7 +653,6 @@
  */
 static void delete_node(struct cmm_object *cmm_mgr_obj, struct cmm_mnode *pnode)
 {
-	DBC_REQUIRE(pnode != NULL);
 	list_add_tail(&pnode->link, &cmm_mgr_obj->node_free_list);
 }
 
@@ -794,9 +727,6 @@
 static struct cmm_allocator *get_allocator(struct cmm_object *cmm_mgr_obj,
 					   u32 ul_seg_id)
 {
-	DBC_REQUIRE(cmm_mgr_obj != NULL);
-	DBC_REQUIRE((ul_seg_id > 0) && (ul_seg_id <= CMM_MAXGPPSEGS));
-
 	return cmm_mgr_obj->pa_gppsm_seg_tab[ul_seg_id - 1];
 }
 
@@ -818,10 +748,6 @@
 	struct cmm_xlator *xlator_object = NULL;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(xlator != NULL);
-	DBC_REQUIRE(hcmm_mgr != NULL);
-
 	*xlator = NULL;
 	if (xlator_attrs == NULL)
 		xlator_attrs = &cmm_dfltxlatorattrs;	/* set defaults */
@@ -851,13 +777,6 @@
 	void *tmp_va_buff;
 	struct cmm_attrs attrs;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(xlator != NULL);
-	DBC_REQUIRE(xlator_obj->cmm_mgr != NULL);
-	DBC_REQUIRE(va_buf != NULL);
-	DBC_REQUIRE(pa_size > 0);
-	DBC_REQUIRE(xlator_obj->seg_id > 0);
-
 	if (xlator_obj) {
 		attrs.seg_id = xlator_obj->seg_id;
 		__raw_writel(0, va_buf);
@@ -887,10 +806,6 @@
 	int status = -EPERM;
 	void *buf_pa = NULL;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(buf_va != NULL);
-	DBC_REQUIRE(xlator_obj->seg_id > 0);
-
 	if (xlator_obj) {
 		/* convert Va to Pa so we can free it. */
 		buf_pa = cmm_xlator_translate(xlator, buf_va, CMM_VA2PA);
@@ -900,7 +815,8 @@
 			if (status) {
 				/* Uh oh, this shouldn't happen. Descriptor
 				 * gone! */
-				DBC_ASSERT(false);	/* CMM is leaking mem */
+				pr_err("%s, line %d: Assertion failed\n",
+				       __FILE__, __LINE__);
 			}
 		}
 	}
@@ -918,10 +834,6 @@
 	struct cmm_xlator *xlator_obj = (struct cmm_xlator *)xlator;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(paddr != NULL);
-	DBC_REQUIRE((segm_id > 0) && (segm_id <= CMM_MAXGPPSEGS));
-
 	if (xlator_obj) {
 		if (set_info) {
 			/* set translators virtual address range */
@@ -948,16 +860,11 @@
 	struct cmm_allocator *allocator = NULL;
 	u32 dw_offset = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(paddr != NULL);
-	DBC_REQUIRE((xtype >= CMM_VA2PA) && (xtype <= CMM_DSPPA2PA));
-
 	if (!xlator_obj)
 		goto loop_cont;
 
 	cmm_mgr_obj = (struct cmm_object *)xlator_obj->cmm_mgr;
 	/* get this translator's default SM allocator */
-	DBC_ASSERT(xlator_obj->seg_id > 0);
 	allocator = cmm_mgr_obj->pa_gppsm_seg_tab[xlator_obj->seg_id - 1];
 	if (!allocator)
 		goto loop_cont;
diff --git a/drivers/staging/tidspbridge/pmgr/cod.c b/drivers/staging/tidspbridge/pmgr/cod.c
index 1a29264..4007826 100644
--- a/drivers/staging/tidspbridge/pmgr/cod.c
+++ b/drivers/staging/tidspbridge/pmgr/cod.c
@@ -30,9 +30,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- Platform Manager */
 /* Include appropriate loader header file */
 #include <dspbridge/dbll.h>
@@ -61,8 +58,6 @@
 	struct cod_manager *cod_mgr;
 };
 
-static u32 refs = 0L;
-
 static struct dbll_fxns ldr_fxns = {
 	(dbll_close_fxn) dbll_close,
 	(dbll_create_fxn) dbll_create,
@@ -183,10 +178,6 @@
 {
 	struct cod_manager *hmgr;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(lib != NULL);
-	DBC_REQUIRE(lib->cod_mgr);
-
 	hmgr = lib->cod_mgr;
 	hmgr->fxns.close_fxn(lib->dbll_lib);
 
@@ -208,9 +199,6 @@
 	struct dbll_attrs zl_attrs;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(mgr != NULL);
-
 	/* assume failure */
 	*mgr = NULL;
 
@@ -263,9 +251,6 @@
  */
 void cod_delete(struct cod_manager *cod_mgr_obj)
 {
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(cod_mgr_obj);
-
 	if (cod_mgr_obj->base_lib) {
 		if (cod_mgr_obj->loaded)
 			cod_mgr_obj->fxns.unload_fxn(cod_mgr_obj->base_lib,
@@ -281,21 +266,6 @@
 }
 
 /*
- *  ======== cod_exit ========
- *  Purpose:
- *      Discontinue usage of the COD module.
- *
- */
-void cod_exit(void)
-{
-	DBC_REQUIRE(refs > 0);
-
-	refs--;
-
-	DBC_ENSURE(refs >= 0);
-}
-
-/*
  *  ======== cod_get_base_lib ========
  *  Purpose:
  *      Get handle to the base image DBL library.
@@ -305,10 +275,6 @@
 {
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(cod_mgr_obj);
-	DBC_REQUIRE(plib != NULL);
-
 	*plib = (struct dbll_library_obj *)cod_mgr_obj->base_lib;
 
 	return status;
@@ -322,10 +288,6 @@
 {
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(cod_mgr_obj);
-	DBC_REQUIRE(sz_name != NULL);
-
 	if (usize <= COD_MAXPATHLENGTH)
 		strncpy(sz_name, cod_mgr_obj->sz_zl_file, usize);
 	else
@@ -342,10 +304,6 @@
  */
 int cod_get_entry(struct cod_manager *cod_mgr_obj, u32 *entry_pt)
 {
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(cod_mgr_obj);
-	DBC_REQUIRE(entry_pt != NULL);
-
 	*entry_pt = cod_mgr_obj->entry;
 
 	return 0;
@@ -361,10 +319,6 @@
 {
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(cod_mgr_obj);
-	DBC_REQUIRE(loader != NULL);
-
 	*loader = (struct dbll_tar_obj *)cod_mgr_obj->target;
 
 	return status;
@@ -382,13 +336,6 @@
 	struct cod_manager *cod_mgr_obj;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(lib != NULL);
-	DBC_REQUIRE(lib->cod_mgr);
-	DBC_REQUIRE(str_sect != NULL);
-	DBC_REQUIRE(addr != NULL);
-	DBC_REQUIRE(len != NULL);
-
 	*addr = 0;
 	*len = 0;
 	if (lib != NULL) {
@@ -399,8 +346,6 @@
 		status = -ESPIPE;
 	}
 
-	DBC_ENSURE(!status || ((*addr == 0) && (*len == 0)));
-
 	return status;
 }
 
@@ -417,11 +362,6 @@
 {
 	struct dbll_sym_val *dbll_sym;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(cod_mgr_obj);
-	DBC_REQUIRE(str_sym != NULL);
-	DBC_REQUIRE(pul_value != NULL);
-
 	dev_dbg(bridge, "%s: cod_mgr_obj: %p str_sym: %s pul_value: %p\n",
 		__func__, cod_mgr_obj, str_sym, pul_value);
 	if (cod_mgr_obj->base_lib) {
@@ -442,25 +382,6 @@
 }
 
 /*
- *  ======== cod_init ========
- *  Purpose:
- *      Initialize the COD module's private state.
- *
- */
-bool cod_init(void)
-{
-	bool ret = true;
-
-	DBC_REQUIRE(refs >= 0);
-
-	if (ret)
-		refs++;
-
-	DBC_ENSURE((ret && refs > 0) || (!ret && refs >= 0));
-	return ret;
-}
-
-/*
  *  ======== cod_load_base ========
  *  Purpose:
  *      Load the initial program image, optionally with command-line arguments,
@@ -482,14 +403,6 @@
 	int status;
 	u32 i;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(cod_mgr_obj);
-	DBC_REQUIRE(num_argc > 0);
-	DBC_REQUIRE(args != NULL);
-	DBC_REQUIRE(args[0] != NULL);
-	DBC_REQUIRE(pfn_write != NULL);
-	DBC_REQUIRE(cod_mgr_obj->base_lib != NULL);
-
 	/*
 	 *  Make sure every argv[] stated in argc has a value, or change argc to
 	 *  reflect true number in NULL terminated argv array.
@@ -538,12 +451,6 @@
 	int status = 0;
 	struct cod_libraryobj *lib = NULL;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(hmgr);
-	DBC_REQUIRE(sz_coff_path != NULL);
-	DBC_REQUIRE(flags == COD_NOLOAD || flags == COD_SYMB);
-	DBC_REQUIRE(lib_obj != NULL);
-
 	*lib_obj = NULL;
 
 	lib = kzalloc(sizeof(struct cod_libraryobj), GFP_KERNEL);
@@ -575,10 +482,6 @@
 	int status = 0;
 	struct dbll_library_obj *lib;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(hmgr);
-	DBC_REQUIRE(sz_coff_path != NULL);
-
 	/* if we previously opened a base image, close it now */
 	if (hmgr->base_lib) {
 		if (hmgr->loaded) {
@@ -612,12 +515,6 @@
 {
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(lib != NULL);
-	DBC_REQUIRE(lib->cod_mgr);
-	DBC_REQUIRE(str_sect != NULL);
-	DBC_REQUIRE(str_content != NULL);
-
 	if (lib != NULL)
 		status =
 		    lib->cod_mgr->fxns.read_sect_fxn(lib->dbll_lib, str_sect,
diff --git a/drivers/staging/tidspbridge/pmgr/dbll.c b/drivers/staging/tidspbridge/pmgr/dbll.c
index 31da62b..9f07036 100644
--- a/drivers/staging/tidspbridge/pmgr/dbll.c
+++ b/drivers/staging/tidspbridge/pmgr/dbll.c
@@ -21,8 +21,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
 #include <dspbridge/gh.h>
 
 /*  ----------------------------------- OS Adaptation Layer */
@@ -189,8 +187,6 @@
 static bool name_match(void *key, void *sp);
 static void sym_delete(void *value);
 
-static u32 refs;		/* module reference count */
-
 /* Symbol Redefinition */
 static int redefined_symbol;
 static int gbl_search = 1;
@@ -202,9 +198,6 @@
 {
 	struct dbll_tar_obj *zl_target;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(zl_lib);
-	DBC_REQUIRE(zl_lib->open_ref > 0);
 	zl_target = zl_lib->target_obj;
 	zl_lib->open_ref--;
 	if (zl_lib->open_ref == 0) {
@@ -241,10 +234,6 @@
 	struct dbll_tar_obj *pzl_target;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(pattrs != NULL);
-	DBC_REQUIRE(target_obj != NULL);
-
 	/* Allocate DBL target object */
 	pzl_target = kzalloc(sizeof(struct dbll_tar_obj), GFP_KERNEL);
 	if (target_obj != NULL) {
@@ -255,8 +244,6 @@
 			pzl_target->attrs = *pattrs;
 			*target_obj = (struct dbll_tar_obj *)pzl_target;
 		}
-		DBC_ENSURE((!status && *target_obj) ||
-				(status && *target_obj == NULL));
 	}
 
 	return status;
@@ -269,9 +256,6 @@
 {
 	struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(zl_target);
-
 	kfree(zl_target);
 
 }
@@ -282,14 +266,7 @@
  */
 void dbll_exit(void)
 {
-	DBC_REQUIRE(refs > 0);
-
-	refs--;
-
-	if (refs == 0)
-		gh_exit();
-
-	DBC_ENSURE(refs >= 0);
+	/* do nothing */
 }
 
 /*
@@ -302,12 +279,6 @@
 	struct dbll_symbol *sym;
 	bool status = false;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(zl_lib);
-	DBC_REQUIRE(name != NULL);
-	DBC_REQUIRE(sym_val != NULL);
-	DBC_REQUIRE(zl_lib->sym_tab != NULL);
-
 	sym = (struct dbll_symbol *)gh_find(zl_lib->sym_tab, name);
 	if (sym != NULL) {
 		*sym_val = &sym->value;
@@ -327,10 +298,6 @@
 {
 	struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(zl_target);
-	DBC_REQUIRE(pattrs != NULL);
-
 	if ((pattrs != NULL) && (zl_target != NULL))
 		*pattrs = zl_target->attrs;
 
@@ -347,12 +314,6 @@
 	char cname[MAXEXPR + 1];
 	bool status = false;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(zl_lib);
-	DBC_REQUIRE(sym_val != NULL);
-	DBC_REQUIRE(zl_lib->sym_tab != NULL);
-	DBC_REQUIRE(name != NULL);
-
 	cname[0] = '_';
 
 	strncpy(cname + 1, name, sizeof(cname) - 2);
@@ -382,12 +343,6 @@
 	struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(name != NULL);
-	DBC_REQUIRE(paddr != NULL);
-	DBC_REQUIRE(psize != NULL);
-	DBC_REQUIRE(zl_lib);
-
 	/* If DOFF file is not open, we open it. */
 	if (zl_lib != NULL) {
 		if (zl_lib->fp == NULL) {
@@ -434,12 +389,7 @@
  */
 bool dbll_init(void)
 {
-	DBC_REQUIRE(refs >= 0);
-
-	if (refs == 0)
-		gh_init();
-
-	refs++;
+	/* do nothing */
 
 	return true;
 }
@@ -456,10 +406,6 @@
 	s32 err;
 	int status = 0;
 	bool opened_doff = false;
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(zl_lib);
-	DBC_REQUIRE(entry != NULL);
-	DBC_REQUIRE(attrs != NULL);
 
 	/*
 	 *  Load if not already loaded.
@@ -558,8 +504,6 @@
 	if (opened_doff)
 		dof_close(zl_lib);
 
-	DBC_ENSURE(status || zl_lib->load_ref > 0);
-
 	dev_dbg(bridge, "%s: lib: %p flags: 0x%x entry: %p, status 0x%x\n",
 		__func__, lib, flags, entry, status);
 
@@ -577,12 +521,6 @@
 	s32 err;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(zl_target);
-	DBC_REQUIRE(zl_target->attrs.fopen != NULL);
-	DBC_REQUIRE(file != NULL);
-	DBC_REQUIRE(lib_obj != NULL);
-
 	zl_lib = zl_target->head;
 	while (zl_lib != NULL) {
 		if (strcmp(zl_lib->file_name, file) == 0) {
@@ -699,8 +637,6 @@
 			dbll_close((struct dbll_library_obj *)zl_lib);
 
 	}
-	DBC_ENSURE((!status && (zl_lib->open_ref > 0) && *lib_obj)
-				|| (status && *lib_obj == NULL));
 
 	dev_dbg(bridge, "%s: target: %p file: %s lib_obj: %p, status 0x%x\n",
 		__func__, target, file, lib_obj, status);
@@ -722,12 +658,6 @@
 	const struct ldr_section_info *sect = NULL;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(zl_lib);
-	DBC_REQUIRE(name != NULL);
-	DBC_REQUIRE(buf != NULL);
-	DBC_REQUIRE(size != 0);
-
 	/* If DOFF file is not open, we open it. */
 	if (zl_lib != NULL) {
 		if (zl_lib->fp == NULL) {
@@ -788,14 +718,11 @@
 	struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
 	s32 err = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(zl_lib);
-	DBC_REQUIRE(zl_lib->load_ref > 0);
 	dev_dbg(bridge, "%s: lib: %p\n", __func__, lib);
 	zl_lib->load_ref--;
 	/* Unload only if reference count is 0 */
 	if (zl_lib->load_ref != 0)
-		goto func_end;
+		return;
 
 	zl_lib->target_obj->attrs = *attrs;
 	if (zl_lib->dload_mod_obj) {
@@ -814,8 +741,6 @@
 	/* delete DOFF desc since it holds *lots* of host OS
 	 * resources */
 	dof_close(zl_lib);
-func_end:
-	DBC_ENSURE(zl_lib->load_ref >= 0);
 }
 
 /*
@@ -874,8 +799,6 @@
 	u16 hash;
 	char *name = (char *)key;
 
-	DBC_REQUIRE(name != NULL);
-
 	hash = 0;
 
 	while (*name) {
@@ -893,9 +816,6 @@
  */
 static bool name_match(void *key, void *sp)
 {
-	DBC_REQUIRE(key != NULL);
-	DBC_REQUIRE(sp != NULL);
-
 	if ((key != NULL) && (sp != NULL)) {
 		if (strcmp((char *)key, ((struct dbll_symbol *)sp)->name) ==
 		    0)
@@ -938,10 +858,7 @@
 	struct dbll_library_obj *lib;
 	int bytes_read = 0;
 
-	DBC_REQUIRE(this != NULL);
 	lib = pstream->lib;
-	DBC_REQUIRE(lib);
-
 	if (lib != NULL) {
 		bytes_read =
 		    (*(lib->target_obj->attrs.fread)) (buffer, 1, bufsize,
@@ -960,10 +877,7 @@
 	struct dbll_library_obj *lib;
 	int status = 0;		/* Success */
 
-	DBC_REQUIRE(this != NULL);
 	lib = pstream->lib;
-	DBC_REQUIRE(lib);
-
 	if (lib != NULL) {
 		status = (*(lib->target_obj->attrs.fseek)) (lib->fp, (long)pos,
 							    SEEK_SET);
@@ -986,10 +900,7 @@
 	struct dbll_sym_val *dbll_sym = NULL;
 	bool status = false;	/* Symbol not found yet */
 
-	DBC_REQUIRE(this != NULL);
 	lib = ldr_sym->lib;
-	DBC_REQUIRE(lib);
-
 	if (lib != NULL) {
 		if (lib->target_obj->attrs.sym_lookup) {
 			/* Check current lib + base lib + dep lib +
@@ -1015,9 +926,6 @@
 	if (!status && gbl_search)
 		dev_dbg(bridge, "%s: Symbol not found: %s\n", __func__, name);
 
-	DBC_ASSERT((status && (dbll_sym != NULL))
-		   || (!status && (dbll_sym == NULL)));
-
 	ret_sym = (struct dynload_symbol *)dbll_sym;
 	return ret_sym;
 }
@@ -1034,11 +942,7 @@
 	struct dbll_library_obj *lib;
 	struct dbll_symbol *sym;
 
-	DBC_REQUIRE(this != NULL);
 	lib = ldr_sym->lib;
-	DBC_REQUIRE(lib);
-	DBC_REQUIRE(lib->sym_tab != NULL);
-
 	sym = (struct dbll_symbol *)gh_find(lib->sym_tab, (char *)name);
 
 	ret_sym = (struct dynload_symbol *)&sym->value;
@@ -1059,10 +963,7 @@
 	struct dbll_library_obj *lib;
 	struct dynload_symbol *ret;
 
-	DBC_REQUIRE(this != NULL);
-	DBC_REQUIRE(name);
 	lib = ldr_sym->lib;
-	DBC_REQUIRE(lib);
 
 	/* Check to see if symbol is already defined in symbol table */
 	if (!(lib->target_obj->attrs.base_image)) {
@@ -1111,10 +1012,7 @@
 	struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
 	struct dbll_library_obj *lib;
 
-	DBC_REQUIRE(this != NULL);
 	lib = ldr_sym->lib;
-	DBC_REQUIRE(lib);
-
 	/* May not need to do anything */
 }
 
@@ -1127,9 +1025,7 @@
 	struct dbll_library_obj *lib;
 	void *buf;
 
-	DBC_REQUIRE(this != NULL);
 	lib = ldr_sym->lib;
-	DBC_REQUIRE(lib);
 
 	buf = kzalloc(memsize, GFP_KERNEL);
 
@@ -1144,9 +1040,7 @@
 	struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
 	struct dbll_library_obj *lib;
 
-	DBC_REQUIRE(this != NULL);
 	lib = ldr_sym->lib;
-	DBC_REQUIRE(lib);
 
 	kfree(mem_ptr);
 }
@@ -1161,9 +1055,7 @@
 	struct dbll_library_obj *lib;
 	char temp_buf[MAXEXPR];
 
-	DBC_REQUIRE(this != NULL);
 	lib = ldr_sym->lib;
-	DBC_REQUIRE(lib);
 	vsnprintf((char *)temp_buf, MAXEXPR, (char *)errstr, args);
 	dev_dbg(bridge, "%s\n", temp_buf);
 }
@@ -1195,9 +1087,7 @@
 	u32 alloc_size = 0;
 	u32 run_addr_flag = 0;
 
-	DBC_REQUIRE(this != NULL);
 	lib = dbll_alloc_obj->lib;
-	DBC_REQUIRE(lib);
 
 	mem_sect_type =
 	    (stype == DLOAD_TEXT) ? DBLL_CODE : (stype ==
@@ -1206,7 +1096,6 @@
 
 	/* Attempt to extract the segment ID and requirement information from
 	   the name of the section */
-	DBC_REQUIRE(info->name);
 	token_len = strlen((char *)(info->name)) + 1;
 
 	sz_sect_name = kzalloc(token_len, GFP_KERNEL);
@@ -1307,9 +1196,7 @@
 	    (stype == DLOAD_TEXT) ? DBLL_CODE : (stype ==
 						 DLOAD_BSS) ? DBLL_BSS :
 	    DBLL_DATA;
-	DBC_REQUIRE(this != NULL);
 	lib = dbll_alloc_obj->lib;
-	DBC_REQUIRE(lib);
 	/* segid was set by alloc function */
 	segid = (u32) info->context;
 	if (mem_sect_type == DBLL_CODE)
@@ -1347,9 +1234,7 @@
 	struct dbll_library_obj *lib;
 	int bytes_read = 0;
 
-	DBC_REQUIRE(this != NULL);
 	lib = init_obj->lib;
-	DBC_REQUIRE(lib);
 	/* Need bridge_brd_read function */
 	return bytes_read;
 }
@@ -1368,7 +1253,6 @@
 	u32 mem_sect_type;
 	bool ret = true;
 
-	DBC_REQUIRE(this != NULL);
 	lib = init_obj->lib;
 	if (!lib)
 		return false;
@@ -1415,7 +1299,6 @@
 	struct dbll_library_obj *lib;
 	struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
 
-	DBC_REQUIRE(this != NULL);
 	lib = init_obj->lib;
 	pbuf = NULL;
 	/* Pass the NULL pointer to write_mem to get the start address of Shared
@@ -1439,9 +1322,7 @@
 	struct dbll_library_obj *lib;
 	bool ret = true;
 
-	DBC_REQUIRE(this != NULL);
 	lib = init_obj->lib;
-	DBC_REQUIRE(lib);
 	/* Save entry point */
 	if (lib != NULL)
 		lib->entry = (u32) start;
diff --git a/drivers/staging/tidspbridge/pmgr/dev.c b/drivers/staging/tidspbridge/pmgr/dev.c
index 522810b..6234ffb 100644
--- a/drivers/staging/tidspbridge/pmgr/dev.c
+++ b/drivers/staging/tidspbridge/pmgr/dev.c
@@ -24,9 +24,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- Platform Manager */
 #include <dspbridge/cod.h>
 #include <dspbridge/drv.h>
@@ -84,9 +81,6 @@
 	char sz_string[MAXREGPATHLENGTH];
 };
 
-/*  ----------------------------------- Globals */
-static u32 refs;		/* Module reference count */
-
 /*  ----------------------------------- Function Prototypes */
 static int fxn_not_implemented(int arg, ...);
 static int init_cod_mgr(struct dev_object *dev_obj);
@@ -106,11 +100,8 @@
 	u32 ul_written = 0;
 	int status;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(host_buf != NULL);	/* Required of BrdWrite(). */
 	if (dev_obj) {
 		/* Require of BrdWrite() */
-		DBC_ASSERT(dev_obj->bridge_context != NULL);
 		status = (*dev_obj->bridge_interface.brd_write) (
 					dev_obj->bridge_context, host_buf,
 					dsp_add, ul_num_bytes, mem_space);
@@ -143,9 +134,6 @@
 	struct drv_object *hdrv_obj = NULL;
 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
 	int status = 0;
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(device_obj != NULL);
-	DBC_REQUIRE(driver_file_name != NULL);
 
 	status = drv_request_bridge_res_dsp((void *)&host_res);
 
@@ -169,7 +157,6 @@
 	/* Create the device object, and pass a handle to the Bridge driver for
 	 * storage. */
 	if (!status) {
-		DBC_ASSERT(drv_fxns);
 		dev_obj = kzalloc(sizeof(struct dev_object), GFP_KERNEL);
 		if (dev_obj) {
 			/* Fill out the rest of the Dev Object structure: */
@@ -191,9 +178,6 @@
 			status = (dev_obj->bridge_interface.dev_create)
 			    (&dev_obj->bridge_context, dev_obj,
 			     host_res);
-			/* Assert bridge_dev_create()'s ensure clause: */
-			DBC_ASSERT(status
-				   || (dev_obj->bridge_context != NULL));
 		} else {
 			status = -ENOMEM;
 		}
@@ -271,7 +255,6 @@
 		*device_obj = NULL;
 	}
 
-	DBC_ENSURE((!status && *device_obj) || (status && !*device_obj));
 	return status;
 }
 
@@ -287,17 +270,11 @@
 	int status = 0;
 	struct dev_object *dev_obj = hdev_obj;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(hdev_obj);
-
 	/* There can be only one Node Manager per DEV object */
-	DBC_ASSERT(!dev_obj->node_mgr);
 	status = node_create_mgr(&dev_obj->node_mgr, hdev_obj);
 	if (status)
 		dev_obj->node_mgr = NULL;
 
-	DBC_ENSURE((!status && dev_obj->node_mgr != NULL)
-		   || (status && dev_obj->node_mgr == NULL));
 	return status;
 }
 
@@ -311,9 +288,6 @@
 	int status = 0;
 	struct dev_object *dev_obj = hdev_obj;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(hdev_obj);
-
 	if (dev_obj->node_mgr) {
 		if (node_delete_mgr(dev_obj->node_mgr))
 			status = -EPERM;
@@ -322,7 +296,6 @@
 
 	}
 
-	DBC_ENSURE((!status && dev_obj->node_mgr == NULL) || status);
 	return status;
 }
 
@@ -337,8 +310,6 @@
 	int status = 0;
 	struct dev_object *dev_obj = hdev_obj;
 
-	DBC_REQUIRE(refs > 0);
-
 	if (hdev_obj) {
 		if (dev_obj->cod_mgr) {
 			cod_delete(dev_obj->cod_mgr);
@@ -415,9 +386,6 @@
 	int status = 0;
 	struct dev_object *dev_obj = hdev_obj;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(mgr != NULL);
-
 	if (hdev_obj) {
 		*mgr = dev_obj->chnl_mgr;
 	} else {
@@ -425,7 +393,6 @@
 		status = -EFAULT;
 	}
 
-	DBC_ENSURE(!status || (mgr != NULL && *mgr == NULL));
 	return status;
 }
 
@@ -441,9 +408,6 @@
 	int status = 0;
 	struct dev_object *dev_obj = hdev_obj;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(mgr != NULL);
-
 	if (hdev_obj) {
 		*mgr = dev_obj->cmm_mgr;
 	} else {
@@ -451,7 +415,6 @@
 		status = -EFAULT;
 	}
 
-	DBC_ENSURE(!status || (mgr != NULL && *mgr == NULL));
 	return status;
 }
 
@@ -467,9 +430,6 @@
 	int status = 0;
 	struct dev_object *dev_obj = hdev_obj;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(mgr != NULL);
-
 	if (hdev_obj) {
 		*mgr = dev_obj->dmm_mgr;
 	} else {
@@ -477,7 +437,6 @@
 		status = -EFAULT;
 	}
 
-	DBC_ENSURE(!status || (mgr != NULL && *mgr == NULL));
 	return status;
 }
 
@@ -492,9 +451,6 @@
 	int status = 0;
 	struct dev_object *dev_obj = hdev_obj;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(cod_mgr != NULL);
-
 	if (hdev_obj) {
 		*cod_mgr = dev_obj->cod_mgr;
 	} else {
@@ -502,7 +458,6 @@
 		status = -EFAULT;
 	}
 
-	DBC_ENSURE(!status || (cod_mgr != NULL && *cod_mgr == NULL));
 	return status;
 }
 
@@ -514,9 +469,6 @@
 {
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(deh_manager != NULL);
-	DBC_REQUIRE(hdev_obj);
 	if (hdev_obj) {
 		*deh_manager = hdev_obj->deh_mgr;
 	} else {
@@ -537,9 +489,6 @@
 	int status = 0;
 	struct dev_object *dev_obj = hdev_obj;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(dev_nde != NULL);
-
 	if (hdev_obj) {
 		*dev_nde = dev_obj->dev_node_obj;
 	} else {
@@ -547,7 +496,6 @@
 		status = -EFAULT;
 	}
 
-	DBC_ENSURE(!status || (dev_nde != NULL && *dev_nde == NULL));
 	return status;
 }
 
@@ -578,9 +526,6 @@
 	int status = 0;
 	struct dev_object *dev_obj = hdev_obj;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(if_fxns != NULL);
-
 	if (hdev_obj) {
 		*if_fxns = &dev_obj->bridge_interface;
 	} else {
@@ -588,7 +533,6 @@
 		status = -EFAULT;
 	}
 
-	DBC_ENSURE(!status || ((if_fxns != NULL) && (*if_fxns == NULL)));
 	return status;
 }
 
@@ -600,10 +544,6 @@
 {
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(io_man != NULL);
-	DBC_REQUIRE(hdev_obj);
-
 	if (hdev_obj) {
 		*io_man = hdev_obj->iomgr;
 	} else {
@@ -638,10 +578,6 @@
  */
 void dev_get_msg_mgr(struct dev_object *hdev_obj, struct msg_mgr **msg_man)
 {
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(msg_man != NULL);
-	DBC_REQUIRE(hdev_obj);
-
 	*msg_man = hdev_obj->msg_mgr;
 }
 
@@ -656,9 +592,6 @@
 	int status = 0;
 	struct dev_object *dev_obj = hdev_obj;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(node_man != NULL);
-
 	if (hdev_obj) {
 		*node_man = dev_obj->node_mgr;
 	} else {
@@ -666,7 +599,6 @@
 		status = -EFAULT;
 	}
 
-	DBC_ENSURE(!status || (node_man != NULL && *node_man == NULL));
 	return status;
 }
 
@@ -679,9 +611,6 @@
 	int status = 0;
 	struct cod_manager *cod_mgr;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(str_sym != NULL && pul_value != NULL);
-
 	if (hdev_obj) {
 		status = dev_get_cod_mgr(hdev_obj, &cod_mgr);
 		if (cod_mgr)
@@ -706,9 +635,6 @@
 	int status = 0;
 	struct dev_object *dev_obj = hdev_obj;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(phbridge_context != NULL);
-
 	if (hdev_obj) {
 		*phbridge_context = dev_obj->bridge_context;
 	} else {
@@ -716,67 +642,10 @@
 		status = -EFAULT;
 	}
 
-	DBC_ENSURE(!status || ((phbridge_context != NULL) &&
-					     (*phbridge_context == NULL)));
 	return status;
 }
 
 /*
- *  ======== dev_exit ========
- *  Purpose:
- *      Decrement reference count, and free resources when reference count is
- *      0.
- */
-void dev_exit(void)
-{
-	DBC_REQUIRE(refs > 0);
-
-	refs--;
-
-	if (refs == 0) {
-		cmm_exit();
-		dmm_exit();
-	}
-
-	DBC_ENSURE(refs >= 0);
-}
-
-/*
- *  ======== dev_init ========
- *  Purpose:
- *      Initialize DEV's private state, keeping a reference count on each call.
- */
-bool dev_init(void)
-{
-	bool cmm_ret, dmm_ret, ret = true;
-
-	DBC_REQUIRE(refs >= 0);
-
-	if (refs == 0) {
-		cmm_ret = cmm_init();
-		dmm_ret = dmm_init();
-
-		ret = cmm_ret && dmm_ret;
-
-		if (!ret) {
-			if (cmm_ret)
-				cmm_exit();
-
-			if (dmm_ret)
-				dmm_exit();
-
-		}
-	}
-
-	if (ret)
-		refs++;
-
-	DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
-
-	return ret;
-}
-
-/*
  *  ======== dev_notify_clients ========
  *  Purpose:
  *      Notify all clients of this device of a change in device status.
@@ -841,14 +710,11 @@
 	int status = 0;
 	struct dev_object *dev_obj = hdev_obj;
 
-	DBC_REQUIRE(refs > 0);
-
 	if (hdev_obj)
 		dev_obj->chnl_mgr = hmgr;
 	else
 		status = -EFAULT;
 
-	DBC_ENSURE(status || (dev_obj->chnl_mgr == hmgr));
 	return status;
 }
 
@@ -859,9 +725,6 @@
  */
 void dev_set_msg_mgr(struct dev_object *hdev_obj, struct msg_mgr *hmgr)
 {
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(hdev_obj);
-
 	hdev_obj->msg_mgr = hmgr;
 }
 
@@ -879,8 +742,6 @@
 	struct mgr_object *hmgr_obj = NULL;
 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
 
-	DBC_REQUIRE(refs > 0);
-
 	/* Given all resources, create a device object. */
 	status = dev_create_device(&hdev_obj, bridge_file_name,
 				   dev_node_obj);
@@ -944,9 +805,6 @@
 	int status = 0;
 	char *sz_dummy_file = "dummy";
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(!dev_obj || (dev_obj->cod_mgr == NULL));
-
 	status = cod_create(&dev_obj->cod_mgr, sz_dummy_file);
 
 	return status;
@@ -976,10 +834,6 @@
 {
 	struct dev_object *dev_obj = (struct dev_object *)hdev_obj;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(dev_obj);
-	DBC_REQUIRE(proc_obj != 0);
-	DBC_REQUIRE(already_attached != NULL);
 	if (!list_empty(&dev_obj->proc_list))
 		*already_attached = true;
 
@@ -1017,10 +871,6 @@
 	struct list_head *cur_elem;
 	struct dev_object *dev_obj = (struct dev_object *)hdev_obj;
 
-	DBC_REQUIRE(dev_obj);
-	DBC_REQUIRE(proc_obj != 0);
-	DBC_REQUIRE(!list_empty(&dev_obj->proc_list));
-
 	/* Search list for dev_obj: */
 	list_for_each(cur_elem, &dev_obj->proc_list) {
 		if ((u32) cur_elem == proc_obj) {
@@ -1069,10 +919,6 @@
     (intf_fxns->pfn = ((drv_fxns->pfn != NULL) ? drv_fxns->pfn : \
     (cast)fxn_not_implemented))
 
-	DBC_REQUIRE(intf_fxns != NULL);
-	DBC_REQUIRE(drv_fxns != NULL);
-	DBC_REQUIRE(MAKEVERSION(drv_fxns->brd_api_major_version,
-			drv_fxns->brd_api_minor_version) <= BRD_API_VERSION);
 	bridge_version = MAKEVERSION(drv_fxns->brd_api_major_version,
 				     drv_fxns->brd_api_minor_version);
 	intf_fxns->brd_api_major_version = drv_fxns->brd_api_major_version;
@@ -1119,33 +965,5 @@
 		STORE_FXN(fxn_msg_setqueueid, msg_set_queue_id);
 	}
 	/* Add code for any additional functions in newerBridge versions here */
-	/* Ensure postcondition: */
-	DBC_ENSURE(intf_fxns->dev_create != NULL);
-	DBC_ENSURE(intf_fxns->dev_destroy != NULL);
-	DBC_ENSURE(intf_fxns->dev_cntrl != NULL);
-	DBC_ENSURE(intf_fxns->brd_monitor != NULL);
-	DBC_ENSURE(intf_fxns->brd_start != NULL);
-	DBC_ENSURE(intf_fxns->brd_stop != NULL);
-	DBC_ENSURE(intf_fxns->brd_status != NULL);
-	DBC_ENSURE(intf_fxns->brd_read != NULL);
-	DBC_ENSURE(intf_fxns->brd_write != NULL);
-	DBC_ENSURE(intf_fxns->chnl_create != NULL);
-	DBC_ENSURE(intf_fxns->chnl_destroy != NULL);
-	DBC_ENSURE(intf_fxns->chnl_open != NULL);
-	DBC_ENSURE(intf_fxns->chnl_close != NULL);
-	DBC_ENSURE(intf_fxns->chnl_add_io_req != NULL);
-	DBC_ENSURE(intf_fxns->chnl_get_ioc != NULL);
-	DBC_ENSURE(intf_fxns->chnl_cancel_io != NULL);
-	DBC_ENSURE(intf_fxns->chnl_flush_io != NULL);
-	DBC_ENSURE(intf_fxns->chnl_get_info != NULL);
-	DBC_ENSURE(intf_fxns->chnl_get_mgr_info != NULL);
-	DBC_ENSURE(intf_fxns->chnl_idle != NULL);
-	DBC_ENSURE(intf_fxns->chnl_register_notify != NULL);
-	DBC_ENSURE(intf_fxns->io_create != NULL);
-	DBC_ENSURE(intf_fxns->io_destroy != NULL);
-	DBC_ENSURE(intf_fxns->io_on_loaded != NULL);
-	DBC_ENSURE(intf_fxns->io_get_proc_load != NULL);
-	DBC_ENSURE(intf_fxns->msg_set_queue_id != NULL);
-
 #undef  STORE_FXN
 }
diff --git a/drivers/staging/tidspbridge/pmgr/dmm.c b/drivers/staging/tidspbridge/pmgr/dmm.c
index 8685233..7c9f839 100644
--- a/drivers/staging/tidspbridge/pmgr/dmm.c
+++ b/drivers/staging/tidspbridge/pmgr/dmm.c
@@ -28,9 +28,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- OS Adaptation Layer */
 #include <dspbridge/sync.h>
 
@@ -54,8 +51,6 @@
 	spinlock_t dmm_lock;	/* Lock to access dmm mgr */
 };
 
-/*  ----------------------------------- Globals */
-static u32 refs;		/* module reference count */
 struct map_page {
 	u32 region_size:15;
 	u32 mapped_size:15;
@@ -123,8 +118,6 @@
 {
 	struct dmm_object *dmm_obj = NULL;
 	int status = 0;
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(dmm_manager != NULL);
 
 	*dmm_manager = NULL;
 	/* create, zero, and tag a cmm mgr object */
@@ -149,7 +142,6 @@
 	struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
 	if (dmm_mgr) {
 		status = dmm_delete_tables(dmm_obj);
 		if (!status)
@@ -169,7 +161,6 @@
 {
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
 	/* Delete all DMM tables */
 	if (dmm_mgr)
 		vfree(virtual_mapping_table);
@@ -179,19 +170,6 @@
 }
 
 /*
- *  ======== dmm_exit ========
- *  Purpose:
- *      Discontinue usage of module; free resources when reference count
- *      reaches 0.
- */
-void dmm_exit(void)
-{
-	DBC_REQUIRE(refs > 0);
-
-	refs--;
-}
-
-/*
  *  ======== dmm_get_handle ========
  *  Purpose:
  *      Return the dynamic memory manager object for this device.
@@ -202,8 +180,6 @@
 	int status = 0;
 	struct dev_object *hdev_obj;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(dmm_manager != NULL);
 	if (hprocessor != NULL)
 		status = proc_get_dev_object(hprocessor, &hdev_obj);
 	else
@@ -216,28 +192,6 @@
 }
 
 /*
- *  ======== dmm_init ========
- *  Purpose:
- *      Initializes private state of DMM module.
- */
-bool dmm_init(void)
-{
-	bool ret = true;
-
-	DBC_REQUIRE(refs >= 0);
-
-	if (ret)
-		refs++;
-
-	DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
-
-	virtual_mapping_table = NULL;
-	table_size = 0;
-
-	return ret;
-}
-
-/*
  *  ======== dmm_map_memory ========
  *  Purpose:
  *      Add a mapping block to the reserved chunk. DMM assumes that this block
diff --git a/drivers/staging/tidspbridge/pmgr/dspapi.c b/drivers/staging/tidspbridge/pmgr/dspapi.c
index 767ffe2..9ef1ad9 100644
--- a/drivers/staging/tidspbridge/pmgr/dspapi.c
+++ b/drivers/staging/tidspbridge/pmgr/dspapi.c
@@ -24,9 +24,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- OS Adaptation Layer */
 #include <dspbridge/ntfy.h>
 
@@ -266,25 +263,10 @@
  */
 void api_exit(void)
 {
-	DBC_REQUIRE(api_c_refs > 0);
 	api_c_refs--;
 
-	if (api_c_refs == 0) {
-		/* Release all modules initialized in api_init(). */
-		cod_exit();
-		dev_exit();
-		chnl_exit();
-		msg_exit();
-		io_exit();
-		strm_exit();
-		disp_exit();
-		node_exit();
-		proc_exit();
+	if (api_c_refs == 0)
 		mgr_exit();
-		rmm_exit();
-		drv_exit();
-	}
-	DBC_ENSURE(api_c_refs >= 0);
 }
 
 /*
@@ -295,64 +277,10 @@
 bool api_init(void)
 {
 	bool ret = true;
-	bool fdrv, fdev, fcod, fchnl, fmsg, fio;
-	bool fmgr, fproc, fnode, fdisp, fstrm, frmm;
 
-	if (api_c_refs == 0) {
-		/* initialize driver and other modules */
-		fdrv = drv_init();
-		fmgr = mgr_init();
-		fproc = proc_init();
-		fnode = node_init();
-		fdisp = disp_init();
-		fstrm = strm_init();
-		frmm = rmm_init();
-		fchnl = chnl_init();
-		fmsg = msg_mod_init();
-		fio = io_init();
-		fdev = dev_init();
-		fcod = cod_init();
-		ret = fdrv && fdev && fchnl && fcod && fmsg && fio;
-		ret = ret && fmgr && fproc && frmm;
-		if (!ret) {
-			if (fdrv)
-				drv_exit();
+	if (api_c_refs == 0)
+		ret = mgr_init();
 
-			if (fmgr)
-				mgr_exit();
-
-			if (fstrm)
-				strm_exit();
-
-			if (fproc)
-				proc_exit();
-
-			if (fnode)
-				node_exit();
-
-			if (fdisp)
-				disp_exit();
-
-			if (fchnl)
-				chnl_exit();
-
-			if (fmsg)
-				msg_exit();
-
-			if (fio)
-				io_exit();
-
-			if (fdev)
-				dev_exit();
-
-			if (fcod)
-				cod_exit();
-
-			if (frmm)
-				rmm_exit();
-
-		}
-	}
 	if (ret)
 		api_c_refs++;
 
@@ -382,8 +310,6 @@
 	struct drv_data *drv_datap;
 	u8 dev_type;
 
-	DBC_REQUIRE(api_c_refs > 0);
-
 	/*  Walk the list of DevObjects, get each devnode, and attempting to
 	 *  autostart the board. Note that this requires COF loading, which
 	 *  requires KFILE. */
diff --git a/drivers/staging/tidspbridge/pmgr/io.c b/drivers/staging/tidspbridge/pmgr/io.c
index 65245f3..4073c9c 100644
--- a/drivers/staging/tidspbridge/pmgr/io.c
+++ b/drivers/staging/tidspbridge/pmgr/io.c
@@ -23,9 +23,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- Platform Manager */
 #include <dspbridge/dev.h>
 
@@ -33,9 +30,6 @@
 #include <ioobj.h>
 #include <dspbridge/io.h>
 
-/*  ----------------------------------- Globals */
-static u32 refs;
-
 /*
  *  ======== io_create ========
  *  Purpose:
@@ -50,10 +44,6 @@
 	struct io_mgr_ *pio_mgr = NULL;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(io_man != NULL);
-	DBC_REQUIRE(mgr_attrts != NULL);
-
 	*io_man = NULL;
 
 	/* A memory base of 0 implies no memory base: */
@@ -94,8 +84,6 @@
 	struct io_mgr_ *pio_mgr = (struct io_mgr_ *)hio_mgr;
 	int status;
 
-	DBC_REQUIRE(refs > 0);
-
 	intf_fxns = pio_mgr->intf_fxns;
 
 	/* Let Bridge channel module destroy the io_mgr: */
@@ -103,36 +91,3 @@
 
 	return status;
 }
-
-/*
- *  ======== io_exit ========
- *  Purpose:
- *      Discontinue usage of the IO module.
- */
-void io_exit(void)
-{
-	DBC_REQUIRE(refs > 0);
-
-	refs--;
-
-	DBC_ENSURE(refs >= 0);
-}
-
-/*
- *  ======== io_init ========
- *  Purpose:
- *      Initialize the IO module's private state.
- */
-bool io_init(void)
-{
-	bool ret = true;
-
-	DBC_REQUIRE(refs >= 0);
-
-	if (ret)
-		refs++;
-
-	DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
-
-	return ret;
-}
diff --git a/drivers/staging/tidspbridge/pmgr/msg.c b/drivers/staging/tidspbridge/pmgr/msg.c
index a691603..f093cfb 100644
--- a/drivers/staging/tidspbridge/pmgr/msg.c
+++ b/drivers/staging/tidspbridge/pmgr/msg.c
@@ -23,9 +23,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- Bridge Driver */
 #include <dspbridge/dspdefs.h>
 
@@ -36,9 +33,6 @@
 #include <msgobj.h>
 #include <dspbridge/msg.h>
 
-/*  ----------------------------------- Globals */
-static u32 refs;		/* module reference count */
-
 /*
  *  ======== msg_create ========
  *  Purpose:
@@ -53,11 +47,6 @@
 	struct msg_mgr *hmsg_mgr;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(msg_man != NULL);
-	DBC_REQUIRE(msg_callback != NULL);
-	DBC_REQUIRE(hdev_obj != NULL);
-
 	*msg_man = NULL;
 
 	dev_get_intf_fxns(hdev_obj, &intf_fxns);
@@ -90,8 +79,6 @@
 	struct msg_mgr_ *msg_mgr_obj = (struct msg_mgr_ *)hmsg_mgr;
 	struct bridge_drv_interface *intf_fxns;
 
-	DBC_REQUIRE(refs > 0);
-
 	if (msg_mgr_obj) {
 		intf_fxns = msg_mgr_obj->intf_fxns;
 
@@ -102,28 +89,3 @@
 			__func__, hmsg_mgr);
 	}
 }
-
-/*
- *  ======== msg_exit ========
- */
-void msg_exit(void)
-{
-	DBC_REQUIRE(refs > 0);
-	refs--;
-
-	DBC_ENSURE(refs >= 0);
-}
-
-/*
- *  ======== msg_mod_init ========
- */
-bool msg_mod_init(void)
-{
-	DBC_REQUIRE(refs >= 0);
-
-	refs++;
-
-	DBC_ENSURE(refs >= 0);
-
-	return true;
-}
diff --git a/drivers/staging/tidspbridge/rmgr/dbdcd.c b/drivers/staging/tidspbridge/rmgr/dbdcd.c
index fda2402..12a1d34 100644
--- a/drivers/staging/tidspbridge/rmgr/dbdcd.c
+++ b/drivers/staging/tidspbridge/rmgr/dbdcd.c
@@ -29,8 +29,6 @@
 
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
 
 /*  ----------------------------------- Platform Manager */
 #include <dspbridge/cod.h>
@@ -85,8 +83,6 @@
 {
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-
 	if (hdcd_mgr)
 		status = dcd_get_objects(hdcd_mgr, sz_coff_path,
 					 (dcd_registerfxn) dcd_register_object,
@@ -107,8 +103,6 @@
 {
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-
 	if (hdcd_mgr)
 		status = dcd_get_objects(hdcd_mgr, sz_coff_path,
 					 (dcd_registerfxn) dcd_register_object,
@@ -131,9 +125,6 @@
 	struct dcd_manager *dcd_mgr_obj = NULL;	/* DCD Manager pointer */
 	int status = 0;
 
-	DBC_REQUIRE(refs >= 0);
-	DBC_REQUIRE(dcd_mgr);
-
 	status = cod_create(&cod_mgr, sz_zl_dll_name);
 	if (status)
 		goto func_end;
@@ -156,9 +147,6 @@
 		cod_delete(cod_mgr);
 	}
 
-	DBC_ENSURE((!status) ||
-			((dcd_mgr_obj == NULL) && (status == -ENOMEM)));
-
 func_end:
 	return status;
 }
@@ -173,8 +161,6 @@
 	struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
 	int status = -EFAULT;
 
-	DBC_REQUIRE(refs >= 0);
-
 	if (hdcd_mgr) {
 		/* Delete the COD manager. */
 		cod_delete(dcd_mgr_obj->cod_mgr);
@@ -205,10 +191,6 @@
 	struct dcd_key_elem *dcd_key;
 	int len;
 
-	DBC_REQUIRE(refs >= 0);
-	DBC_REQUIRE(index >= 0);
-	DBC_REQUIRE(uuid_obj != NULL);
-
 	if ((index != 0) && (enum_refs == 0)) {
 		/*
 		 * If an enumeration is being performed on an index greater
@@ -222,7 +204,6 @@
 		 *  "_\0" + length of sz_obj_type string + terminating NULL.
 		 */
 		dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
-		DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
 
 		/* Create proper REG key; concatenate DCD_REGKEY with
 		 * obj_type. */
@@ -294,8 +275,6 @@
 		}
 	}
 
-	DBC_ENSURE(uuid_obj || (status == -EPERM));
-
 	return status;
 }
 
@@ -307,11 +286,9 @@
 void dcd_exit(void)
 {
 	struct dcd_key_elem *rv, *rv_tmp;
-	DBC_REQUIRE(refs > 0);
 
 	refs--;
 	if (refs == 0) {
-		cod_exit();
 		list_for_each_entry_safe(rv, rv_tmp, &reg_key_list, link) {
 			list_del(&rv->link);
 			kfree(rv->path);
@@ -319,7 +296,6 @@
 		}
 	}
 
-	DBC_ENSURE(refs >= 0);
 }
 
 /*
@@ -333,12 +309,6 @@
 {
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(hdcd_mgr);
-	DBC_REQUIRE(uuid_obj != NULL);
-	DBC_REQUIRE(dep_lib_uuids != NULL);
-	DBC_REQUIRE(prstnt_dep_libs != NULL);
-
 	status =
 	    get_dep_lib_info(hdcd_mgr, uuid_obj, &num_libs, NULL, dep_lib_uuids,
 			     prstnt_dep_libs, phase);
@@ -356,12 +326,6 @@
 {
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(hdcd_mgr);
-	DBC_REQUIRE(num_libs != NULL);
-	DBC_REQUIRE(num_pers_libs != NULL);
-	DBC_REQUIRE(uuid_obj != NULL);
-
 	status = get_dep_lib_info(hdcd_mgr, uuid_obj, num_libs, num_pers_libs,
 				  NULL, NULL, phase);
 
@@ -393,10 +357,6 @@
 	u32 dw_key_len;		/* Len of REG key. */
 	char sz_obj_type[MAX_INT2CHAR_LENGTH];	/* str. rep. of obj_type. */
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(obj_def != NULL);
-	DBC_REQUIRE(obj_uuid != NULL);
-
 	sz_uuid = kzalloc(MAXUUIDLEN, GFP_KERNEL);
 	if (!sz_uuid) {
 		status = -ENOMEM;
@@ -411,7 +371,6 @@
 	/* Pre-determine final key length. It's length of DCD_REGKEY +
 	 *  "_\0" + length of sz_obj_type string + terminating NULL */
 	dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
-	DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
 
 	/* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
 	strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
@@ -470,7 +429,6 @@
 	}
 
 	/* Ensure sz_uuid + 1 is not greater than sizeof sz_sect_name. */
-	DBC_ASSERT((strlen(sz_uuid) + 1) < sizeof(sz_sect_name));
 
 	/* Create section name based on node UUID. A period is
 	 * pre-pended to the UUID string to form the section name.
@@ -553,7 +511,6 @@
 	struct dsp_uuid dsp_uuid_obj;
 	s32 object_type;
 
-	DBC_REQUIRE(refs > 0);
 	if (!hdcd_mgr) {
 		status = -EFAULT;
 		goto func_end;
@@ -663,11 +620,6 @@
 	int status = 0;
 	struct dcd_key_elem *dcd_key = NULL;
 
-	DBC_REQUIRE(uuid_obj != NULL);
-	DBC_REQUIRE(str_lib_name != NULL);
-	DBC_REQUIRE(buff_size != NULL);
-	DBC_REQUIRE(hdcd_mgr);
-
 	dev_dbg(bridge, "%s: hdcd_mgr %p, uuid_obj %p, str_lib_name %p,"
 		" buff_size %p\n", __func__, hdcd_mgr, uuid_obj, str_lib_name,
 		buff_size);
@@ -677,7 +629,6 @@
 	 *  "_\0" + length of sz_obj_type string + terminating NULL.
 	 */
 	dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
-	DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
 
 	/* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
 	strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
@@ -705,7 +656,6 @@
 		break;
 	default:
 		status = -EINVAL;
-		DBC_ASSERT(false);
 	}
 	if (!status) {
 		if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
@@ -787,30 +737,14 @@
  */
 bool dcd_init(void)
 {
-	bool init_cod;
 	bool ret = true;
 
-	DBC_REQUIRE(refs >= 0);
-
-	if (refs == 0) {
-		/* Initialize required modules. */
-		init_cod = cod_init();
-
-		if (!init_cod) {
-			ret = false;
-			/* Exit initialized modules. */
-			if (init_cod)
-				cod_exit();
-		}
-
+	if (refs == 0)
 		INIT_LIST_HEAD(&reg_key_list);
-	}
 
 	if (ret)
 		refs++;
 
-	DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs == 0)));
-
 	return ret;
 }
 
@@ -832,15 +766,6 @@
 	char sz_obj_type[MAX_INT2CHAR_LENGTH];	/* str. rep. of obj_type. */
 	struct dcd_key_elem *dcd_key = NULL;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(uuid_obj != NULL);
-	DBC_REQUIRE((obj_type == DSP_DCDNODETYPE) ||
-		    (obj_type == DSP_DCDPROCESSORTYPE) ||
-		    (obj_type == DSP_DCDLIBRARYTYPE) ||
-		    (obj_type == DSP_DCDCREATELIBTYPE) ||
-		    (obj_type == DSP_DCDEXECUTELIBTYPE) ||
-		    (obj_type == DSP_DCDDELETELIBTYPE));
-
 	dev_dbg(bridge, "%s: object UUID %p, obj_type %d, szPathName %s\n",
 		__func__, uuid_obj, obj_type, psz_path_name);
 
@@ -849,7 +774,6 @@
 	 *  "_\0" + length of sz_obj_type string + terminating NULL.
 	 */
 	dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
-	DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
 
 	/* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
 	strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
@@ -987,15 +911,6 @@
 {
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(uuid_obj != NULL);
-	DBC_REQUIRE((obj_type == DSP_DCDNODETYPE) ||
-		    (obj_type == DSP_DCDPROCESSORTYPE) ||
-		    (obj_type == DSP_DCDLIBRARYTYPE) ||
-		    (obj_type == DSP_DCDCREATELIBTYPE) ||
-		    (obj_type == DSP_DCDEXECUTELIBTYPE) ||
-		    (obj_type == DSP_DCDDELETELIBTYPE));
-
 	/*
 	 *  When dcd_register_object is called with NULL as pathname,
 	 *  it indicates an unregister object operation.
@@ -1055,12 +970,6 @@
 	s32 entry_id;
 #endif
 
-	DBC_REQUIRE(psz_buf != NULL);
-	DBC_REQUIRE(ul_buf_size != 0);
-	DBC_REQUIRE((obj_type == DSP_DCDNODETYPE)
-		    || (obj_type == DSP_DCDPROCESSORTYPE));
-	DBC_REQUIRE(gen_obj != NULL);
-
 	switch (obj_type) {
 	case DSP_DCDNODETYPE:
 		/*
@@ -1082,7 +991,6 @@
 		token = strsep(&psz_cur, seps);
 
 		/* ac_name */
-		DBC_REQUIRE(token);
 		token_len = strlen(token);
 		if (token_len > DSP_MAXNAMELEN - 1)
 			token_len = DSP_MAXNAMELEN - 1;
@@ -1167,7 +1075,6 @@
 		token = strsep(&psz_cur, seps);
 
 		/* char *str_create_phase_fxn */
-		DBC_REQUIRE(token);
 		token_len = strlen(token);
 		gen_obj->obj_data.node_obj.str_create_phase_fxn =
 					kzalloc(token_len + 1, GFP_KERNEL);
@@ -1178,7 +1085,6 @@
 		token = strsep(&psz_cur, seps);
 
 		/* char *str_execute_phase_fxn */
-		DBC_REQUIRE(token);
 		token_len = strlen(token);
 		gen_obj->obj_data.node_obj.str_execute_phase_fxn =
 					kzalloc(token_len + 1, GFP_KERNEL);
@@ -1189,7 +1095,6 @@
 		token = strsep(&psz_cur, seps);
 
 		/* char *str_delete_phase_fxn */
-		DBC_REQUIRE(token);
 		token_len = strlen(token);
 		gen_obj->obj_data.node_obj.str_delete_phase_fxn =
 					kzalloc(token_len + 1, GFP_KERNEL);
@@ -1421,12 +1326,6 @@
 	u16 dep_libs = 0;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-
-	DBC_REQUIRE(hdcd_mgr);
-	DBC_REQUIRE(num_libs != NULL);
-	DBC_REQUIRE(uuid_obj != NULL);
-
 	/*  Initialize to 0 dependent libraries, if only counting number of
 	 *  dependent libraries */
 	if (!get_uuids) {
diff --git a/drivers/staging/tidspbridge/rmgr/disp.c b/drivers/staging/tidspbridge/rmgr/disp.c
index a9aa22f..4af51b7 100644
--- a/drivers/staging/tidspbridge/rmgr/disp.c
+++ b/drivers/staging/tidspbridge/rmgr/disp.c
@@ -24,9 +24,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- OS Adaptation Layer */
 #include <dspbridge/sync.h>
 
@@ -72,8 +69,6 @@
 	u32 data_mau_size;	/* Size of DSP Data MAU */
 };
 
-static u32 refs;
-
 static void delete_disp(struct disp_object *disp_obj);
 static int fill_stream_def(rms_word *pdw_buf, u32 *ptotal, u32 offset,
 				  struct node_strmdef strm_def, u32 max,
@@ -96,11 +91,6 @@
 	int status = 0;
 	u8 dev_type;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(dispatch_obj != NULL);
-	DBC_REQUIRE(disp_attrs != NULL);
-	DBC_REQUIRE(hdev_obj != NULL);
-
 	*dispatch_obj = NULL;
 
 	/* Allocate Node Dispatcher object */
@@ -168,8 +158,6 @@
 	else
 		delete_disp(disp_obj);
 
-	DBC_ENSURE((status && *dispatch_obj == NULL) ||
-				(!status && *dispatch_obj));
 	return status;
 }
 
@@ -179,43 +167,10 @@
  */
 void disp_delete(struct disp_object *disp_obj)
 {
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(disp_obj);
-
 	delete_disp(disp_obj);
 }
 
 /*
- *  ======== disp_exit ========
- *  Discontinue usage of DISP module.
- */
-void disp_exit(void)
-{
-	DBC_REQUIRE(refs > 0);
-
-	refs--;
-
-	DBC_ENSURE(refs >= 0);
-}
-
-/*
- *  ======== disp_init ========
- *  Initialize the DISP module.
- */
-bool disp_init(void)
-{
-	bool ret = true;
-
-	DBC_REQUIRE(refs >= 0);
-
-	if (ret)
-		refs++;
-
-	DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
-	return ret;
-}
-
-/*
  *  ======== disp_node_change_priority ========
  *  Change the priority of a node currently running on the target.
  */
@@ -227,10 +182,6 @@
 	struct rms_command *rms_cmd;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(disp_obj);
-	DBC_REQUIRE(hnode != NULL);
-
 	/* Send message to RMS to change priority */
 	rms_cmd = (struct rms_command *)(disp_obj->buf);
 	rms_cmd->fxn = (rms_word) (rms_fxn);
@@ -276,12 +227,6 @@
 	struct dsp_nodeinfo node_info;
 	u8 dev_type;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(disp_obj);
-	DBC_REQUIRE(hnode != NULL);
-	DBC_REQUIRE(node_get_type(hnode) != NODE_DEVICE);
-	DBC_REQUIRE(node_env != NULL);
-
 	status = dev_get_dev_type(disp_obj->dev_obj, &dev_type);
 
 	if (status)
@@ -292,11 +237,9 @@
 			__func__, dev_type);
 		goto func_end;
 	}
-	DBC_REQUIRE(pargs != NULL);
 	node_type = node_get_type(hnode);
 	node_msg_args = pargs->asa.node_msg_args;
 	max = disp_obj->bufsize_rms;	/*Max # of RMS words that can be sent */
-	DBC_ASSERT(max == RMS_COMMANDBUFSIZE);
 	chars_in_rms_word = sizeof(rms_word) / disp_obj->char_size;
 	/* Number of RMS words needed to hold arg data */
 	dw_length =
@@ -457,7 +400,6 @@
 	}
 	if (!status) {
 		ul_bytes = total * sizeof(rms_word);
-		DBC_ASSERT(ul_bytes < (RMS_COMMANDBUFSIZE * sizeof(rms_word)));
 		status = send_message(disp_obj, node_get_timeout(hnode),
 				      ul_bytes, node_env);
 	}
@@ -480,10 +422,6 @@
 	int status = 0;
 	u8 dev_type;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(disp_obj);
-	DBC_REQUIRE(hnode != NULL);
-
 	status = dev_get_dev_type(disp_obj->dev_obj, &dev_type);
 
 	if (!status) {
@@ -521,9 +459,6 @@
 	struct rms_command *rms_cmd;
 	int status = 0;
 	u8 dev_type;
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(disp_obj);
-	DBC_REQUIRE(hnode != NULL);
 
 	status = dev_get_dev_type(disp_obj->dev_obj, &dev_type);
 
@@ -620,7 +555,6 @@
 		 *  1 from total.
 		 */
 		total += sizeof(struct rms_strm_def) / sizeof(rms_word) - 1;
-		DBC_REQUIRE(strm_def.sz_device);
 		dw_length = strlen(strm_def.sz_device) + 1;
 
 		/* Number of RMS_WORDS needed to hold device name */
@@ -659,8 +593,6 @@
 	struct chnl_ioc chnl_ioc_obj;
 	int status = 0;
 
-	DBC_REQUIRE(pdw_arg != NULL);
-
 	*pdw_arg = (u32) NULL;
 	intf_fxns = disp_obj->intf_fxns;
 	chnl_obj = disp_obj->chnl_to_dsp;
@@ -703,7 +635,6 @@
 			status = -EPERM;
 		} else {
 			if (CHNL_IS_IO_COMPLETE(chnl_ioc_obj)) {
-				DBC_ASSERT(chnl_ioc_obj.buf == pbuf);
 				if (*((int *)chnl_ioc_obj.buf) < 0) {
 					/* Translate DSP's to kernel error */
 					status = -EREMOTEIO;
diff --git a/drivers/staging/tidspbridge/rmgr/drv.c b/drivers/staging/tidspbridge/rmgr/drv.c
index db8215f..6795205 100644
--- a/drivers/staging/tidspbridge/rmgr/drv.c
+++ b/drivers/staging/tidspbridge/rmgr/drv.c
@@ -24,9 +24,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- This */
 #include <dspbridge/drv.h>
 #include <dspbridge/dev.h>
@@ -54,7 +51,6 @@
 };
 
 /*  ----------------------------------- Globals */
-static s32 refs;
 static bool ext_phys_mem_pool_enabled;
 struct ext_phys_mem_pool {
 	u32 phys_mem_base;
@@ -172,7 +168,6 @@
 {
 	struct node_res_object *node_res_obj =
 	    (struct node_res_object *)node_resource;
-	DBC_ASSERT(node_resource != NULL);
 	node_res_obj->node_allocated = status;
 }
 
@@ -181,7 +176,6 @@
 {
 	struct node_res_object *node_res_obj =
 	    (struct node_res_object *)node_resource;
-	DBC_ASSERT(node_resource != NULL);
 	node_res_obj->heap_allocated = status;
 }
 
@@ -308,9 +302,6 @@
 	struct drv_object *pdrv_object = NULL;
 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
 
-	DBC_REQUIRE(drv_obj != NULL);
-	DBC_REQUIRE(refs > 0);
-
 	pdrv_object = kzalloc(sizeof(struct drv_object), GFP_KERNEL);
 	if (pdrv_object) {
 		/* Create and Initialize List of device objects */
@@ -336,25 +327,10 @@
 		kfree(pdrv_object);
 	}
 
-	DBC_ENSURE(status || pdrv_object);
 	return status;
 }
 
 /*
- *  ======== drv_exit ========
- *  Purpose:
- *      Discontinue usage of the DRV module.
- */
-void drv_exit(void)
-{
-	DBC_REQUIRE(refs > 0);
-
-	refs--;
-
-	DBC_ENSURE(refs >= 0);
-}
-
-/*
  *  ======== = drv_destroy ======== =
  *  purpose:
  *      Invoked during bridge de-initialization
@@ -365,9 +341,6 @@
 	struct drv_object *pdrv_object = (struct drv_object *)driver_obj;
 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(pdrv_object);
-
 	kfree(pdrv_object);
 	/* Update the DRV Object in the driver data */
 	if (drv_datap) {
@@ -389,17 +362,8 @@
 			      struct dev_object **device_obj)
 {
 	int status = 0;
-#ifdef CONFIG_TIDSPBRIDGE_DEBUG
-	/* used only for Assertions and debug messages */
-	struct drv_object *pdrv_obj = (struct drv_object *)hdrv_obj;
-#endif
 	struct dev_object *dev_obj;
 	u32 i;
-	DBC_REQUIRE(pdrv_obj);
-	DBC_REQUIRE(device_obj != NULL);
-	DBC_REQUIRE(index >= 0);
-	DBC_REQUIRE(refs > 0);
-	DBC_ASSERT(!(list_empty(&pdrv_obj->dev_list)));
 
 	dev_obj = (struct dev_object *)drv_get_first_dev_object();
 	for (i = 0; i < index; i++) {
@@ -524,25 +488,6 @@
 }
 
 /*
- *  ======== drv_init ========
- *  Purpose:
- *      Initialize DRV module private state.
- */
-int drv_init(void)
-{
-	s32 ret = 1;		/* function return value */
-
-	DBC_REQUIRE(refs >= 0);
-
-	if (ret)
-		refs++;
-
-	DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
-
-	return ret;
-}
-
-/*
  *  ======== drv_insert_dev_object ========
  *  Purpose:
  *      Insert a DevObject into the list of Manager object.
@@ -552,10 +497,6 @@
 {
 	struct drv_object *pdrv_object = (struct drv_object *)driver_obj;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(hdev_obj != NULL);
-	DBC_REQUIRE(pdrv_object);
-
 	list_add_tail((struct list_head *)hdev_obj, &pdrv_object->dev_list);
 
 	return 0;
@@ -574,12 +515,6 @@
 	struct drv_object *pdrv_object = (struct drv_object *)driver_obj;
 	struct list_head *cur_elem;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(pdrv_object);
-	DBC_REQUIRE(hdev_obj != NULL);
-
-	DBC_REQUIRE(!list_empty(&pdrv_object->dev_list));
-
 	/* Search list for p_proc_object: */
 	list_for_each(cur_elem, &pdrv_object->dev_list) {
 		/* If found, remove it. */
@@ -605,9 +540,6 @@
 	struct drv_ext *pszdev_node;
 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
 
-	DBC_REQUIRE(dw_context != 0);
-	DBC_REQUIRE(dev_node_strg != NULL);
-
 	/*
 	 *  Allocate memory to hold the string. This will live until
 	 *  it is freed in the Release resources. Update the driver object
@@ -639,10 +571,6 @@
 		*dev_node_strg = 0;
 	}
 
-	DBC_ENSURE((!status && dev_node_strg != NULL &&
-		    !list_empty(&pdrv_object->dev_node_string)) ||
-		   (status && *dev_node_strg == 0));
-
 	return status;
 }
 
@@ -900,8 +828,6 @@
 void mem_free_phys_mem(void *virtual_address, u32 physical_address,
 		       u32 byte_size)
 {
-	DBC_REQUIRE(virtual_address != NULL);
-
 	if (!ext_phys_mem_pool_enabled)
 		dma_free_coherent(NULL, byte_size, virtual_address,
 				  physical_address);
diff --git a/drivers/staging/tidspbridge/rmgr/drv_interface.c b/drivers/staging/tidspbridge/rmgr/drv_interface.c
index 385740b..3cac014 100644
--- a/drivers/staging/tidspbridge/rmgr/drv_interface.c
+++ b/drivers/staging/tidspbridge/rmgr/drv_interface.c
@@ -16,11 +16,8 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-/*  ----------------------------------- Host OS */
-
 #include <plat/dsp.h>
 
-#include <dspbridge/host_os.h>
 #include <linux/types.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
@@ -33,36 +30,25 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- OS Adaptation Layer */
 #include <dspbridge/clk.h>
-#include <dspbridge/sync.h>
 
 /*  ----------------------------------- Platform Manager */
-#include <dspbridge/dspapi-ioctl.h>
 #include <dspbridge/dspapi.h>
 #include <dspbridge/dspdrv.h>
 
 /*  ----------------------------------- Resource Manager */
 #include <dspbridge/pwr.h>
 
-/*  ----------------------------------- This */
-#include <drv_interface.h>
-
 #include <dspbridge/resourcecleanup.h>
-#include <dspbridge/chnl.h>
 #include <dspbridge/proc.h>
 #include <dspbridge/dev.h>
-#include <dspbridge/drv.h>
 
 #ifdef CONFIG_TIDSPBRIDGE_DVFS
 #include <mach-omap2/omap3-opp.h>
 #endif
 
 /*  ----------------------------------- Globals */
-#define DRIVER_NAME  "DspBridge"
 #define DSPBRIDGE_VERSION	"0.3"
 s32 dsp_debug;
 
@@ -131,7 +117,166 @@
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DSPBRIDGE_VERSION);
 
-static char *driver_name = DRIVER_NAME;
+/*
+ * This function is called when an application opens handle to the
+ * bridge driver.
+ */
+static int bridge_open(struct inode *ip, struct file *filp)
+{
+	int status = 0;
+	struct process_context *pr_ctxt = NULL;
+
+	/*
+	 * Allocate a new process context and insert it into global
+	 * process context list.
+	 */
+
+#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
+	if (recover) {
+		if (filp->f_flags & O_NONBLOCK ||
+		    wait_for_completion_interruptible(&bridge_open_comp))
+			return -EBUSY;
+	}
+#endif
+	pr_ctxt = kzalloc(sizeof(struct process_context), GFP_KERNEL);
+	if (!pr_ctxt)
+		return -ENOMEM;
+
+	pr_ctxt->res_state = PROC_RES_ALLOCATED;
+	spin_lock_init(&pr_ctxt->dmm_map_lock);
+	INIT_LIST_HEAD(&pr_ctxt->dmm_map_list);
+	spin_lock_init(&pr_ctxt->dmm_rsv_lock);
+	INIT_LIST_HEAD(&pr_ctxt->dmm_rsv_list);
+
+	pr_ctxt->node_id = kzalloc(sizeof(struct idr), GFP_KERNEL);
+	if (!pr_ctxt->node_id) {
+		status = -ENOMEM;
+		goto err1;
+	}
+
+	idr_init(pr_ctxt->node_id);
+
+	pr_ctxt->stream_id = kzalloc(sizeof(struct idr), GFP_KERNEL);
+	if (!pr_ctxt->stream_id) {
+		status = -ENOMEM;
+		goto err2;
+	}
+
+	idr_init(pr_ctxt->stream_id);
+
+	filp->private_data = pr_ctxt;
+
+#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
+	atomic_inc(&bridge_cref);
+#endif
+	return 0;
+
+err2:
+	kfree(pr_ctxt->node_id);
+err1:
+	kfree(pr_ctxt);
+	return status;
+}
+
+/*
+ * This function is called when an application closes handle to the bridge
+ * driver.
+ */
+static int bridge_release(struct inode *ip, struct file *filp)
+{
+	int status = 0;
+	struct process_context *pr_ctxt;
+
+	if (!filp->private_data) {
+		status = -EIO;
+		goto err;
+	}
+
+	pr_ctxt = filp->private_data;
+	flush_signals(current);
+	drv_remove_all_resources(pr_ctxt);
+	proc_detach(pr_ctxt);
+	kfree(pr_ctxt->node_id);
+	kfree(pr_ctxt->stream_id);
+	kfree(pr_ctxt);
+
+	filp->private_data = NULL;
+
+err:
+#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
+	if (!atomic_dec_return(&bridge_cref))
+		complete(&bridge_comp);
+#endif
+	return status;
+}
+
+/* This function provides IO interface to the bridge driver. */
+static long bridge_ioctl(struct file *filp, unsigned int code,
+			 unsigned long args)
+{
+	int status;
+	u32 retval = 0;
+	union trapped_args buf_in;
+
+#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
+	if (recover) {
+		status = -EIO;
+		goto err;
+	}
+#endif
+#ifdef CONFIG_PM
+	status = omap34_xxbridge_suspend_lockout(&bridge_suspend_data, filp);
+	if (status != 0)
+		return status;
+#endif
+
+	if (!filp->private_data) {
+		status = -EIO;
+		goto err;
+	}
+
+	status = copy_from_user(&buf_in, (union trapped_args *)args,
+				sizeof(union trapped_args));
+
+	if (!status) {
+		status = api_call_dev_ioctl(code, &buf_in, &retval,
+					    filp->private_data);
+
+		if (!status) {
+			status = retval;
+		} else {
+			dev_dbg(bridge, "%s: IOCTL Failed, code: 0x%x "
+				"status 0x%x\n", __func__, code, status);
+			status = -1;
+		}
+
+	}
+
+err:
+	return status;
+}
+
+/* This function maps kernel space memory to user space memory. */
+static int bridge_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	u32 status;
+
+	vma->vm_flags |= VM_RESERVED | VM_IO;
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	dev_dbg(bridge, "%s: vm filp %p start %lx end %lx page_prot %ulx "
+		"flags %lx\n", __func__, filp,
+		vma->vm_start, vma->vm_end, vma->vm_page_prot,
+		vma->vm_flags);
+
+	status = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+				 vma->vm_end - vma->vm_start,
+				 vma->vm_page_prot);
+	if (status != 0)
+		status = -EAGAIN;
+
+	return status;
+}
 
 static const struct file_operations bridge_fops = {
 	.open = bridge_open,
@@ -211,10 +356,10 @@
 #endif
 #ifdef CONFIG_TIDSPBRIDGE_DVFS
 static int dspbridge_scale_notification(struct notifier_block *op,
-		unsigned long val, void *ptr)
+					unsigned long val, void *ptr)
 {
 	struct omap_dsp_platform_data *pdata =
-		omap_dspbridge_dev->dev.platform_data;
+	    omap_dspbridge_dev->dev.platform_data;
 
 	if (CPUFREQ_POSTCHANGE == val && pdata->dsp_get_opp)
 		pwr_pm_post_scale(PRCM_VDD1, pdata->dsp_get_opp());
@@ -319,7 +464,7 @@
 err1:
 #ifdef CONFIG_TIDSPBRIDGE_DVFS
 	cpufreq_unregister_notifier(&iva_clk_notifier,
-					CPUFREQ_TRANSITION_NOTIFIER);
+				    CPUFREQ_TRANSITION_NOTIFIER);
 #endif
 	dsp_clk_exit();
 
@@ -345,7 +490,7 @@
 		goto err1;
 
 	/* use 2.6 device model */
-	err = alloc_chrdev_region(&dev, 0, 1, driver_name);
+	err = alloc_chrdev_region(&dev, 0, 1, "DspBridge");
 	if (err) {
 		pr_err("%s: Can't get major %d\n", __func__, driver_major);
 		goto err1;
@@ -385,7 +530,6 @@
 static int __devexit omap34_xx_bridge_remove(struct platform_device *pdev)
 {
 	dev_t devno;
-	bool ret;
 	int status = 0;
 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
 
@@ -398,16 +542,15 @@
 
 #ifdef CONFIG_TIDSPBRIDGE_DVFS
 	if (cpufreq_unregister_notifier(&iva_clk_notifier,
-						CPUFREQ_TRANSITION_NOTIFIER))
+					CPUFREQ_TRANSITION_NOTIFIER))
 		pr_err("%s: cpufreq_unregister_notifier failed for iva2_ck\n",
 		       __func__);
 #endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */
 
 	if (driver_context) {
 		/* Put the DSP in reset state */
-		ret = dsp_deinit(driver_context);
+		dsp_deinit(driver_context);
 		driver_context = 0;
-		DBC_ASSERT(ret == true);
 	}
 
 	kfree(drv_datap);
@@ -431,7 +574,7 @@
 }
 
 #ifdef CONFIG_PM
-static int BRIDGE_SUSPEND(struct platform_device *pdev, pm_message_t state)
+static int bridge_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	u32 status;
 	u32 command = PWR_EMERGENCYDEEPSLEEP;
@@ -444,7 +587,7 @@
 	return 0;
 }
 
-static int BRIDGE_RESUME(struct platform_device *pdev)
+static int bridge_resume(struct platform_device *pdev)
 {
 	u32 status;
 
@@ -456,9 +599,6 @@
 	wake_up(&bridge_suspend_data.suspend_wq);
 	return 0;
 }
-#else
-#define BRIDGE_SUSPEND NULL
-#define BRIDGE_RESUME NULL
 #endif
 
 static struct platform_driver bridge_driver = {
@@ -467,8 +607,10 @@
 		   },
 	.probe = omap34_xx_bridge_probe,
 	.remove = __devexit_p(omap34_xx_bridge_remove),
-	.suspend = BRIDGE_SUSPEND,
-	.resume = BRIDGE_RESUME,
+#ifdef CONFIG_PM
+	.suspend = bridge_suspend,
+	.resume = bridge_resume,
+#endif
 };
 
 static int __init bridge_init(void)
@@ -481,170 +623,6 @@
 	platform_driver_unregister(&bridge_driver);
 }
 
-/*
- * This function is called when an application opens handle to the
- * bridge driver.
- */
-static int bridge_open(struct inode *ip, struct file *filp)
-{
-	int status = 0;
-	struct process_context *pr_ctxt = NULL;
-
-	/*
-	 * Allocate a new process context and insert it into global
-	 * process context list.
-	 */
-
-#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
-	if (recover) {
-		if (filp->f_flags & O_NONBLOCK ||
-			wait_for_completion_interruptible(&bridge_open_comp))
-			return -EBUSY;
-	}
-#endif
-	pr_ctxt = kzalloc(sizeof(struct process_context), GFP_KERNEL);
-	if (!pr_ctxt)
-		return -ENOMEM;
-
-	pr_ctxt->res_state = PROC_RES_ALLOCATED;
-	spin_lock_init(&pr_ctxt->dmm_map_lock);
-	INIT_LIST_HEAD(&pr_ctxt->dmm_map_list);
-	spin_lock_init(&pr_ctxt->dmm_rsv_lock);
-	INIT_LIST_HEAD(&pr_ctxt->dmm_rsv_list);
-
-	pr_ctxt->node_id = kzalloc(sizeof(struct idr), GFP_KERNEL);
-	if (!pr_ctxt->node_id) {
-		status = -ENOMEM;
-		goto err1;
-	}
-
-	idr_init(pr_ctxt->node_id);
-
-	pr_ctxt->stream_id = kzalloc(sizeof(struct idr), GFP_KERNEL);
-	if (!pr_ctxt->stream_id) {
-		status = -ENOMEM;
-		goto err2;
-	}
-
-	idr_init(pr_ctxt->stream_id);
-
-	filp->private_data = pr_ctxt;
-
-#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
-	atomic_inc(&bridge_cref);
-#endif
-	return 0;
-
-err2:
-	kfree(pr_ctxt->node_id);
-err1:
-	kfree(pr_ctxt);
-	return status;
-}
-
-/*
- * This function is called when an application closes handle to the bridge
- * driver.
- */
-static int bridge_release(struct inode *ip, struct file *filp)
-{
-	int status = 0;
-	struct process_context *pr_ctxt;
-
-	if (!filp->private_data) {
-		status = -EIO;
-		goto err;
-	}
-
-	pr_ctxt = filp->private_data;
-	flush_signals(current);
-	drv_remove_all_resources(pr_ctxt);
-	proc_detach(pr_ctxt);
-	kfree(pr_ctxt->node_id);
-	kfree(pr_ctxt->stream_id);
-	kfree(pr_ctxt);
-
-	filp->private_data = NULL;
-
-err:
-#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
-	if (!atomic_dec_return(&bridge_cref))
-		complete(&bridge_comp);
-#endif
-	return status;
-}
-
-/* This function provides IO interface to the bridge driver. */
-static long bridge_ioctl(struct file *filp, unsigned int code,
-			 unsigned long args)
-{
-	int status;
-	u32 retval = 0;
-	union trapped_args buf_in;
-
-	DBC_REQUIRE(filp != NULL);
-#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
-	if (recover) {
-		status = -EIO;
-		goto err;
-	}
-#endif
-#ifdef CONFIG_PM
-	status = omap34_xxbridge_suspend_lockout(&bridge_suspend_data, filp);
-	if (status != 0)
-		return status;
-#endif
-
-	if (!filp->private_data) {
-		status = -EIO;
-		goto err;
-	}
-
-	status = copy_from_user(&buf_in, (union trapped_args *)args,
-				sizeof(union trapped_args));
-
-	if (!status) {
-		status = api_call_dev_ioctl(code, &buf_in, &retval,
-					     filp->private_data);
-
-		if (!status) {
-			status = retval;
-		} else {
-			dev_dbg(bridge, "%s: IOCTL Failed, code: 0x%x "
-				"status 0x%x\n", __func__, code, status);
-			status = -1;
-		}
-
-	}
-
-err:
-	return status;
-}
-
-/* This function maps kernel space memory to user space memory. */
-static int bridge_mmap(struct file *filp, struct vm_area_struct *vma)
-{
-	u32 offset = vma->vm_pgoff << PAGE_SHIFT;
-	u32 status;
-
-	DBC_ASSERT(vma->vm_start < vma->vm_end);
-
-	vma->vm_flags |= VM_RESERVED | VM_IO;
-	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
-	dev_dbg(bridge, "%s: vm filp %p offset %x start %lx end %lx page_prot "
-		"%lx flags %lx\n", __func__, filp, offset,
-		vma->vm_start, vma->vm_end, vma->vm_page_prot, vma->vm_flags);
-
-	status = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
-				 vma->vm_end - vma->vm_start,
-				 vma->vm_page_prot);
-	if (status != 0)
-		status = -EAGAIN;
-
-	return status;
-}
-
 /* To remove all process resources before removing the process from the
  * process context list */
 int drv_remove_all_resources(void *process_ctxt)
diff --git a/drivers/staging/tidspbridge/rmgr/drv_interface.h b/drivers/staging/tidspbridge/rmgr/drv_interface.h
deleted file mode 100644
index ab07060..0000000
--- a/drivers/staging/tidspbridge/rmgr/drv_interface.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * drv_interface.h
- *
- * DSP-BIOS Bridge driver support functions for TI OMAP processors.
- *
- * Copyright (C) 2005-2006 Texas Instruments, Inc.
- *
- * This package 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.
- *
- * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#ifndef	_DRV_INTERFACE_H_
-#define _DRV_INTERFACE_H_
-
-/* Prototypes for all functions in this bridge */
-static int __init bridge_init(void);	/* Initialize bridge */
-static void __exit bridge_exit(void);	/* Opposite of initialize */
-static int bridge_open(struct inode *ip, struct file *filp);	/* Open */
-static int bridge_release(struct inode *ip, struct file *filp);	/* Release */
-static long bridge_ioctl(struct file *filp, unsigned int code,
-				unsigned long args);
-static int bridge_mmap(struct file *filp, struct vm_area_struct *vma);
-#endif /* ifndef _DRV_INTERFACE_H_ */
diff --git a/drivers/staging/tidspbridge/rmgr/dspdrv.c b/drivers/staging/tidspbridge/rmgr/dspdrv.c
index 7a6fc73..dc767b1 100644
--- a/drivers/staging/tidspbridge/rmgr/dspdrv.c
+++ b/drivers/staging/tidspbridge/rmgr/dspdrv.c
@@ -23,9 +23,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- Platform Manager */
 #include <dspbridge/drv.h>
 #include <dspbridge/dev.h>
@@ -102,8 +99,6 @@
 	} else {
 		dev_dbg(bridge, "%s: Failed\n", __func__);
 	}			/* End api_init_complete2 */
-	DBC_ENSURE((!status && drv_obj != NULL) ||
-		   (status && drv_obj == NULL));
 	*init_status = status;
 	/* Return the Driver Object */
 	return (u32) drv_obj;
diff --git a/drivers/staging/tidspbridge/rmgr/mgr.c b/drivers/staging/tidspbridge/rmgr/mgr.c
index d635c01..8a1e928 100644
--- a/drivers/staging/tidspbridge/rmgr/mgr.c
+++ b/drivers/staging/tidspbridge/rmgr/mgr.c
@@ -26,9 +26,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- OS Adaptation Layer */
 #include <dspbridge/sync.h>
 
@@ -62,9 +59,6 @@
 	struct mgr_object *pmgr_obj = NULL;
 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
 
-	DBC_REQUIRE(mgr_obj != NULL);
-	DBC_REQUIRE(refs > 0);
-
 	pmgr_obj = kzalloc(sizeof(struct mgr_object), GFP_KERNEL);
 	if (pmgr_obj) {
 		status = dcd_create_manager(ZLDLLNAME, &pmgr_obj->dcd_mgr);
@@ -92,7 +86,6 @@
 		status = -ENOMEM;
 	}
 
-	DBC_ENSURE(status || pmgr_obj);
 	return status;
 }
 
@@ -106,9 +99,6 @@
 	struct mgr_object *pmgr_obj = (struct mgr_object *)hmgr_obj;
 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(hmgr_obj);
-
 	/* Free resources */
 	if (hmgr_obj->dcd_mgr)
 		dcd_destroy_manager(hmgr_obj->dcd_mgr);
@@ -140,11 +130,6 @@
 	struct mgr_object *pmgr_obj = NULL;
 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
 
-	DBC_REQUIRE(pndb_props != NULL);
-	DBC_REQUIRE(pu_num_nodes != NULL);
-	DBC_REQUIRE(undb_props_size >= sizeof(struct dsp_ndbprops));
-	DBC_REQUIRE(refs > 0);
-
 	*pu_num_nodes = 0;
 	/* Get the Manager Object from the driver data */
 	if (!drv_datap || !drv_datap->mgr_object) {
@@ -153,7 +138,6 @@
 	}
 	pmgr_obj = drv_datap->mgr_object;
 
-	DBC_ASSERT(pmgr_obj);
 	/* Forever loop till we hit failed or no more items in the
 	 * Enumeration. We will exit the loop other than 0; */
 	while (!status) {
@@ -205,11 +189,6 @@
 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
 	bool proc_detect = false;
 
-	DBC_REQUIRE(processor_info != NULL);
-	DBC_REQUIRE(pu_num_procs != NULL);
-	DBC_REQUIRE(processor_info_size >= sizeof(struct dsp_processorinfo));
-	DBC_REQUIRE(refs > 0);
-
 	*pu_num_procs = 0;
 
 	/* Retrieve the Object handle from the driver data */
@@ -242,7 +221,6 @@
 		dev_dbg(bridge, "%s: Failed to get MGR Object\n", __func__);
 		goto func_end;
 	}
-	DBC_ASSERT(pmgr_obj);
 	/* Forever loop till we hit no more items in the
 	 * Enumeration. We will exit the loop other than 0; */
 	while (status1 == 0) {
@@ -310,12 +288,9 @@
  */
 void mgr_exit(void)
 {
-	DBC_REQUIRE(refs > 0);
 	refs--;
 	if (refs == 0)
 		dcd_exit();
-
-	DBC_ENSURE(refs >= 0);
 }
 
 /*
@@ -328,16 +303,11 @@
 	int status = -EPERM;
 	struct mgr_object *pmgr_obj = (struct mgr_object *)mgr_handle;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(dcd_handle != NULL);
-
 	*dcd_handle = (u32) NULL;
 	if (pmgr_obj) {
 		*dcd_handle = (u32) pmgr_obj->dcd_mgr;
 		status = 0;
 	}
-	DBC_ENSURE((!status && *dcd_handle != (u32) NULL) ||
-		   (status && *dcd_handle == (u32) NULL));
 
 	return status;
 }
@@ -349,22 +319,13 @@
 bool mgr_init(void)
 {
 	bool ret = true;
-	bool init_dcd = false;
 
-	DBC_REQUIRE(refs >= 0);
-
-	if (refs == 0) {
-		init_dcd = dcd_init();	/*  DCD Module */
-
-		if (!init_dcd)
-			ret = false;
-	}
+	if (refs == 0)
+		ret = dcd_init();	/*  DCD Module */
 
 	if (ret)
 		refs++;
 
-	DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
-
 	return ret;
 }
 
@@ -380,8 +341,6 @@
 	struct sync_object *sync_events[MAX_EVENTS];
 	u32 i;
 
-	DBC_REQUIRE(count < MAX_EVENTS);
-
 	for (i = 0; i < count; i++)
 		sync_events[i] = anotifications[i]->handle;
 
diff --git a/drivers/staging/tidspbridge/rmgr/nldr.c b/drivers/staging/tidspbridge/rmgr/nldr.c
index 0e70cba..30d5480 100644
--- a/drivers/staging/tidspbridge/rmgr/nldr.c
+++ b/drivers/staging/tidspbridge/rmgr/nldr.c
@@ -22,8 +22,6 @@
 
 #include <dspbridge/dbdefs.h>
 
-#include <dspbridge/dbc.h>
-
 /* Platform manager */
 #include <dspbridge/cod.h>
 #include <dspbridge/dev.h>
@@ -265,8 +263,6 @@
 	(dbll_unload_fxn) dbll_unload,
 };
 
-static u32 refs;		/* module reference count */
-
 static int add_ovly_info(void *handle, struct dbll_sect_info *sect_info,
 				u32 addr, u32 bytes);
 static int add_ovly_node(struct dsp_uuid *uuid_obj,
@@ -313,11 +309,6 @@
 	struct nldr_nodeobject *nldr_node_obj = NULL;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(node_props != NULL);
-	DBC_REQUIRE(nldr_nodeobj != NULL);
-	DBC_REQUIRE(nldr_obj);
-
 	/* Initialize handle in case of failure */
 	*nldr_nodeobj = NULL;
 	/* Allocate node object */
@@ -398,8 +389,6 @@
 	if (status && nldr_node_obj)
 		kfree(nldr_node_obj);
 
-	DBC_ENSURE((!status && *nldr_nodeobj)
-		   || (status && *nldr_nodeobj == NULL));
 	return status;
 }
 
@@ -425,12 +414,6 @@
 	struct rmm_segment *rmm_segs = NULL;
 	u16 i;
 	int status = 0;
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(nldr != NULL);
-	DBC_REQUIRE(hdev_obj != NULL);
-	DBC_REQUIRE(pattrs != NULL);
-	DBC_REQUIRE(pattrs->ovly != NULL);
-	DBC_REQUIRE(pattrs->write != NULL);
 
 	/* Allocate dynamic loader object */
 	nldr_obj = kzalloc(sizeof(struct nldr_object), GFP_KERNEL);
@@ -440,13 +423,10 @@
 		dev_get_cod_mgr(hdev_obj, &cod_mgr);
 		if (cod_mgr) {
 			status = cod_get_loader(cod_mgr, &nldr_obj->dbll);
-			DBC_ASSERT(!status);
 			status = cod_get_base_lib(cod_mgr, &nldr_obj->base_lib);
-			DBC_ASSERT(!status);
 			status =
 			    cod_get_base_name(cod_mgr, sz_zl_file,
 							COD_MAXPATHLENGTH);
-			DBC_ASSERT(!status);
 		}
 		status = 0;
 		/* end lazy status checking */
@@ -547,7 +527,6 @@
 		status =
 		    cod_get_base_name(cod_mgr, sz_zl_file, COD_MAXPATHLENGTH);
 		/* lazy check */
-		DBC_ASSERT(!status);
 		/* First count number of overlay nodes */
 		status =
 		    dcd_get_objects(nldr_obj->dcd_mgr, sz_zl_file,
@@ -583,7 +562,6 @@
 		*nldr = NULL;
 	}
 	/* FIXME:Temp. Fix. Must be removed */
-	DBC_ENSURE((!status && *nldr) || (status && *nldr == NULL));
 	return status;
 }
 
@@ -595,8 +573,6 @@
 	struct ovly_sect *ovly_section;
 	struct ovly_sect *next;
 	u16 i;
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(nldr_obj);
 
 	nldr_obj->ldr_fxns.exit_fxn();
 	if (nldr_obj->rmm)
@@ -644,22 +620,6 @@
 }
 
 /*
- *  ======== nldr_exit ========
- *  Discontinue usage of NLDR module.
- */
-void nldr_exit(void)
-{
-	DBC_REQUIRE(refs > 0);
-
-	refs--;
-
-	if (refs == 0)
-		rmm_exit();
-
-	DBC_ENSURE(refs >= 0);
-}
-
-/*
  *  ======== nldr_get_fxn_addr ========
  */
 int nldr_get_fxn_addr(struct nldr_nodeobject *nldr_node_obj,
@@ -671,10 +631,6 @@
 	bool status1 = false;
 	s32 i = 0;
 	struct lib_node root = { NULL, 0, NULL };
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(nldr_node_obj);
-	DBC_REQUIRE(addr != NULL);
-	DBC_REQUIRE(str_fxn != NULL);
 
 	nldr_obj = nldr_node_obj->nldr_obj;
 	/* Called from node_create(), node_delete(), or node_run(). */
@@ -690,7 +646,6 @@
 			root = nldr_node_obj->delete_lib;
 			break;
 		default:
-			DBC_ASSERT(false);
 			break;
 		}
 	} else {
@@ -760,7 +715,6 @@
 {
 	int status = 0;
 	struct nldr_object *nldr_obj = nldr;
-	DBC_REQUIRE(rmm_mgr != NULL);
 
 	if (nldr) {
 		*rmm_mgr = nldr_obj->rmm;
@@ -769,29 +723,10 @@
 		status = -EFAULT;
 	}
 
-	DBC_ENSURE(!status || (rmm_mgr != NULL && *rmm_mgr == NULL));
-
 	return status;
 }
 
 /*
- *  ======== nldr_init ========
- *  Initialize the NLDR module.
- */
-bool nldr_init(void)
-{
-	DBC_REQUIRE(refs >= 0);
-
-	if (refs == 0)
-		rmm_init();
-
-	refs++;
-
-	DBC_ENSURE(refs > 0);
-	return true;
-}
-
-/*
  *  ======== nldr_load ========
  */
 int nldr_load(struct nldr_nodeobject *nldr_node_obj,
@@ -801,9 +736,6 @@
 	struct dsp_uuid lib_uuid;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(nldr_node_obj);
-
 	nldr_obj = nldr_node_obj->nldr_obj;
 
 	if (nldr_node_obj->dynamic) {
@@ -839,7 +771,6 @@
 					break;
 
 				default:
-					DBC_ASSERT(false);
 					break;
 				}
 			}
@@ -863,9 +794,6 @@
 	struct lib_node *root_lib = NULL;
 	s32 i = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(nldr_node_obj);
-
 	if (nldr_node_obj != NULL) {
 		if (nldr_node_obj->dynamic) {
 			if (*nldr_node_obj->phase_split) {
@@ -889,7 +817,6 @@
 					nldr_node_obj->pers_libs = 0;
 					break;
 				default:
-					DBC_ASSERT(false);
 					break;
 				}
 			} else {
@@ -929,7 +856,6 @@
 	/* Find the node it belongs to */
 	for (i = 0; i < nldr_obj->ovly_nodes; i++) {
 		node_name = nldr_obj->ovly_table[i].node_name;
-		DBC_REQUIRE(node_name);
 		if (strncmp(node_name, sect_name + 1, strlen(node_name)) == 0) {
 			/* Found the node */
 			break;
@@ -1018,8 +944,6 @@
 			/* Add node to table */
 			nldr_obj->ovly_table[nldr_obj->ovly_nid].uuid =
 			    *uuid_obj;
-			DBC_REQUIRE(obj_def.obj_data.node_obj.ndb_props.
-				    ac_name);
 			len =
 			    strlen(obj_def.obj_data.node_obj.ndb_props.ac_name);
 			node_name = obj_def.obj_data.node_obj.ndb_props.ac_name;
@@ -1129,7 +1053,6 @@
 		ret =
 		    rmm_free(nldr_obj->rmm, 0, ovly_section->sect_run_addr,
 			     ovly_section->size, true);
-		DBC_ASSERT(ret);
 		ovly_section = ovly_section->next_sect;
 		i++;
 	}
@@ -1249,7 +1172,6 @@
 
 	if (depth > MAXDEPTH) {
 		/* Error */
-		DBC_ASSERT(false);
 	}
 	root->lib = NULL;
 	/* Allocate a buffer for library file name of size DBL_MAXPATHLENGTH */
@@ -1312,7 +1234,6 @@
 		    dcd_get_num_dep_libs(nldr_node_obj->nldr_obj->dcd_mgr,
 					 &uuid, &nd_libs, &np_libs, phase);
 	}
-	DBC_ASSERT(nd_libs >= np_libs);
 	if (!status) {
 		if (!(*nldr_node_obj->phase_split))
 			np_libs = 0;
@@ -1474,7 +1395,6 @@
 		}
 	}
 
-	DBC_ASSERT(i < nldr_obj->ovly_nodes);
 
 	if (!po_node) {
 		status = -ENOENT;
@@ -1500,7 +1420,6 @@
 		break;
 
 	default:
-		DBC_ASSERT(false);
 		break;
 	}
 
@@ -1623,9 +1542,6 @@
 	struct rmm_addr *rmm_addr_obj = (struct rmm_addr *)dsp_address;
 	bool mem_load_req = false;
 	int status = -ENOMEM;	/* Set to fail */
-	DBC_REQUIRE(hnode);
-	DBC_REQUIRE(mem_sect == DBLL_CODE || mem_sect == DBLL_DATA ||
-		    mem_sect == DBLL_BSS);
 	nldr_obj = hnode->nldr_obj;
 	rmm = nldr_obj->rmm;
 	/* Convert size to DSP words */
@@ -1651,7 +1567,6 @@
 			mem_phase_bit = EXECUTEDATAFLAGBIT;
 			break;
 		default:
-			DBC_ASSERT(false);
 			break;
 		}
 		if (mem_sect == DBLL_CODE)
@@ -1670,11 +1585,9 @@
 	/* Find an appropriate segment based on mem_sect */
 	if (segid == NULLID) {
 		/* No memory requirements of preferences */
-		DBC_ASSERT(!mem_load_req);
 		goto func_cont;
 	}
 	if (segid <= MAXSEGID) {
-		DBC_ASSERT(segid < nldr_obj->dload_segs);
 		/* Attempt to allocate from segid first. */
 		rmm_addr_obj->segid = segid;
 		status =
@@ -1685,7 +1598,6 @@
 		}
 	} else {
 		/* segid > MAXSEGID ==> Internal or external memory */
-		DBC_ASSERT(segid == MEMINTERNALID || segid == MEMEXTERNALID);
 		/*  Check for any internal or external memory segment,
 		 *  depending on segid. */
 		mem_sect_type |= segid == MEMINTERNALID ?
@@ -1736,8 +1648,6 @@
 	u32 word_size;
 	int status = -ENOMEM;	/* Set to fail */
 
-	DBC_REQUIRE(nldr_obj);
-
 	rmm = nldr_obj->rmm;
 
 	/* Convert size to DSP words */
@@ -1761,7 +1671,6 @@
 	struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
 	u16 i;
 
-	DBC_ASSERT(root != NULL);
 
 	/* Unload dependent libraries */
 	for (i = 0; i < root->dep_libs; i++)
@@ -1812,7 +1721,6 @@
 		}
 	}
 
-	DBC_ASSERT(i < nldr_obj->ovly_nodes);
 
 	if (!po_node)
 		/* TODO: Should we print warning here? */
@@ -1839,14 +1747,11 @@
 		other_alloc = po_node->other_sects;
 		break;
 	default:
-		DBC_ASSERT(false);
 		break;
 	}
-	DBC_ASSERT(ref_count && (*ref_count > 0));
 	if (ref_count && (*ref_count > 0)) {
 		*ref_count -= 1;
 		if (other_ref) {
-			DBC_ASSERT(*other_ref > 0);
 			*other_ref -= 1;
 		}
 	}
@@ -1897,9 +1802,6 @@
 	bool status1 = false;
 	s32 i = 0;
 	struct lib_node root = { NULL, 0, NULL };
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(offset_output != NULL);
-	DBC_REQUIRE(sym_name != NULL);
 	pr_debug("%s(0x%x, 0x%x, 0x%x, 0x%x,  %s)\n", __func__, (u32) nldr_node,
 			sym_addr, offset_range, (u32) offset_output, sym_name);
 
@@ -1915,7 +1817,6 @@
 			root = nldr_node->delete_lib;
 			break;
 		default:
-			DBC_ASSERT(false);
 			break;
 		}
 	} else {
diff --git a/drivers/staging/tidspbridge/rmgr/node.c b/drivers/staging/tidspbridge/rmgr/node.c
index 5dadaa4..7fb426c 100644
--- a/drivers/staging/tidspbridge/rmgr/node.c
+++ b/drivers/staging/tidspbridge/rmgr/node.c
@@ -26,9 +26,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- OS Adaptation Layer */
 #include <dspbridge/memdefs.h>
 #include <dspbridge/proc.h>
@@ -162,7 +159,6 @@
 	/* Loader properties */
 	struct nldr_object *nldr_obj;	/* Handle to loader */
 	struct node_ldr_fxns nldr_fxns;	/* Handle to loader functions */
-	bool loader_init;	/* Loader Init function succeeded? */
 };
 
 /*
@@ -264,16 +260,12 @@
 static u32 mem_write(void *priv_ref, u32 dsp_add, void *pbuf,
 		     u32 ul_num_bytes, u32 mem_space);
 
-static u32 refs;		/* module reference count */
-
 /* Dynamic loader functions. */
 static struct node_ldr_fxns nldr_fxns = {
 	nldr_allocate,
 	nldr_create,
 	nldr_delete,
-	nldr_exit,
 	nldr_get_fxn_addr,
-	nldr_init,
 	nldr_load,
 	nldr_unload,
 };
@@ -326,11 +318,6 @@
 
 	void *node_res;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(hprocessor != NULL);
-	DBC_REQUIRE(noderes != NULL);
-	DBC_REQUIRE(node_uuid != NULL);
-
 	*noderes = NULL;
 
 	status = proc_get_processor_id(hprocessor, &proc_id);
@@ -673,7 +660,6 @@
 		drv_proc_node_update_heap_status(node_res, true);
 		drv_proc_node_update_status(node_res, true);
 	}
-	DBC_ENSURE((status && *noderes == NULL) || (!status && *noderes));
 func_end:
 	dev_dbg(bridge, "%s: hprocessor: %p pNodeId: %p pargs: %p attr_in: %p "
 		"node_res: %p status: 0x%x\n", __func__, hprocessor,
@@ -696,11 +682,6 @@
 	bool set_info;
 	u32 proc_id;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(pbuffer != NULL);
-
-	DBC_REQUIRE(usize > 0);
-
 	if (!pnode)
 		status = -EFAULT;
 	else if (node_get_type(pnode) == NODE_DEVICE)
@@ -714,7 +695,6 @@
 
 	status = proc_get_processor_id(pnode->processor, &proc_id);
 	if (proc_id != DSP_UNIT) {
-		DBC_ASSERT(NULL);
 		goto func_end;
 	}
 	/*  If segment ID includes MEM_SETVIRTUALSEGID then pbuffer is a
@@ -782,8 +762,6 @@
 	int status = 0;
 	u32 proc_id;
 
-	DBC_REQUIRE(refs > 0);
-
 	if (!hnode || !hnode->node_mgr) {
 		status = -EFAULT;
 	} else {
@@ -854,7 +832,6 @@
 	s8 chnl_mode;
 	u32 dw_length;
 	int status = 0;
-	DBC_REQUIRE(refs > 0);
 
 	if (!node1 || !node2)
 		return -EFAULT;
@@ -903,7 +880,6 @@
 	if (node1_type != NODE_GPP) {
 		hnode_mgr = node1->node_mgr;
 	} else {
-		DBC_ASSERT(node2 != (struct node_object *)DSP_HGPPNODE);
 		hnode_mgr = node2->node_mgr;
 	}
 
@@ -982,9 +958,6 @@
 			goto out_unlock;
 		}
 
-		DBC_ASSERT((node1_type == NODE_GPP) ||
-				(node2_type == NODE_GPP));
-
 		chnl_mode = (node1_type == NODE_GPP) ?
 			CHNL_MODETODSP : CHNL_MODEFROMDSP;
 
@@ -1139,7 +1112,6 @@
 	    omap_dspbridge_dev->dev.platform_data;
 #endif
 
-	DBC_REQUIRE(refs > 0);
 	if (!pnode) {
 		status = -EFAULT;
 		goto func_end;
@@ -1291,10 +1263,6 @@
 	int status = 0;
 	u8 dev_type;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(node_man != NULL);
-	DBC_REQUIRE(hdev_obj != NULL);
-
 	*node_man = NULL;
 	/* Allocate Node manager object */
 	node_mgr_obj = kzalloc(sizeof(struct node_mgr), GFP_KERNEL);
@@ -1366,7 +1334,6 @@
 	nldr_attrs_obj.write = mem_write;
 	nldr_attrs_obj.dsp_word_size = node_mgr_obj->dsp_word_size;
 	nldr_attrs_obj.dsp_mau_size = node_mgr_obj->dsp_mau_size;
-	node_mgr_obj->loader_init = node_mgr_obj->nldr_fxns.init();
 	status = node_mgr_obj->nldr_fxns.create(&node_mgr_obj->nldr_obj,
 			hdev_obj,
 			&nldr_attrs_obj);
@@ -1375,8 +1342,6 @@
 
 	*node_man = node_mgr_obj;
 
-	DBC_ENSURE((status && *node_man == NULL) || (!status && *node_man));
-
 	return status;
 out_err:
 	delete_node_mgr(node_mgr_obj);
@@ -1409,7 +1374,6 @@
 	void *node_res = noderes;
 
 	struct dsp_processorstate proc_state;
-	DBC_REQUIRE(refs > 0);
 
 	if (!pnode) {
 		status = -EFAULT;
@@ -1554,8 +1518,6 @@
  */
 int node_delete_mgr(struct node_mgr *hnode_mgr)
 {
-	DBC_REQUIRE(refs > 0);
-
 	if (!hnode_mgr)
 		return -EFAULT;
 
@@ -1576,10 +1538,6 @@
 	struct node_object *hnode;
 	u32 i = 0;
 	int status = 0;
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(node_tab != NULL || node_tab_size == 0);
-	DBC_REQUIRE(pu_num_nodes != NULL);
-	DBC_REQUIRE(pu_allocated != NULL);
 
 	if (!hnode_mgr) {
 		status = -EFAULT;
@@ -1605,20 +1563,6 @@
 }
 
 /*
- *  ======== node_exit ========
- *  Purpose:
- *      Discontinue usage of NODE module.
- */
-void node_exit(void)
-{
-	DBC_REQUIRE(refs > 0);
-
-	refs--;
-
-	DBC_ENSURE(refs >= 0);
-}
-
-/*
  *  ======== node_free_msg_buf ========
  *  Purpose:
  *      Frees the message buffer.
@@ -1629,10 +1573,6 @@
 	struct node_object *pnode = (struct node_object *)hnode;
 	int status = 0;
 	u32 proc_id;
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(pbuffer != NULL);
-	DBC_REQUIRE(pnode != NULL);
-	DBC_REQUIRE(pnode->xlator != NULL);
 
 	if (!hnode) {
 		status = -EFAULT;
@@ -1653,7 +1593,6 @@
 			status = cmm_xlator_free_buf(pnode->xlator, pbuffer);
 		}
 	} else {
-		DBC_ASSERT(NULL);	/* BUG */
 	}
 func_end:
 	return status;
@@ -1669,9 +1608,6 @@
 			 struct dsp_nodeattr *pattr, u32 attr_size)
 {
 	struct node_mgr *hnode_mgr;
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(pattr != NULL);
-	DBC_REQUIRE(attr_size >= sizeof(struct dsp_nodeattr));
 
 	if (!hnode)
 		return -EFAULT;
@@ -1713,9 +1649,6 @@
 {
 	enum node_type node_type;
 	int status = -EINVAL;
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(dir == DSP_TONODE || dir == DSP_FROMNODE);
-	DBC_REQUIRE(chan_id != NULL);
 
 	if (!hnode) {
 		status = -EFAULT;
@@ -1734,7 +1667,6 @@
 			}
 		}
 	} else {
-		DBC_ASSERT(dir == DSP_FROMNODE);
 		if (index < MAX_OUTPUTS(hnode)) {
 			if (hnode->outputs[index].type == HOSTCONNECT) {
 				*chan_id = hnode->outputs[index].dev_id;
@@ -1761,9 +1693,6 @@
 	struct dsp_processorstate proc_state;
 	struct proc_object *hprocessor;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(message != NULL);
-
 	if (!hnode) {
 		status = -EFAULT;
 		goto func_end;
@@ -1831,14 +1760,12 @@
 {
 	int status = 0;
 	struct node_mgr *node_mgr_obj = hnode_mgr;
-	DBC_REQUIRE(nldr_ovlyobj != NULL);
 
 	if (!hnode_mgr)
 		status = -EFAULT;
 	else
 		*nldr_ovlyobj = node_mgr_obj->nldr_obj;
 
-	DBC_ENSURE(!status || (nldr_ovlyobj != NULL && *nldr_ovlyobj == NULL));
 	return status;
 }
 
@@ -1852,8 +1779,6 @@
 {
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-
 	if (!hnode)
 		status = -EFAULT;
 	else
@@ -1867,8 +1792,6 @@
  */
 enum nldr_loadtype node_get_load_type(struct node_object *hnode)
 {
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(hnode);
 	if (!hnode) {
 		dev_dbg(bridge, "%s: Failed. hnode: %p\n", __func__, hnode);
 		return -1;
@@ -1884,8 +1807,6 @@
  */
 u32 node_get_timeout(struct node_object *hnode)
 {
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(hnode);
 	if (!hnode) {
 		dev_dbg(bridge, "%s: failed. hnode: %p\n", __func__, hnode);
 		return 0;
@@ -1915,20 +1836,6 @@
 }
 
 /*
- *  ======== node_init ========
- *  Purpose:
- *      Initialize the NODE module.
- */
-bool node_init(void)
-{
-	DBC_REQUIRE(refs >= 0);
-
-	refs++;
-
-	return true;
-}
-
-/*
  *  ======== node_on_exit ========
  *  Purpose:
  *      Gets called when RMS_EXIT is received for a node.
@@ -1970,8 +1877,6 @@
 	struct dsp_processorstate proc_state;
 	struct proc_object *hprocessor;
 
-	DBC_REQUIRE(refs > 0);
-
 	if (!hnode) {
 		status = -EFAULT;
 	} else {
@@ -2054,9 +1959,6 @@
 	struct dsp_processorstate proc_state;
 	struct proc_object *hprocessor;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(pmsg != NULL);
-
 	if (!hnode) {
 		status = -EFAULT;
 		goto func_end;
@@ -2146,9 +2048,6 @@
 	struct bridge_drv_interface *intf_fxns;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(hnotification != NULL);
-
 	if (!hnode) {
 		status = -EFAULT;
 	} else {
@@ -2207,8 +2106,6 @@
 	struct dsp_processorstate proc_state;
 	struct proc_object *hprocessor;
 
-	DBC_REQUIRE(refs > 0);
-
 	if (!hnode) {
 		status = -EFAULT;
 		goto func_end;
@@ -2287,7 +2184,6 @@
 						   NODE_GET_PRIORITY(hnode));
 	} else {
 		/* We should never get here */
-		DBC_ASSERT(false);
 	}
 func_cont1:
 	/* Update node state. */
@@ -2326,9 +2222,6 @@
 	struct deh_mgr *hdeh_mgr;
 	struct dsp_processorstate proc_state;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(pstatus != NULL);
-
 	if (!hnode || !hnode->node_mgr) {
 		status = -EFAULT;
 		goto func_end;
@@ -2610,9 +2503,6 @@
 		if (hnode_mgr->nldr_obj)
 			hnode_mgr->nldr_fxns.delete(hnode_mgr->nldr_obj);
 
-		if (hnode_mgr->loader_init)
-			hnode_mgr->nldr_fxns.exit();
-
 		kfree(hnode_mgr);
 	}
 }
@@ -2668,7 +2558,6 @@
 			strm1->connect_type = CONNECTTYPE_GPPOUTPUT;
 	} else {
 		/* GPP == > NODE */
-		DBC_ASSERT(node2 != (struct node_object *)DSP_HGPPNODE);
 		strm_index = node2->num_inputs + node2->num_outputs - 1;
 		strm2 = &(node2->stream_connect[strm_index]);
 		strm2->cb_struct = sizeof(struct dsp_streamconnect);
@@ -2748,9 +2637,6 @@
 	char *pstr_fxn_name = NULL;
 	struct node_mgr *hnode_mgr = hnode->node_mgr;
 	int status = 0;
-	DBC_REQUIRE(node_get_type(hnode) == NODE_TASK ||
-		    node_get_type(hnode) == NODE_DAISSOCKET ||
-		    node_get_type(hnode) == NODE_MESSAGE);
 
 	switch (phase) {
 	case CREATEPHASE:
@@ -2767,7 +2653,6 @@
 		break;
 	default:
 		/* Should never get here */
-		DBC_ASSERT(false);
 		break;
 	}
 
@@ -2787,9 +2672,6 @@
 {
 	u32 i;
 
-	DBC_REQUIRE(hnode);
-	DBC_REQUIRE(node_info != NULL);
-
 	node_info->cb_struct = sizeof(struct dsp_nodeinfo);
 	node_info->nb_node_database_props =
 	    hnode->dcd_props.obj_data.node_obj.ndb_props;
@@ -2848,9 +2730,7 @@
 				pmsg_args->max_msgs);
 		} else {
 			/* Copy device name */
-			DBC_REQUIRE(pndb_props->ac_name);
 			len = strlen(pndb_props->ac_name);
-			DBC_ASSERT(len < MAXDEVNAMELEN);
 			hnode->str_dev_name = kzalloc(len + 1, GFP_KERNEL);
 			if (hnode->str_dev_name == NULL) {
 				status = -ENOMEM;
@@ -2938,10 +2818,6 @@
 	struct dcd_nodeprops dcd_node_props;
 	struct dsp_processorstate proc_state;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(hprocessor != NULL);
-	DBC_REQUIRE(node_uuid != NULL);
-
 	if (hprocessor == NULL || node_uuid == NULL) {
 		status = -EFAULT;
 		goto func_end;
@@ -3063,8 +2939,6 @@
 	/* Function interface to Bridge driver*/
 	struct bridge_drv_interface *intf_fxns;
 
-	DBC_REQUIRE(hnode);
-
 	hnode_mgr = hnode->node_mgr;
 
 	ul_size = ul_num_bytes / hnode_mgr->dsp_word_size;
@@ -3106,9 +2980,6 @@
 	/* Function interface to Bridge driver */
 	struct bridge_drv_interface *intf_fxns;
 
-	DBC_REQUIRE(hnode);
-	DBC_REQUIRE(mem_space & DBLL_CODE || mem_space & DBLL_DATA);
-
 	hnode_mgr = hnode->node_mgr;
 
 	ul_timeout = hnode->timeout;
diff --git a/drivers/staging/tidspbridge/rmgr/proc.c b/drivers/staging/tidspbridge/rmgr/proc.c
index 242dd13..7e4f12f 100644
--- a/drivers/staging/tidspbridge/rmgr/proc.c
+++ b/drivers/staging/tidspbridge/rmgr/proc.c
@@ -25,9 +25,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- OS Adaptation Layer */
 #include <dspbridge/ntfy.h>
 #include <dspbridge/sync.h>
@@ -101,8 +98,6 @@
 	struct list_head proc_list;
 };
 
-static u32 refs;
-
 DEFINE_MUTEX(proc_lock);	/* For critical sections */
 
 /*  ----------------------------------- Function Prototypes */
@@ -281,9 +276,6 @@
 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
 	u8 dev_type;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(ph_processor != NULL);
-
 	if (pr_ctxt->processor) {
 		*ph_processor = pr_ctxt->processor;
 		return status;
@@ -382,10 +374,6 @@
 		kfree(p_proc_object);
 	}
 func_end:
-	DBC_ENSURE((status == -EPERM && *ph_processor == NULL) ||
-		   (!status && p_proc_object) ||
-		   (status == 0 && p_proc_object));
-
 	return status;
 }
 
@@ -445,10 +433,6 @@
 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
 	u8 dev_type;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(dev_node_obj != NULL);
-	DBC_REQUIRE(hdev_obj != NULL);
-
 	/* Create a Dummy PROC Object */
 	if (!drv_datap || !drv_datap->mgr_object) {
 		status = -ENODATA;
@@ -516,8 +500,6 @@
 	struct proc_object *p_proc_object = hprocessor;
 	u32 timeout = 0;
 
-	DBC_REQUIRE(refs > 0);
-
 	if (p_proc_object) {
 		/* intercept PWR deep sleep command */
 		if (dw_cmd == BRDIOCTL_DEEPSLEEP) {
@@ -565,8 +547,6 @@
 	int status = 0;
 	struct proc_object *p_proc_object = NULL;
 
-	DBC_REQUIRE(refs > 0);
-
 	p_proc_object = (struct proc_object *)pr_ctxt->processor;
 
 	if (p_proc_object) {
@@ -607,11 +587,6 @@
 	struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
 	struct node_mgr *hnode_mgr = NULL;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(node_tab != NULL || node_tab_size == 0);
-	DBC_REQUIRE(pu_num_nodes != NULL);
-	DBC_REQUIRE(pu_allocated != NULL);
-
 	if (p_proc_object) {
 		if (!(dev_get_node_manager(p_proc_object->dev_obj,
 						       &hnode_mgr))) {
@@ -768,8 +743,6 @@
 	struct process_context *pr_ctxt = (struct process_context *) hprocessor;
 	struct dmm_map_object *map_obj;
 
-	DBC_REQUIRE(refs > 0);
-
 	if (!pr_ctxt) {
 		status = -EFAULT;
 		goto err_out;
@@ -810,8 +783,6 @@
 	struct process_context *pr_ctxt = (struct process_context *) hprocessor;
 	struct dmm_map_object *map_obj;
 
-	DBC_REQUIRE(refs > 0);
-
 	if (!pr_ctxt) {
 		status = -EFAULT;
 		goto err_out;
@@ -884,10 +855,6 @@
 	struct rmm_target_obj *rmm = NULL;
 	struct io_mgr *hio_mgr = NULL;	/* IO manager handle */
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(resource_info != NULL);
-	DBC_REQUIRE(resource_info_size >= sizeof(struct dsp_resourceinfo));
-
 	if (!p_proc_object) {
 		status = -EFAULT;
 		goto func_end;
@@ -940,21 +907,6 @@
 }
 
 /*
- *  ======== proc_exit ========
- *  Purpose:
- *      Decrement reference count, and free resources when reference count is
- *      0.
- */
-void proc_exit(void)
-{
-	DBC_REQUIRE(refs > 0);
-
-	refs--;
-
-	DBC_ENSURE(refs >= 0);
-}
-
-/*
  *  ======== proc_get_dev_object ========
  *  Purpose:
  *      Return the Dev Object handle for a given Processor.
@@ -966,9 +918,6 @@
 	int status = -EPERM;
 	struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(device_obj != NULL);
-
 	if (p_proc_object) {
 		*device_obj = p_proc_object->dev_obj;
 		status = 0;
@@ -977,9 +926,6 @@
 		status = -EFAULT;
 	}
 
-	DBC_ENSURE((!status && *device_obj != NULL) ||
-		   (status && *device_obj == NULL));
-
 	return status;
 }
 
@@ -996,10 +942,6 @@
 	struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
 	int brd_status;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(proc_state_obj != NULL);
-	DBC_REQUIRE(state_info_size >= sizeof(struct dsp_processorstate));
-
 	if (p_proc_object) {
 		/* First, retrieve BRD state information */
 		status = (*p_proc_object->intf_fxns->brd_status)
@@ -1055,25 +997,6 @@
 }
 
 /*
- *  ======== proc_init ========
- *  Purpose:
- *      Initialize PROC's private state, keeping a reference count on each call
- */
-bool proc_init(void)
-{
-	bool ret = true;
-
-	DBC_REQUIRE(refs >= 0);
-
-	if (ret)
-		refs++;
-
-	DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
-
-	return ret;
-}
-
-/*
  *  ======== proc_load ========
  *  Purpose:
  *      Reset a processor and load a new base program image.
@@ -1111,10 +1034,6 @@
 	    omap_dspbridge_dev->dev.platform_data;
 #endif
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(argc_index > 0);
-	DBC_REQUIRE(user_args != NULL);
-
 #ifdef OPT_LOAD_TIME_INSTRUMENTATION
 	do_gettimeofday(&tv1);
 #endif
@@ -1202,8 +1121,6 @@
 			if (status) {
 				status = -EPERM;
 			} else {
-				DBC_ASSERT(p_proc_object->last_coff ==
-					   NULL);
 				/* Allocate memory for pszLastCoff */
 				p_proc_object->last_coff =
 						kzalloc((strlen(user_args[0]) +
@@ -1226,7 +1143,6 @@
 		if (!hmsg_mgr) {
 			status = msg_create(&hmsg_mgr, p_proc_object->dev_obj,
 					    (msg_onexit) node_on_exit);
-			DBC_ASSERT(!status);
 			dev_set_msg_mgr(p_proc_object->dev_obj, hmsg_mgr);
 		}
 	}
@@ -1322,7 +1238,6 @@
 							strlen(pargv0) + 1);
 			else
 				status = -ENOMEM;
-			DBC_ASSERT(brd_state == BRD_LOADED);
 		}
 	}
 
@@ -1331,9 +1246,6 @@
 		pr_err("%s: Processor failed to load\n", __func__);
 		proc_stop(p_proc_object);
 	}
-	DBC_ENSURE((!status
-		    && p_proc_object->proc_state == PROC_LOADED)
-		   || status);
 #ifdef OPT_LOAD_TIME_INSTRUMENTATION
 	do_gettimeofday(&tv2);
 	if (tv2.tv_usec < tv1.tv_usec) {
@@ -1443,9 +1355,6 @@
 	struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
 	struct deh_mgr *hdeh_mgr;
 
-	DBC_REQUIRE(hnotification != NULL);
-	DBC_REQUIRE(refs > 0);
-
 	/* Check processor handle */
 	if (!p_proc_object) {
 		status = -EFAULT;
@@ -1567,7 +1476,6 @@
 	u32 dw_dsp_addr;	/* Loaded code's entry point. */
 	int brd_state;
 
-	DBC_REQUIRE(refs > 0);
 	if (!p_proc_object) {
 		status = -EFAULT;
 		goto func_end;
@@ -1616,7 +1524,6 @@
 		if (!((*p_proc_object->intf_fxns->brd_status)
 				(p_proc_object->bridge_context, &brd_state))) {
 			pr_info("%s: dsp in running state\n", __func__);
-			DBC_ASSERT(brd_state != BRD_HIBERNATION);
 		}
 	} else {
 		pr_err("%s: Failed to start the dsp\n", __func__);
@@ -1624,8 +1531,6 @@
 	}
 
 func_end:
-	DBC_ENSURE((!status && p_proc_object->proc_state ==
-		    PROC_RUNNING) || status);
 	return status;
 }
 
@@ -1644,9 +1549,7 @@
 	u32 node_tab_size = 1;
 	u32 num_nodes = 0;
 	u32 nodes_allocated = 0;
-	int brd_state;
 
-	DBC_REQUIRE(refs > 0);
 	if (!p_proc_object) {
 		status = -EFAULT;
 		goto func_end;
@@ -1678,11 +1581,6 @@
 				msg_delete(hmsg_mgr);
 				dev_set_msg_mgr(p_proc_object->dev_obj, NULL);
 			}
-			if (!((*p_proc_object->
-			      intf_fxns->brd_status) (p_proc_object->
-							  bridge_context,
-							  &brd_state)))
-				DBC_ASSERT(brd_state == BRD_STOPPED);
 		}
 	} else {
 		pr_err("%s: Failed to stop the processor\n", __func__);
@@ -1820,10 +1718,6 @@
 {
 	int status = -EPERM;
 	struct msg_mgr *hmsg_mgr;
-	int brd_state;
-
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(proc_obj);
 
 	/* This is needed only when Device is loaded when it is
 	 * already 'ACTIVE' */
@@ -1840,13 +1734,8 @@
 	if (!((*proc_obj->intf_fxns->brd_monitor)
 			  (proc_obj->bridge_context))) {
 		status = 0;
-		if (!((*proc_obj->intf_fxns->brd_status)
-				  (proc_obj->bridge_context, &brd_state)))
-			DBC_ASSERT(brd_state == BRD_IDLE);
 	}
 
-	DBC_ENSURE((!status && brd_state == BRD_IDLE) ||
-		   status);
 	return status;
 }
 
@@ -1880,8 +1769,6 @@
 {
 	char **pp_envp = new_envp;
 
-	DBC_REQUIRE(new_envp);
-
 	/* Prepend new environ var=value string */
 	*new_envp++ = sz_var;
 
@@ -1906,9 +1793,6 @@
 	int status = 0;
 	struct proc_object *p_proc_object = (struct proc_object *)proc;
 
-	DBC_REQUIRE(p_proc_object);
-	DBC_REQUIRE(is_valid_proc_event(events));
-	DBC_REQUIRE(refs > 0);
 	if (!p_proc_object) {
 		status = -EFAULT;
 		goto func_end;
@@ -1930,9 +1814,6 @@
 	int status = 0;
 	struct proc_object *p_proc_object = (struct proc_object *)proc;
 
-	DBC_REQUIRE(is_valid_proc_event(events));
-	DBC_REQUIRE(refs > 0);
-
 	if (!p_proc_object) {
 		status = -EFAULT;
 		goto func_end;
diff --git a/drivers/staging/tidspbridge/rmgr/rmm.c b/drivers/staging/tidspbridge/rmgr/rmm.c
index f3dc0dd..52187bd 100644
--- a/drivers/staging/tidspbridge/rmgr/rmm.c
+++ b/drivers/staging/tidspbridge/rmgr/rmm.c
@@ -46,9 +46,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- This */
 #include <dspbridge/rmm.h>
 
@@ -83,8 +80,6 @@
 	struct list_head ovly_list;	/* List of overlay memory in use */
 };
 
-static u32 refs;		/* module reference count */
-
 static bool alloc_block(struct rmm_target_obj *target, u32 segid, u32 size,
 			u32 align, u32 *dsp_address);
 static bool free_block(struct rmm_target_obj *target, u32 segid, u32 addr,
@@ -101,12 +96,6 @@
 	u32 addr;
 	int status = 0;
 
-	DBC_REQUIRE(target);
-	DBC_REQUIRE(dsp_address != NULL);
-	DBC_REQUIRE(size > 0);
-	DBC_REQUIRE(reserve || (target->num_segs > 0));
-	DBC_REQUIRE(refs > 0);
-
 	if (!reserve) {
 		if (!alloc_block(target, segid, size, align, dsp_address)) {
 			status = -ENOMEM;
@@ -170,9 +159,6 @@
 	s32 i;
 	int status = 0;
 
-	DBC_REQUIRE(target_obj != NULL);
-	DBC_REQUIRE(num_segs == 0 || seg_tab != NULL);
-
 	/* Allocate DBL target object */
 	target = kzalloc(sizeof(struct rmm_target_obj), GFP_KERNEL);
 
@@ -235,9 +221,6 @@
 
 	}
 
-	DBC_ENSURE((!status && *target_obj)
-		   || (status && *target_obj == NULL));
-
 	return status;
 }
 
@@ -251,8 +234,6 @@
 	struct rmm_header *next;
 	u32 i;
 
-	DBC_REQUIRE(target);
-
 	kfree(target->seg_tab);
 
 	list_for_each_entry_safe(sect, tmp, &target->ovly_list, list_elem) {
@@ -277,18 +258,6 @@
 }
 
 /*
- *  ======== rmm_exit ========
- */
-void rmm_exit(void)
-{
-	DBC_REQUIRE(refs > 0);
-
-	refs--;
-
-	DBC_ENSURE(refs >= 0);
-}
-
-/*
  *  ======== rmm_free ========
  */
 bool rmm_free(struct rmm_target_obj *target, u32 segid, u32 dsp_addr, u32 size,
@@ -297,15 +266,6 @@
 	struct rmm_ovly_sect *sect, *tmp;
 	bool ret = false;
 
-	DBC_REQUIRE(target);
-
-	DBC_REQUIRE(reserved || segid < target->num_segs);
-	DBC_REQUIRE(reserved || (dsp_addr >= target->seg_tab[segid].base &&
-				 (dsp_addr + size) <= (target->seg_tab[segid].
-						   base +
-						   target->seg_tab[segid].
-						   length)));
-
 	/*
 	 *  Free or unreserve memory.
 	 */
@@ -319,7 +279,6 @@
 		list_for_each_entry_safe(sect, tmp, &target->ovly_list,
 				list_elem) {
 			if (dsp_addr == sect->addr) {
-				DBC_ASSERT(size == sect->size);
 				/* Remove from list */
 				list_del(&sect->list_elem);
 				kfree(sect);
@@ -331,18 +290,6 @@
 }
 
 /*
- *  ======== rmm_init ========
- */
-bool rmm_init(void)
-{
-	DBC_REQUIRE(refs >= 0);
-
-	refs++;
-
-	return true;
-}
-
-/*
  *  ======== rmm_stat ========
  */
 bool rmm_stat(struct rmm_target_obj *target, enum dsp_memtype segid,
@@ -354,9 +301,6 @@
 	u32 total_free_size = 0;
 	u32 free_blocks = 0;
 
-	DBC_REQUIRE(mem_stat_buf != NULL);
-	DBC_ASSERT(target != NULL);
-
 	if ((u32) segid < target->num_segs) {
 		head = target->free_list[segid];
 
diff --git a/drivers/staging/tidspbridge/rmgr/strm.c b/drivers/staging/tidspbridge/rmgr/strm.c
index 3fae0e9..34cc934 100644
--- a/drivers/staging/tidspbridge/rmgr/strm.c
+++ b/drivers/staging/tidspbridge/rmgr/strm.c
@@ -24,9 +24,6 @@
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 
-/*  ----------------------------------- Trace & Debug */
-#include <dspbridge/dbc.h>
-
 /*  ----------------------------------- OS Adaptation Layer */
 #include <dspbridge/sync.h>
 
@@ -84,9 +81,6 @@
 	struct cmm_xlatorobject *xlator;
 };
 
-/*  ----------------------------------- Globals */
-static u32 refs;		/* module reference count */
-
 /*  ----------------------------------- Function Prototypes */
 static int delete_strm(struct strm_object *stream_obj);
 
@@ -104,9 +98,6 @@
 	u32 i;
 	struct strm_object *stream_obj = strmres->stream;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(ap_buffer != NULL);
-
 	if (stream_obj) {
 		/*
 		 * Allocate from segment specified at time of stream open.
@@ -122,7 +113,6 @@
 		goto func_end;
 
 	for (i = 0; i < num_bufs; i++) {
-		DBC_ASSERT(stream_obj->xlator != NULL);
 		(void)cmm_xlator_alloc_buf(stream_obj->xlator, &ap_buffer[i],
 					   usize);
 		if (ap_buffer[i] == NULL) {
@@ -156,8 +146,6 @@
 	int status = 0;
 	struct strm_object *stream_obj = strmres->stream;
 
-	DBC_REQUIRE(refs > 0);
-
 	if (!stream_obj) {
 		status = -EFAULT;
 	} else {
@@ -167,7 +155,6 @@
 		status =
 		    (*intf_fxns->chnl_get_info) (stream_obj->chnl_obj,
 						     &chnl_info_obj);
-		DBC_ASSERT(!status);
 
 		if (chnl_info_obj.cio_cs > 0 || chnl_info_obj.cio_reqs > 0)
 			status = -EPIPE;
@@ -180,9 +167,6 @@
 
 	idr_remove(pr_ctxt->stream_id, strmres->id);
 func_end:
-	DBC_ENSURE(status == 0 || status == -EFAULT ||
-		   status == -EPIPE || status == -EPERM);
-
 	dev_dbg(bridge, "%s: stream_obj: %p, status 0x%x\n", __func__,
 		stream_obj, status);
 	return status;
@@ -199,10 +183,6 @@
 	struct strm_mgr *strm_mgr_obj;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(strm_man != NULL);
-	DBC_REQUIRE(dev_obj != NULL);
-
 	*strm_man = NULL;
 	/* Allocate STRM manager object */
 	strm_mgr_obj = kzalloc(sizeof(struct strm_mgr), GFP_KERNEL);
@@ -217,7 +197,6 @@
 		if (!status) {
 			(void)dev_get_intf_fxns(dev_obj,
 						&(strm_mgr_obj->intf_fxns));
-			DBC_ASSERT(strm_mgr_obj->intf_fxns != NULL);
 		}
 	}
 
@@ -226,8 +205,6 @@
 	else
 		kfree(strm_mgr_obj);
 
-	DBC_ENSURE((!status && *strm_man) || (status && *strm_man == NULL));
-
 	return status;
 }
 
@@ -238,27 +215,10 @@
  */
 void strm_delete(struct strm_mgr *strm_mgr_obj)
 {
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(strm_mgr_obj);
-
 	kfree(strm_mgr_obj);
 }
 
 /*
- *  ======== strm_exit ========
- *  Purpose:
- *      Discontinue usage of STRM module.
- */
-void strm_exit(void)
-{
-	DBC_REQUIRE(refs > 0);
-
-	refs--;
-
-	DBC_ENSURE(refs >= 0);
-}
-
-/*
  *  ======== strm_free_buffer ========
  *  Purpose:
  *      Frees the buffers allocated for a stream.
@@ -270,15 +230,11 @@
 	u32 i = 0;
 	struct strm_object *stream_obj = strmres->stream;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(ap_buffer != NULL);
-
 	if (!stream_obj)
 		status = -EFAULT;
 
 	if (!status) {
 		for (i = 0; i < num_bufs; i++) {
-			DBC_ASSERT(stream_obj->xlator != NULL);
 			status =
 			    cmm_xlator_free_buf(stream_obj->xlator,
 						ap_buffer[i]);
@@ -306,10 +262,6 @@
 	int status = 0;
 	void *virt_base = NULL;	/* NULL if no SM used */
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(stream_info != NULL);
-	DBC_REQUIRE(stream_info_size >= sizeof(struct stream_info));
-
 	if (!stream_obj) {
 		status = -EFAULT;
 	} else {
@@ -330,7 +282,6 @@
 
 	if (stream_obj->xlator) {
 		/* We have a translator */
-		DBC_ASSERT(stream_obj->segment_id > 0);
 		cmm_xlator_info(stream_obj->xlator, (u8 **) &virt_base, 0,
 				stream_obj->segment_id, false);
 	}
@@ -370,8 +321,6 @@
 	struct bridge_drv_interface *intf_fxns;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-
 	if (!stream_obj) {
 		status = -EFAULT;
 	} else {
@@ -388,25 +337,6 @@
 }
 
 /*
- *  ======== strm_init ========
- *  Purpose:
- *      Initialize the STRM module.
- */
-bool strm_init(void)
-{
-	bool ret = true;
-
-	DBC_REQUIRE(refs >= 0);
-
-	if (ret)
-		refs++;
-
-	DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
-
-	return ret;
-}
-
-/*
  *  ======== strm_issue ========
  *  Purpose:
  *      Issues a buffer on a stream
@@ -418,9 +348,6 @@
 	int status = 0;
 	void *tmp_buf = NULL;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(pbuf != NULL);
-
 	if (!stream_obj) {
 		status = -EFAULT;
 	} else {
@@ -471,9 +398,6 @@
 
 	void *stream_res;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(strmres != NULL);
-	DBC_REQUIRE(pattr != NULL);
 	*strmres = NULL;
 	if (dir != DSP_TONODE && dir != DSP_FROMNODE) {
 		status = -EPERM;
@@ -536,14 +460,12 @@
 		goto func_cont;
 
 	/* No System DMA */
-	DBC_ASSERT(strm_obj->strm_mode != STRMMODE_LDMA);
 	/* Get the shared mem mgr for this streams dev object */
 	status = dev_get_cmm_mgr(strm_mgr_obj->dev_obj, &hcmm_mgr);
 	if (!status) {
 		/*Allocate a SM addr translator for this strm. */
 		status = cmm_xlator_create(&strm_obj->xlator, hcmm_mgr, NULL);
 		if (!status) {
-			DBC_ASSERT(strm_obj->segment_id > 0);
 			/*  Set translators Virt Addr attributes */
 			status = cmm_xlator_info(strm_obj->xlator,
 						 (u8 **) &pattr->virt_base,
@@ -575,10 +497,6 @@
 				 * strm_mgr_obj->chnl_mgr better be valid or we
 				 * assert here), and then return -EPERM.
 				 */
-				DBC_ASSERT(status == -ENOSR ||
-					   status == -ECHRNG ||
-					   status == -EALREADY ||
-					   status == -EIO);
 				status = -EPERM;
 			}
 		}
@@ -594,12 +512,6 @@
 		(void)delete_strm(strm_obj);
 	}
 
-	/* ensure we return a documented error code */
-	DBC_ENSURE((!status && strm_obj) ||
-		   (*strmres == NULL && (status == -EFAULT ||
-					status == -EPERM
-					|| status == -EINVAL)));
-
 	dev_dbg(bridge, "%s: hnode: %p dir: 0x%x index: 0x%x pattr: %p "
 		"strmres: %p status: 0x%x\n", __func__,
 		hnode, dir, index, pattr, strmres, status);
@@ -619,11 +531,6 @@
 	int status = 0;
 	void *tmp_buf = NULL;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(buf_ptr != NULL);
-	DBC_REQUIRE(nbytes != NULL);
-	DBC_REQUIRE(pdw_arg != NULL);
-
 	if (!stream_obj) {
 		status = -EFAULT;
 		goto func_end;
@@ -679,11 +586,6 @@
 		*buf_ptr = chnl_ioc_obj.buf;
 	}
 func_end:
-	/* ensure we return a documented return code */
-	DBC_ENSURE(!status || status == -EFAULT ||
-		   status == -ETIME || status == -ESRCH ||
-		   status == -EPERM);
-
 	dev_dbg(bridge, "%s: stream_obj: %p buf_ptr: %p nbytes: %p "
 		"pdw_arg: %p status 0x%x\n", __func__, stream_obj,
 		buf_ptr, nbytes, pdw_arg, status);
@@ -702,9 +604,6 @@
 	struct bridge_drv_interface *intf_fxns;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(hnotification != NULL);
-
 	if (!stream_obj) {
 		status = -EFAULT;
 	} else if ((event_mask & ~((DSP_STREAMIOCOMPLETION) |
@@ -725,10 +624,7 @@
 							    notify_type,
 							    hnotification);
 	}
-	/* ensure we return a documented return code */
-	DBC_ENSURE(!status || status == -EFAULT ||
-		   status == -ETIME || status == -ESRCH ||
-		   status == -ENOSYS || status == -EPERM);
+
 	return status;
 }
 
@@ -747,11 +643,6 @@
 	u32 i;
 	int status = 0;
 
-	DBC_REQUIRE(refs > 0);
-	DBC_REQUIRE(strm_tab != NULL);
-	DBC_REQUIRE(pmask != NULL);
-	DBC_REQUIRE(strms > 0);
-
 	*pmask = 0;
 	for (i = 0; i < strms; i++) {
 		if (!strm_tab[i]) {
@@ -811,9 +702,6 @@
 func_end:
 	kfree(sync_events);
 
-	DBC_ENSURE((!status && (*pmask != 0 || utimeout == 0)) ||
-		   (status && *pmask == 0));
-
 	return status;
 }
 
diff --git a/drivers/staging/usbip/stub.h b/drivers/staging/usbip/stub.h
index d407368..a73e437 100644
--- a/drivers/staging/usbip/stub.h
+++ b/drivers/staging/usbip/stub.h
@@ -35,7 +35,6 @@
 struct stub_device {
 	struct usb_interface *interface;
 	struct usb_device *udev;
-	struct list_head list;
 
 	struct usbip_device ud;
 	__u32 devid;
diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c
index 03420e2..fa870e3 100644
--- a/drivers/staging/usbip/stub_dev.c
+++ b/drivers/staging/usbip/stub_dev.c
@@ -297,7 +297,6 @@
 	sdev->devid		= (busnum << 16) | devnum;
 	sdev->ud.side		= USBIP_STUB;
 	sdev->ud.status		= SDEV_ST_AVAILABLE;
-	/* sdev->ud.lock = SPIN_LOCK_UNLOCKED; */
 	spin_lock_init(&sdev->ud.lock);
 	sdev->ud.tcp_socket	= NULL;
 
@@ -306,7 +305,6 @@
 	INIT_LIST_HEAD(&sdev->priv_free);
 	INIT_LIST_HEAD(&sdev->unlink_free);
 	INIT_LIST_HEAD(&sdev->unlink_tx);
-	/* sdev->priv_lock = SPIN_LOCK_UNLOCKED; */
 	spin_lock_init(&sdev->priv_lock);
 
 	init_waitqueue_head(&sdev->tx_waitq);
diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c
index 27ac363..1d5b3fc 100644
--- a/drivers/staging/usbip/stub_rx.c
+++ b/drivers/staging/usbip/stub_rx.c
@@ -367,15 +367,6 @@
 	}
 
 	epd = &ep->desc;
-#if 0
-	/* epnum 0 is always control */
-	if (epnum == 0) {
-		if (dir == USBIP_DIR_OUT)
-			return usb_sndctrlpipe(udev, 0);
-		else
-			return usb_rcvctrlpipe(udev, 0);
-	}
-#endif
 	if (usb_endpoint_xfer_control(epd)) {
 		if (dir == USBIP_DIR_OUT)
 			return usb_sndctrlpipe(udev, epnum);
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c
index d93e7f1..70f23026 100644
--- a/drivers/staging/usbip/usbip_common.c
+++ b/drivers/staging/usbip/usbip_common.c
@@ -735,26 +735,25 @@
  * buffer and iso packets need to be stored and be in propeper endian in urb
  * before calling this function
  */
-int usbip_pad_iso(struct usbip_device *ud, struct urb *urb)
+void usbip_pad_iso(struct usbip_device *ud, struct urb *urb)
 {
 	int np = urb->number_of_packets;
 	int i;
-	int ret;
 	int actualoffset = urb->actual_length;
 
 	if (!usb_pipeisoc(urb->pipe))
-		return 0;
+		return;
 
 	/* if no packets or length of data is 0, then nothing to unpack */
 	if (np == 0 || urb->actual_length == 0)
-		return 0;
+		return;
 
 	/*
 	 * if actual_length is transfer_buffer_length then no padding is
 	 * present.
 	*/
 	if (urb->actual_length == urb->transfer_buffer_length)
-		return 0;
+		return;
 
 	/*
 	 * loop over all packets from last to first (to prevent overwritting
@@ -766,8 +765,6 @@
 			urb->transfer_buffer + actualoffset,
 			urb->iso_frame_desc[i].actual_length);
 	}
-
-	return ret;
 }
 EXPORT_SYMBOL_GPL(usbip_pad_iso);
 
diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h
index b8f8c48..c7b888c 100644
--- a/drivers/staging/usbip/usbip_common.h
+++ b/drivers/staging/usbip/usbip_common.h
@@ -306,7 +306,7 @@
 void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen);
 /* some members of urb must be substituted before. */
 int usbip_recv_iso(struct usbip_device *ud, struct urb *urb);
-int usbip_pad_iso(struct usbip_device *ud, struct urb *urb);
+void usbip_pad_iso(struct usbip_device *ud, struct urb *urb);
 int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb);
 
 /* usbip_event.c */
diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c
index 2ee97e2..dca9bf1 100644
--- a/drivers/staging/usbip/vhci_hcd.c
+++ b/drivers/staging/usbip/vhci_hcd.c
@@ -386,29 +386,6 @@
 				dum->port_status[rhport] |=
 					USB_PORT_STAT_ENABLE;
 			}
-#if 0
-			if (dum->driver) {
-				dum->port_status[rhport] |=
-					USB_PORT_STAT_ENABLE;
-				/* give it the best speed we agree on */
-				dum->gadget.speed = dum->driver->speed;
-				dum->gadget.ep0->maxpacket = 64;
-				switch (dum->gadget.speed) {
-				case USB_SPEED_HIGH:
-					dum->port_status[rhport] |=
-						USB_PORT_STAT_HIGH_SPEED;
-					break;
-				case USB_SPEED_LOW:
-					dum->gadget.ep0->maxpacket = 8;
-					dum->port_status[rhport] |=
-						USB_PORT_STAT_LOW_SPEED;
-					break;
-				default:
-					dum->gadget.speed = USB_SPEED_FULL;
-					break;
-				}
-			}
-#endif
 		}
 		((u16 *) buf)[0] = cpu_to_le16(dum->port_status[rhport]);
 		((u16 *) buf)[1] = cpu_to_le16(dum->port_status[rhport] >> 16);
@@ -425,15 +402,6 @@
 		case USB_PORT_FEAT_SUSPEND:
 			usbip_dbg_vhci_rh(" SetPortFeature: "
 					  "USB_PORT_FEAT_SUSPEND\n");
-#if 0
-			dum->port_status[rhport] |=
-				(1 << USB_PORT_FEAT_SUSPEND);
-			if (dum->driver->suspend) {
-				spin_unlock(&dum->lock);
-				dum->driver->suspend(&dum->gadget);
-				spin_lock(&dum->lock);
-			}
-#endif
 			break;
 		case USB_PORT_FEAT_RESET:
 			usbip_dbg_vhci_rh(" SetPortFeature: "
@@ -444,13 +412,6 @@
 					~(USB_PORT_STAT_ENABLE |
 					  USB_PORT_STAT_LOW_SPEED |
 					  USB_PORT_STAT_HIGH_SPEED);
-#if 0
-				if (dum->driver) {
-					dev_dbg(hardware, "disconnect\n");
-					stop_activity(dum, dum->driver);
-				}
-#endif
-
 				/* FIXME test that code path! */
 			}
 			/* 50msec reset signaling */
@@ -934,14 +895,12 @@
 
 	vdev->ud.side   = USBIP_VHCI;
 	vdev->ud.status = VDEV_ST_NULL;
-	/* vdev->ud.lock   = SPIN_LOCK_UNLOCKED; */
 	spin_lock_init(&vdev->ud.lock);
 
 	INIT_LIST_HEAD(&vdev->priv_rx);
 	INIT_LIST_HEAD(&vdev->priv_tx);
 	INIT_LIST_HEAD(&vdev->unlink_tx);
 	INIT_LIST_HEAD(&vdev->unlink_rx);
-	/* vdev->priv_lock = SPIN_LOCK_UNLOCKED; */
 	spin_lock_init(&vdev->priv_lock);
 
 	init_waitqueue_head(&vdev->waitq_tx);
diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c
index 3f511b4..f5fba732 100644
--- a/drivers/staging/usbip/vhci_rx.c
+++ b/drivers/staging/usbip/vhci_rx.c
@@ -94,8 +94,7 @@
 		return;
 
 	/* restore the padding in iso packets */
-	if (usbip_pad_iso(ud, urb) < 0)
-		return;
+	usbip_pad_iso(ud, urb);
 
 	if (usbip_dbg_flag_vhci_rx)
 		usbip_dump_urb(urb);
diff --git a/drivers/staging/vme/devices/vme_pio2.h b/drivers/staging/vme/devices/vme_pio2.h
index 3c59313..72d9ce0 100644
--- a/drivers/staging/vme/devices/vme_pio2.h
+++ b/drivers/staging/vme/devices/vme_pio2.h
@@ -243,7 +243,7 @@
 int pio2_cntr_reset(struct pio2_card *);
 
 int pio2_gpio_reset(struct pio2_card *);
-int __init pio2_gpio_init(struct pio2_card *);
-void __exit pio2_gpio_exit(struct pio2_card *);
+int __devinit pio2_gpio_init(struct pio2_card *);
+void pio2_gpio_exit(struct pio2_card *);
 
 #endif /* _VME_PIO2_H_ */
diff --git a/drivers/staging/vme/devices/vme_pio2_gpio.c b/drivers/staging/vme/devices/vme_pio2_gpio.c
index dc837de..8584849 100644
--- a/drivers/staging/vme/devices/vme_pio2_gpio.c
+++ b/drivers/staging/vme/devices/vme_pio2_gpio.c
@@ -187,7 +187,7 @@
 	return 0;
 }
 
-int __init pio2_gpio_init(struct pio2_card *card)
+int __devinit pio2_gpio_init(struct pio2_card *card)
 {
 	int retval = 0;
 	char *label;
@@ -220,7 +220,7 @@
 	return retval;
 };
 
-void __exit pio2_gpio_exit(struct pio2_card *card)
+void pio2_gpio_exit(struct pio2_card *card)
 {
 	const char *label = card->gc.label;
 
diff --git a/drivers/staging/vme/vme.h b/drivers/staging/vme/vme.h
index 9d38cee..c9d65bf 100644
--- a/drivers/staging/vme/vme.h
+++ b/drivers/staging/vme/vme.h
@@ -156,7 +156,7 @@
 void vme_irq_free(struct vme_dev *, int, int);
 int vme_irq_generate(struct vme_dev *, int, int);
 
-struct vme_resource * vme_lm_request(struct vme_dev *);
+struct vme_resource *vme_lm_request(struct vme_dev *);
 int vme_lm_count(struct vme_resource *);
 int vme_lm_set(struct vme_resource *, unsigned long long, u32, u32);
 int vme_lm_get(struct vme_resource *, unsigned long long *, u32 *, u32 *);
diff --git a/drivers/staging/vt6655/bssdb.c b/drivers/staging/vt6655/bssdb.c
index 577599e..1368e8c 100644
--- a/drivers/staging/vt6655/bssdb.c
+++ b/drivers/staging/vt6655/bssdb.c
@@ -1327,13 +1327,13 @@
     }
 
     if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
-        // if adhoc started which essid is NULL string, rescaning.
+        // if adhoc started which essid is NULL string, rescanning.
         if ((pMgmt->eCurrState == WMAC_STATE_STARTED) && (pCurrSSID->len == 0)) {
             if (pDevice->uAutoReConnectTime < 10) {
                 pDevice->uAutoReConnectTime++;
             }
             else {
-                DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Adhoc re-scaning ...\n");
+                DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Adhoc re-scanning ...\n");
 	      pMgmt->eScanType = WMAC_SCAN_ACTIVE;
                 bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, NULL);
                 bScheduleCommand((void *) pDevice, WLAN_CMD_SSID, NULL);
diff --git a/drivers/staging/vt6655/ioctl.c b/drivers/staging/vt6655/ioctl.c
index 7fd5cc5..ef197ef 100644
--- a/drivers/staging/vt6655/ioctl.c
+++ b/drivers/staging/vt6655/ioctl.c
@@ -324,16 +324,16 @@
 				pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID;
 				memset(pList->sBSSIDList[ii].abySSID, 0, WLAN_SSID_MAXLEN + 1);
 				memcpy(pList->sBSSIDList[ii].abySSID, pItemSSID->abySSID, pItemSSID->len);
-				if (WLAN_GET_CAP_INFO_ESS(pBSS->wCapInfo)) {
+				if (WLAN_GET_CAP_INFO_ESS(pBSS->wCapInfo))
 					pList->sBSSIDList[ii].byNetType = INFRA;
-				} else {
+				else
 					pList->sBSSIDList[ii].byNetType = ADHOC;
-				}
-				if (WLAN_GET_CAP_INFO_PRIVACY(pBSS->wCapInfo)) {
+
+				if (WLAN_GET_CAP_INFO_PRIVACY(pBSS->wCapInfo))
 					pList->sBSSIDList[ii].bWEPOn = true;
-				} else {
+				else
 					pList->sBSSIDList[ii].bWEPOn = false;
-				}
+
 				ii++;
 				if (ii >= pList->uItem)
 					break;
@@ -367,9 +367,9 @@
 		netif_stop_queue(pDevice->dev);
 
 		spin_lock_irq(&pDevice->lock);
-		if (pDevice->bRadioOff == false) {
+		if (pDevice->bRadioOff == false)
 			CARDbRadioPowerOff(pDevice);
-		}
+
 		pDevice->bLinkPass = false;
 		memset(pMgmt->abyCurrBSSID, 0, 6);
 		pMgmt->eCurrState = WMAC_STATE_IDLE;
@@ -489,13 +489,12 @@
 			break;
 		}
 
-		if (sStartAPCmd.wBBPType == PHY80211g) {
+		if (sStartAPCmd.wBBPType == PHY80211g)
 			pMgmt->byAPBBType = PHY_TYPE_11G;
-		} else if (sStartAPCmd.wBBPType == PHY80211a) {
+		else if (sStartAPCmd.wBBPType == PHY80211a)
 			pMgmt->byAPBBType = PHY_TYPE_11A;
-		} else {
+		else
 			pMgmt->byAPBBType = PHY_TYPE_11B;
-		}
 
 		pItemSSID = (PWLAN_IE_SSID)sStartAPCmd.ssid;
 		if (pItemSSID->len > WLAN_SSID_MAXLEN + 1)
diff --git a/drivers/staging/vt6656/bssdb.c b/drivers/staging/vt6656/bssdb.c
index 32c67ed..619c257 100644
--- a/drivers/staging/vt6656/bssdb.c
+++ b/drivers/staging/vt6656/bssdb.c
@@ -1195,13 +1195,13 @@
     }
 
     if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
-        // if adhoc started which essid is NULL string, rescaning.
+        // if adhoc started which essid is NULL string, rescanning.
         if ((pMgmt->eCurrState == WMAC_STATE_STARTED) && (pCurrSSID->len == 0)) {
             if (pDevice->uAutoReConnectTime < 10) {
                 pDevice->uAutoReConnectTime++;
             }
             else {
-                DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Adhoc re-scaning ...\n");
+                DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Adhoc re-scanning ...\n");
 	       pMgmt->eScanType = WMAC_SCAN_ACTIVE;
 		bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, NULL);
 		bScheduleCommand((void *) pDevice, WLAN_CMD_SSID, NULL);
diff --git a/drivers/staging/vt6656/iwctl.c b/drivers/staging/vt6656/iwctl.c
index ecfda52..b24e531 100644
--- a/drivers/staging/vt6656/iwctl.c
+++ b/drivers/staging/vt6656/iwctl.c
@@ -46,9 +46,6 @@
 
 #include <net/iw_handler.h>
 
-
-/*---------------------  Static Definitions -------------------------*/
-
 #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
 #define SUPPORTED_WIRELESS_EXT                  18
 #else
@@ -63,19 +60,8 @@
     5700, 5745, 5765, 5785, 5805, 5825
 	};
 
-
-/*---------------------  Static Classes  ----------------------------*/
-
-
-//static int          msglevel                =MSG_LEVEL_DEBUG;
 static int          msglevel                =MSG_LEVEL_INFO;
 
-
-/*---------------------  Static Variables  --------------------------*/
-/*---------------------  Static Functions  --------------------------*/
-
-/*---------------------  Export Variables  --------------------------*/
-
 struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev)
 {
 	PSDevice pDevice = netdev_priv(dev);
@@ -87,7 +73,6 @@
                pDevice->wstats.qual.qual =(BYTE) pDevice->scStatistic.LinkQuality;
 	RFvRSSITodBm(pDevice, (BYTE)(pDevice->uCurrRSSI), &ldBm);
 	pDevice->wstats.qual.level = ldBm;
-	//pDevice->wstats.qual.level = 0x100 - pDevice->uCurrRSSI;
 	pDevice->wstats.qual.noise = 0;
 	pDevice->wstats.qual.updated = 1;
 	pDevice->wstats.discard.nwid = 0;
@@ -100,21 +85,6 @@
 	return &pDevice->wstats;
 }
 
-
-
-/*------------------------------------------------------------------*/
-
-
-static int iwctl_commit(struct net_device *dev,
-			      struct iw_request_info *info,
-			      void *wrq,
-			      char *extra)
-{
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWCOMMIT\n");
-
-	return 0;
-}
-
 /*
  * Wireless Handler : get protocol name
  */
@@ -197,14 +167,12 @@
  }
 
 	 pMgmt->eScanType = WMAC_SCAN_PASSIVE;
-         //printk("SIOCSIWSCAN:WLAN_CMD_BSSID_SCAN\n");
 	bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, NULL);
 	spin_unlock_irq(&pDevice->lock);
 
 	return 0;
 }
 
-
 /*
  * Wireless Handler : get scan results
  */
@@ -503,7 +471,7 @@
  * Wireless Handler : get operation mode
  */
 
-int iwctl_giwmode(struct net_device *dev,
+void iwctl_giwmode(struct net_device *dev,
              struct iw_request_info *info,
              __u32 *wmode,
              char *extra)
@@ -530,8 +498,6 @@
 	default:
 		*wmode = IW_MODE_ADHOC;
 	}
-
-	return 0;
 }
 
 
@@ -539,7 +505,7 @@
  * Wireless Handler : get capability range
  */
 
-int iwctl_giwrange(struct net_device *dev,
+void iwctl_giwrange(struct net_device *dev,
              struct iw_request_info *info,
              struct iw_point *wrq,
              char *extra)
@@ -634,9 +600,6 @@
 		range->avg_qual.level = 176;	// -80 dBm
 		range->avg_qual.noise = 0;
 	}
-
-
-	return 0;
 }
 
 
@@ -708,9 +671,7 @@
 
     memcpy(wrq->sa_data, pMgmt->abyCurrBSSID, 6);
 
-//20080123-02,<Modify> by Einsn Liu
  if ((pDevice->bLinkPass == FALSE) && (pMgmt->eCurrMode != WMAC_MODE_ESS_AP))
- //   if ((pDevice->bLinkPass == FALSE) && (pMgmt->eCurrMode == WMAC_MODE_ESS_STA))
         memset(wrq->sa_data, 0, 6);
 
     if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
@@ -895,8 +856,7 @@
 /*
  * Wireless Handler : get essid
  */
-
-int iwctl_giwessid(struct net_device *dev,
+void iwctl_giwessid(struct net_device *dev,
              struct iw_request_info *info,
              struct iw_point *wrq,
              char *extra)
@@ -913,14 +873,11 @@
 
 	// Get the current SSID
     pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
-	//pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
 	memcpy(extra, pItemSSID->abySSID , pItemSSID->len);
 	extra[pItemSSID->len] = '\0';
 
         wrq->length = pItemSSID->len;
 	wrq->flags = 1; // active
-
-	return 0;
 }
 
 /*
@@ -1008,8 +965,7 @@
 /*
  * Wireless Handler : get data rate
  */
-
-int iwctl_giwrate(struct net_device *dev,
+void iwctl_giwrate(struct net_device *dev,
              struct iw_request_info *info,
              struct iw_param *wrq,
              char *extra)
@@ -1047,9 +1003,6 @@
 	    if (pDevice->bFixRate == TRUE)
 	        wrq->fixed = TRUE;
     }
-
-
-	return 0;
 }
 
 
@@ -1057,27 +1010,19 @@
 /*
  * Wireless Handler : set rts threshold
  */
-
 int iwctl_siwrts(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra)
+		 struct iw_param *wrq)
 {
-	PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-	int rc = 0;
+	PSDevice pDevice = (PSDevice)netdev_priv(dev);
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRTS \n");
+	if ((wrq->value < 0 || wrq->value > 2312) && !wrq->disabled)
+		return -EINVAL;
 
-	{
-	    int rthr = wrq->value;
-	    if(wrq->disabled)
-			rthr = 2312;
-	    if((rthr < 0) || (rthr > 2312)) {
-			rc = -EINVAL;
-    	}else {
-		    pDevice->wRTSThreshold = rthr;
-	    }
-    }
+	else if (wrq->disabled)
+		pDevice->wRTSThreshold = 2312;
+
+	else
+		pDevice->wRTSThreshold = wrq->value;
 
 	return 0;
 }
@@ -1327,55 +1272,6 @@
 	return rc;
 }
 
-/*
- * Wireless Handler : get encode mode
- */
-//2008-0409-06, <Mark> by Einsn Liu
- /*
-int iwctl_giwencode(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_point *wrq,
-             char *extra)
-{
-    PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
-    int rc = 0;
-    char abyKey[WLAN_WEP232_KEYLEN];
-	unsigned int index = (unsigned int)(wrq->flags & IW_ENCODE_INDEX);
-	PSKeyItem   pKey = NULL;
-
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWENCODE\n");
-
-
-	memset(abyKey, 0, sizeof(abyKey));
-	// Check encryption mode
-	wrq->flags = IW_ENCODE_NOKEY;
-	// Is WEP enabled ???
-	if (pDevice->bEncryptionEnable)
-		wrq->flags |=  IW_ENCODE_ENABLED;
-    else
-		wrq->flags |=  IW_ENCODE_DISABLED;
-
-    if (pMgmt->bShareKeyAlgorithm)
-		wrq->flags |=  IW_ENCODE_RESTRICTED;
-	else
-		wrq->flags |=  IW_ENCODE_OPEN;
-
-	if (KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, (BYTE)index , &pKey)){
-        wrq->length = pKey->uKeyLength;
-        memcpy(abyKey, pKey->abyKey,  pKey->uKeyLength);
-    }
-    else {
-        rc = -EINVAL;
-        return rc;
-    }
-	wrq->flags |= index;
-	// Copy the key to the user buffer
-	memcpy(extra,  abyKey, WLAN_WEP232_KEYLEN);
-	return 0;
-}
-*/
-
 int iwctl_giwencode(struct net_device *dev,
 			struct iw_request_info *info,
 			struct iw_point *wrq,
@@ -1562,7 +1458,6 @@
 		wpa_version = wrq->value;
 		if(wrq->value == IW_AUTH_WPA_VERSION_DISABLED) {
 		       PRINT_K("iwctl_siwauth:set WPADEV to disable at 1??????\n");
-			//pDevice->bWPADEVUp = FALSE;
 		}
 		else if(wrq->value == IW_AUTH_WPA_VERSION_WPA) {
                           PRINT_K("iwctl_siwauth:set WPADEV to WPA1******\n");
@@ -1570,7 +1465,6 @@
 		else {
                           PRINT_K("iwctl_siwauth:set WPADEV to WPA2******\n");
 		}
-		//pDevice->bWPASuppWextEnabled =TRUE;
 		break;
 	case IW_AUTH_CIPHER_PAIRWISE:
 		pairwise = wrq->value;
@@ -1627,11 +1521,6 @@
 		}
 		break;
 	case IW_AUTH_WPA_ENABLED:
-		//pDevice->bWPADEVUp = !! wrq->value;
-		//if(pDevice->bWPADEVUp==TRUE)
-		  // printk("iwctl_siwauth:set WPADEV to enable successful*******\n");
-		//else
-		 //  printk("iwctl_siwauth:set WPADEV to enable fail?????\n");
 		break;
 	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
 		break;
@@ -1646,7 +1535,6 @@
 			pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
 			pMgmt->bShareKeyAlgorithm = FALSE;
 			pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
-			//pDevice->bWPADEVUp = FALSE;
 			 PRINT_K("iwctl_siwauth:set WPADEV to disaable at 2?????\n");
 		}
 
@@ -1655,15 +1543,6 @@
 		ret = -EOPNOTSUPP;
 		break;
 	}
-/*
-	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wpa_version = %d\n",wpa_version);
-	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pairwise = %d\n",pairwise);
-	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->eEncryptionStatus = %d\n",pDevice->eEncryptionStatus);
-	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pMgmt->eAuthenMode  = %d\n",pMgmt->eAuthenMode);
-	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pMgmt->bShareKeyAlgorithm = %s\n",pMgmt->bShareKeyAlgorithm?"TRUE":"FALSE");
-	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->bEncryptionEnable = %s\n",pDevice->bEncryptionEnable?"TRUE":"FALSE");
-	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->bWPADEVUp = %s\n",pDevice->bWPADEVUp?"TRUE":"FALSE");
-*/
    return ret;
 }
 
@@ -1752,8 +1631,6 @@
     u8  seq[IW_ENCODE_SEQ_MAX_SIZE];
     u8 key[64];
     size_t seq_len=0,key_len=0;
-//
-   // int ii;
     u8 *buf;
     size_t blen;
     u8 key_array[64];
@@ -1883,7 +1760,6 @@
 	PSDevice			pDevice = (PSDevice)netdev_priv(dev);
 	PSMgmtObject	pMgmt = &(pDevice->sMgmtObj);
 	struct iw_mlme *mlme = (struct iw_mlme *)extra;
-	//u16 reason = cpu_to_le16(mlme->reason_code);
 	int ret = 0;
 
 	if(memcmp(pMgmt->abyCurrBSSID, mlme->addr.sa_data, ETH_ALEN)){
@@ -1892,12 +1768,6 @@
 	}
 	switch(mlme->cmd){
 	case IW_MLME_DEAUTH:
-		//this command seems to be not complete,please test it --einsnliu
-		//printk("iwctl_siwmlme--->send DEAUTH\n");
-		/* bScheduleCommand((void *) pDevice,
-		   WLAN_CMD_DEAUTH,
-		   (PBYTE)&reason); */
-		//break;
 	case IW_MLME_DISASSOC:
 		if(pDevice->bLinkPass == TRUE){
 		  PRINT_K("iwctl_siwmlme--->send DISASSOCIATE\n");
@@ -1916,77 +1786,9 @@
 
 #endif
 
-/*------------------------------------------------------------------*/
-/*
- * Structures to export the Wireless Handlers
- */
-
-
-/*
 static const iw_handler		iwctl_handler[] =
 {
-	(iw_handler) iwctl_commit,      // SIOCSIWCOMMIT
-	(iw_handler) iwctl_giwname,     // SIOCGIWNAME
-	(iw_handler) NULL,				// SIOCSIWNWID
-	(iw_handler) iwctl_siwfreq,		// SIOCSIWFREQ
-	(iw_handler) iwctl_giwfreq,		// SIOCGIWFREQ
-	(iw_handler) iwctl_siwmode,		// SIOCSIWMODE
-	(iw_handler) iwctl_giwmode,		// SIOCGIWMODE
-	(iw_handler) NULL,		        // SIOCSIWSENS
-	(iw_handler) iwctl_giwsens,		        // SIOCGIWSENS
-	(iw_handler) NULL, 		        // SIOCSIWRANGE
-	(iw_handler) iwctl_giwrange,		// SIOCGIWRANGE
-	(iw_handler) NULL,         		    // SIOCSIWPRIV
-	(iw_handler) NULL,             		// SIOCGIWPRIV
-	(iw_handler) NULL,             		// SIOCSIWSTATS
-	(iw_handler) NULL,                  // SIOCGIWSTATS
-    (iw_handler) NULL,                  // SIOCSIWSPY
-	(iw_handler) NULL,		            // SIOCGIWSPY
-	(iw_handler) NULL,				    // -- hole --
-	(iw_handler) NULL,				    // -- hole --
-	(iw_handler) iwctl_siwap,		    // SIOCSIWAP
-	(iw_handler) iwctl_giwap,		    // SIOCGIWAP
-	(iw_handler) NULL,				    // -- hole -- 0x16
-	(iw_handler) iwctl_giwaplist,       // SIOCGIWAPLIST
-	(iw_handler) iwctl_siwscan,         // SIOCSIWSCAN
-	(iw_handler) iwctl_giwscan,         // SIOCGIWSCAN
-	(iw_handler) iwctl_siwessid,		// SIOCSIWESSID
-	(iw_handler) iwctl_giwessid,		// SIOCGIWESSID
-	(iw_handler) NULL,		// SIOCSIWNICKN
-	(iw_handler) NULL,		// SIOCGIWNICKN
-	(iw_handler) NULL,				    // -- hole --
-	(iw_handler) NULL,				    // -- hole --
-	(iw_handler) iwctl_siwrate,		// SIOCSIWRATE 0x20
-	(iw_handler) iwctl_giwrate,		// SIOCGIWRATE
-	(iw_handler) iwctl_siwrts,		// SIOCSIWRTS
-	(iw_handler) iwctl_giwrts,		// SIOCGIWRTS
-	(iw_handler) iwctl_siwfrag,		// SIOCSIWFRAG
-	(iw_handler) iwctl_giwfrag,		// SIOCGIWFRAG
-	(iw_handler) NULL,		// SIOCSIWTXPOW
-	(iw_handler) NULL,		// SIOCGIWTXPOW
-	(iw_handler) iwctl_siwretry,		// SIOCSIWRETRY
-	(iw_handler) iwctl_giwretry,		// SIOCGIWRETRY
-	(iw_handler) iwctl_siwencode,		// SIOCSIWENCODE
-	(iw_handler) iwctl_giwencode,		// SIOCGIWENCODE
-	(iw_handler) iwctl_siwpower,		// SIOCSIWPOWER
-	(iw_handler) iwctl_giwpower,		// SIOCGIWPOWER
-	(iw_handler) NULL,			// -- hole --
-	(iw_handler) NULL,			// -- hole --
-	(iw_handler) iwctl_siwgenie,    // SIOCSIWGENIE
-	(iw_handler) iwctl_giwgenie,    // SIOCGIWGENIE
-	(iw_handler) iwctl_siwauth,		// SIOCSIWAUTH
-	(iw_handler) iwctl_giwauth,		// SIOCGIWAUTH
-	(iw_handler) iwctl_siwencodeext,		// SIOCSIWENCODEEXT
-	(iw_handler) iwctl_giwencodeext,		// SIOCGIWENCODEEXT
-	(iw_handler) NULL,				// SIOCSIWPMKSA
-	(iw_handler) NULL,				// -- hole --
-
-};
-*/
-
-static const iw_handler		iwctl_handler[] =
-{
-	(iw_handler) iwctl_commit,      // SIOCSIWCOMMIT
+	(iw_handler) NULL,      /* SIOCSIWCOMMIT */
 	(iw_handler) NULL,      // SIOCGIWNAME
 	(iw_handler) NULL,				// SIOCSIWNWID
 	(iw_handler) NULL,				// SIOCGIWNWID
@@ -2063,13 +1865,9 @@
 {
 	.get_wireless_stats = &iwctl_get_wireless_stats,
 	.num_standard	= sizeof(iwctl_handler)/sizeof(iw_handler),
-//	.num_private	= sizeof(iwctl_private_handler)/sizeof(iw_handler),
-//	.num_private_args = sizeof(iwctl_private_args)/sizeof(struct iw_priv_args),
 	.num_private	= 0,
 	.num_private_args = 0,
 	.standard	= (iw_handler *) iwctl_handler,
-//	.private	= (iw_handler *) iwctl_private_handler,
-//	.private_args	= (struct iw_priv_args *)iwctl_private_args,
 	.private	= NULL,
 	.private_args	= NULL,
 };
diff --git a/drivers/staging/vt6656/iwctl.h b/drivers/staging/vt6656/iwctl.h
index 10a240e..0c6e049 100644
--- a/drivers/staging/vt6656/iwctl.h
+++ b/drivers/staging/vt6656/iwctl.h
@@ -46,13 +46,13 @@
 			 struct sockaddr *wrq,
              char *extra);
 
-int iwctl_giwrange(struct net_device *dev,
+void iwctl_giwrange(struct net_device *dev,
              struct iw_request_info *info,
              struct iw_point *wrq,
              char *extra);
 
 
-int iwctl_giwmode(struct net_device *dev,
+void iwctl_giwmode(struct net_device *dev,
              struct iw_request_info *info,
              __u32 *wmode,
              char *extra);
@@ -97,7 +97,7 @@
              struct iw_point *wrq,
              char *extra);
 
-int iwctl_giwessid(struct net_device *dev,
+void iwctl_giwessid(struct net_device *dev,
              struct iw_request_info *info,
              struct iw_point *wrq,
              char *extra);
@@ -107,16 +107,13 @@
 			 struct iw_param *wrq,
              char *extra);
 
-int iwctl_giwrate(struct net_device *dev,
+void iwctl_giwrate(struct net_device *dev,
              struct iw_request_info *info,
              struct iw_param *wrq,
              char *extra);
 
 int iwctl_siwrts(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra);
-
+		 struct iw_param *wrq);
 
 int iwctl_giwrts(struct net_device *dev,
              struct iw_request_info *info,
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index 6a708f4..763e028 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -1657,8 +1657,8 @@
 		{
 			char essid[IW_ESSID_MAX_SIZE+1];
 			if (wrq->u.essid.pointer) {
-				rc = iwctl_giwessid(dev, NULL,
-						    &(wrq->u.essid), essid);
+				iwctl_giwessid(dev, NULL,
+					    &(wrq->u.essid), essid);
 				if (copy_to_user(wrq->u.essid.pointer,
 						         essid,
 						         wrq->u.essid.length) )
@@ -1698,14 +1698,13 @@
 
 	// Get the current bit-rate
 	case SIOCGIWRATE:
-
-		rc = iwctl_giwrate(dev, NULL, &(wrq->u.bitrate), NULL);
+		iwctl_giwrate(dev, NULL, &(wrq->u.bitrate), NULL);
 		break;
 
 	// Set the desired RTS threshold
 	case SIOCSIWRTS:
 
-		rc = iwctl_siwrts(dev, NULL, &(wrq->u.rts), NULL);
+		rc = iwctl_siwrts(dev, &(wrq->u.rts));
 		break;
 
 	// Get the current RTS threshold
@@ -1733,7 +1732,7 @@
 
 		// Get mode of operation
 	case SIOCGIWMODE:
-		rc = iwctl_giwmode(dev, NULL, &(wrq->u.mode), NULL);
+		iwctl_giwmode(dev, NULL, &(wrq->u.mode), NULL);
 		break;
 
 		// Set WEP keys and mode
@@ -1811,7 +1810,7 @@
 		{
 			struct iw_range range;
 
-			rc = iwctl_giwrange(dev, NULL, &(wrq->u.data), (char *) &range);
+			iwctl_giwrange(dev, NULL, &(wrq->u.data), (char *) &range);
 			if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range)))
 				rc = -EFAULT;
 		}
diff --git a/drivers/staging/vt6656/wpactl.c b/drivers/staging/vt6656/wpactl.c
index 2fa4f84..5435e82 100644
--- a/drivers/staging/vt6656/wpactl.c
+++ b/drivers/staging/vt6656/wpactl.c
@@ -46,23 +46,18 @@
 
 #define VIAWGET_WPA_MAX_BUF_SIZE 1024
 
-
-
 static const int frequency_list[] = {
 	2412, 2417, 2422, 2427, 2432, 2437, 2442,
 	2447, 2452, 2457, 2462, 2467, 2472, 2484
 };
+
 /*---------------------  Static Classes  ----------------------------*/
 
 /*---------------------  Static Variables  --------------------------*/
-//static int          msglevel                =MSG_LEVEL_DEBUG;
-static int          msglevel                =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
 
 /*---------------------  Static Functions  --------------------------*/
 
-
-
-
 /*---------------------  Export Variables  --------------------------*/
 static void wpadev_setup(struct net_device *dev)
 {
@@ -72,9 +67,9 @@
 	dev->addr_len           = ETH_ALEN;
 	dev->tx_queue_len       = 1000;
 
-	memset(dev->broadcast,0xFF, ETH_ALEN);
+	memset(dev->broadcast, 0xFF, ETH_ALEN);
 
-	dev->flags              = IFF_BROADCAST|IFF_MULTICAST;
+	dev->flags              = IFF_BROADCAST | IFF_MULTICAST;
 }
 
 /*
@@ -90,45 +85,43 @@
  * Return Value:
  *
  */
-
 static int wpa_init_wpadev(PSDevice pDevice)
 {
-    PSDevice wpadev_priv;
+	PSDevice wpadev_priv;
 	struct net_device *dev = pDevice->dev;
-         int ret=0;
+	int ret = 0;
 
 	pDevice->wpadev = alloc_netdev(sizeof(PSDevice), "vntwpa", wpadev_setup);
 	if (pDevice->wpadev == NULL)
 		return -ENOMEM;
 
-    wpadev_priv = netdev_priv(pDevice->wpadev);
-    *wpadev_priv = *pDevice;
+	wpadev_priv = netdev_priv(pDevice->wpadev);
+	*wpadev_priv = *pDevice;
 	memcpy(pDevice->wpadev->dev_addr, dev->dev_addr, ETH_ALEN);
-         pDevice->wpadev->base_addr = dev->base_addr;
+	pDevice->wpadev->base_addr = dev->base_addr;
 	pDevice->wpadev->irq = dev->irq;
 	pDevice->wpadev->mem_start = dev->mem_start;
 	pDevice->wpadev->mem_end = dev->mem_end;
 	ret = register_netdev(pDevice->wpadev);
 	if (ret) {
 		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: register_netdev(WPA) failed!\n",
-		       dev->name);
+			dev->name);
 		free_netdev(pDevice->wpadev);
 		return -1;
 	}
 
 	if (pDevice->skb == NULL) {
-        pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
-        if (pDevice->skb == NULL)
-		    return -ENOMEM;
-    }
+		pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
+		if (pDevice->skb == NULL)
+			return -ENOMEM;
+	}
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Registered netdev %s for WPA management\n",
-	       dev->name, pDevice->wpadev->name);
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Registered netdev %s for WPA management\n",
+		dev->name, pDevice->wpadev->name);
 
 	return 0;
 }
 
-
 /*
  * Description:
  *      unregister net_device (wpadev)
@@ -141,29 +134,24 @@
  * Return Value:
  *
  */
-
 static int wpa_release_wpadev(PSDevice pDevice)
 {
-    if (pDevice->skb) {
-        dev_kfree_skb(pDevice->skb);
-        pDevice->skb = NULL;
-    }
+	if (pDevice->skb) {
+		dev_kfree_skb(pDevice->skb);
+		pDevice->skb = NULL;
+	}
 
-    if (pDevice->wpadev) {
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Netdevice %s unregistered\n",
-	       pDevice->dev->name, pDevice->wpadev->name);
-	unregister_netdev(pDevice->wpadev);
-	free_netdev(pDevice->wpadev);
-         pDevice->wpadev = NULL;
-    }
+	if (pDevice->wpadev) {
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Netdevice %s unregistered\n",
+			pDevice->dev->name, pDevice->wpadev->name);
+		unregister_netdev(pDevice->wpadev);
+		free_netdev(pDevice->wpadev);
+		pDevice->wpadev = NULL;
+	}
 
 	return 0;
 }
 
-
-
-
-
 /*
  * Description:
  *      Set enable/disable dev for wpa supplicant deamon
@@ -177,13 +165,11 @@
  * Return Value:
  *
  */
-
 int wpa_set_wpadev(PSDevice pDevice, int val)
 {
 	if (val)
 		return wpa_init_wpadev(pDevice);
-	else
-		return wpa_release_wpadev(pDevice);
+	return wpa_release_wpadev(pDevice);
 }
 
 /*
@@ -199,245 +185,217 @@
  * Return Value:
  *
  */
-
  int wpa_set_keys(PSDevice pDevice, void *ctx, BOOL  fcpfkernel)
 {
-    struct viawget_wpa_param *param=ctx;
-    PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
-    DWORD   dwKeyIndex = 0;
-    BYTE    abyKey[MAX_KEY_LEN];
-    BYTE    abySeq[MAX_KEY_LEN];
-    QWORD   KeyRSC;
-//    NDIS_802_11_KEY_RSC KeyRSC;
-    BYTE    byKeyDecMode = KEY_CTL_WEP;
+	struct viawget_wpa_param *param = ctx;
+	PSMgmtObject pMgmt = &pDevice->sMgmtObj;
+	DWORD dwKeyIndex = 0;
+	BYTE abyKey[MAX_KEY_LEN];
+	BYTE abySeq[MAX_KEY_LEN];
+	QWORD KeyRSC;
+	BYTE byKeyDecMode = KEY_CTL_WEP;
 	int ret = 0;
-	int uu, ii;
-
+	int uu;
+	int ii;
 
 	if (param->u.wpa_key.alg_name > WPA_ALG_CCMP)
 		return -EINVAL;
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "param->u.wpa_key.alg_name = %d \n", param->u.wpa_key.alg_name);
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "param->u.wpa_key.alg_name = %d \n",
+		param->u.wpa_key.alg_name);
 	if (param->u.wpa_key.alg_name == WPA_ALG_NONE) {
-        pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
-        pDevice->bEncryptionEnable = FALSE;
-        pDevice->byKeyIndex = 0;
-        pDevice->bTransmitKey = FALSE;
-        for (uu=0; uu<MAX_KEY_TABLE; uu++) {
-            MACvDisableKeyEntry(pDevice, uu);
-        }
-        return ret;
-    }
+		pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
+		pDevice->bEncryptionEnable = FALSE;
+		pDevice->byKeyIndex = 0;
+		pDevice->bTransmitKey = FALSE;
+		for (uu=0; uu<MAX_KEY_TABLE; uu++) {
+			MACvDisableKeyEntry(pDevice, uu);
+		}
+		return ret;
+	}
 
 	if (param->u.wpa_key.key && param->u.wpa_key.key_len > sizeof(abyKey))
 		return -EINVAL;
 
-    spin_unlock_irq(&pDevice->lock);
-    if(param->u.wpa_key.key && fcpfkernel) {
-       memcpy(&abyKey[0], param->u.wpa_key.key, param->u.wpa_key.key_len);
-     }
-    else {
-	if (param->u.wpa_key.key &&
-	    copy_from_user(&abyKey[0], param->u.wpa_key.key, param->u.wpa_key.key_len)) {
-	    spin_lock_irq(&pDevice->lock);
-	    return -EINVAL;
+	spin_unlock_irq(&pDevice->lock);
+	if (param->u.wpa_key.key && fcpfkernel) {
+		memcpy(&abyKey[0], param->u.wpa_key.key, param->u.wpa_key.key_len);
+	} else {
+		if (param->u.wpa_key.key &&
+			copy_from_user(&abyKey[0], param->u.wpa_key.key,
+				param->u.wpa_key.key_len)) {
+			spin_lock_irq(&pDevice->lock);
+			return -EINVAL;
+		}
 	}
-     }
-    spin_lock_irq(&pDevice->lock);
+	spin_lock_irq(&pDevice->lock);
 
-    dwKeyIndex = (DWORD)(param->u.wpa_key.key_index);
+	dwKeyIndex = (DWORD)(param->u.wpa_key.key_index);
 
 	if (param->u.wpa_key.alg_name == WPA_ALG_WEP) {
-        if (dwKeyIndex > 3) {
-            return -EINVAL;
-        }
-        else {
-            if (param->u.wpa_key.set_tx) {
-                pDevice->byKeyIndex = (BYTE)dwKeyIndex;
-                pDevice->bTransmitKey = TRUE;
-		        dwKeyIndex |= (1 << 31);
-            }
-            KeybSetDefaultKey(  pDevice,
-                                &(pDevice->sKey),
-                                dwKeyIndex & ~(BIT30 | USE_KEYRSC),
-                                param->u.wpa_key.key_len,
-                                NULL,
-                                abyKey,
-                                KEY_CTL_WEP
-                              );
+		if (dwKeyIndex > 3) {
+			return -EINVAL;
+		} else {
+			if (param->u.wpa_key.set_tx) {
+				pDevice->byKeyIndex = (BYTE)dwKeyIndex;
+				pDevice->bTransmitKey = TRUE;
+				dwKeyIndex |= (1 << 31);
+			}
+			KeybSetDefaultKey(  pDevice,
+					&(pDevice->sKey),
+					dwKeyIndex & ~(BIT30 | USE_KEYRSC),
+					param->u.wpa_key.key_len,
+					NULL,
+					abyKey,
+					KEY_CTL_WEP
+				);
 
-        }
-        pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
-        pDevice->bEncryptionEnable = TRUE;
-        return ret;
+		}
+		pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
+		pDevice->bEncryptionEnable = TRUE;
+		return ret;
 	}
 
 
 	if (param->u.wpa_key.seq && param->u.wpa_key.seq_len > sizeof(abySeq))
 		return -EINVAL;
 
-    spin_unlock_irq(&pDevice->lock);
-        if(param->u.wpa_key.seq && fcpfkernel) {
-           memcpy(&abySeq[0], param->u.wpa_key.seq, param->u.wpa_key.seq_len);
-        	}
-       else {
-	if (param->u.wpa_key.seq &&
-	    copy_from_user(&abySeq[0], param->u.wpa_key.seq, param->u.wpa_key.seq_len)) {
-	    spin_lock_irq(&pDevice->lock);
-	    return -EINVAL;
-	}
+	spin_unlock_irq(&pDevice->lock);
+        if (param->u.wpa_key.seq && fcpfkernel) {
+		memcpy(&abySeq[0], param->u.wpa_key.seq, param->u.wpa_key.seq_len);
+	} else {
+		if (param->u.wpa_key.seq &&
+			copy_from_user(&abySeq[0], param->u.wpa_key.seq,
+				param->u.wpa_key.seq_len)) {
+			spin_lock_irq(&pDevice->lock);
+			return -EINVAL;
+		}
 	}
 	spin_lock_irq(&pDevice->lock);
 
 	if (param->u.wpa_key.seq_len > 0) {
 		for (ii = 0 ; ii < param->u.wpa_key.seq_len ; ii++) {
-		     if (ii < 4)
-			    LODWORD(KeyRSC) |= (abySeq[ii] << (ii * 8));
-			 else
-			    HIDWORD(KeyRSC) |= (abySeq[ii] << ((ii-4) * 8));
-	         //KeyRSC |= (abySeq[ii] << (ii * 8));
+			if (ii < 4)
+				LODWORD(KeyRSC) |= (abySeq[ii] << (ii * 8));
+			else
+				HIDWORD(KeyRSC) |= (abySeq[ii] << ((ii-4) * 8));
 		}
 		dwKeyIndex |= 1 << 29;
 	}
 
-    if (param->u.wpa_key.key_index >= MAX_GROUP_KEY) {
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return  dwKeyIndex > 3\n");
-        return -EINVAL;
-    }
+	if (param->u.wpa_key.key_index >= MAX_GROUP_KEY) {
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return  dwKeyIndex > 3\n");
+		return -EINVAL;
+	}
 
 	if (param->u.wpa_key.alg_name == WPA_ALG_TKIP) {
-        pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled;
-    }
+		pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled;
+	}
 
 	if (param->u.wpa_key.alg_name == WPA_ALG_CCMP) {
-        pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled;
-    }
+		pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled;
+	}
 
 	if (param->u.wpa_key.set_tx)
 		dwKeyIndex |= (1 << 31);
 
 
-    if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled)
-        byKeyDecMode = KEY_CTL_CCMP;
-    else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled)
-        byKeyDecMode = KEY_CTL_TKIP;
-    else
-        byKeyDecMode = KEY_CTL_WEP;
+	if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled)
+		byKeyDecMode = KEY_CTL_CCMP;
+	else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled)
+		byKeyDecMode = KEY_CTL_TKIP;
+	else
+		byKeyDecMode = KEY_CTL_WEP;
 
-    // Fix HCT test that set 256 bits KEY and Ndis802_11Encryption3Enabled
-    if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
-        if (param->u.wpa_key.key_len == MAX_KEY_LEN)
-            byKeyDecMode = KEY_CTL_TKIP;
-        else if (param->u.wpa_key.key_len == WLAN_WEP40_KEYLEN)
-            byKeyDecMode = KEY_CTL_WEP;
-        else if (param->u.wpa_key.key_len == WLAN_WEP104_KEYLEN)
-            byKeyDecMode = KEY_CTL_WEP;
-    } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
-        if (param->u.wpa_key.key_len == WLAN_WEP40_KEYLEN)
-            byKeyDecMode = KEY_CTL_WEP;
-        else if (param->u.wpa_key.key_len == WLAN_WEP104_KEYLEN)
-            byKeyDecMode = KEY_CTL_WEP;
+	// Fix HCT test that set 256 bits KEY and Ndis802_11Encryption3Enabled
+	if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
+		if (param->u.wpa_key.key_len == MAX_KEY_LEN)
+			byKeyDecMode = KEY_CTL_TKIP;
+		else if (param->u.wpa_key.key_len == WLAN_WEP40_KEYLEN)
+			byKeyDecMode = KEY_CTL_WEP;
+		else if (param->u.wpa_key.key_len == WLAN_WEP104_KEYLEN)
+			byKeyDecMode = KEY_CTL_WEP;
+	} else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
+		if (param->u.wpa_key.key_len == WLAN_WEP40_KEYLEN)
+			byKeyDecMode = KEY_CTL_WEP;
+		else if (param->u.wpa_key.key_len == WLAN_WEP104_KEYLEN)
+			byKeyDecMode = KEY_CTL_WEP;
+	}
+
+	// Check TKIP key length
+	if ((byKeyDecMode == KEY_CTL_TKIP) &&
+		(param->u.wpa_key.key_len != MAX_KEY_LEN)) {
+		// TKIP Key must be 256 bits
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return- TKIP Key must be 256 bits!\n");
+		return -EINVAL;
     }
+	// Check AES key length
+	if ((byKeyDecMode == KEY_CTL_CCMP) &&
+		(param->u.wpa_key.key_len != AES_KEY_LEN)) {
+		// AES Key must be 128 bits
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return - AES Key must be 128 bits\n");
+		return -EINVAL;
+	}
 
-    // Check TKIP key length
-    if ((byKeyDecMode == KEY_CTL_TKIP) &&
-        (param->u.wpa_key.key_len != MAX_KEY_LEN)) {
-        // TKIP Key must be 256 bits
-        //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA - TKIP Key must be 256 bits\n"));
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return- TKIP Key must be 256 bits!\n");
-        return -EINVAL;
-    }
-    // Check AES key length
-    if ((byKeyDecMode == KEY_CTL_CCMP) &&
-        (param->u.wpa_key.key_len != AES_KEY_LEN)) {
-        // AES Key must be 128 bits
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return - AES Key must be 128 bits\n");
-        return -EINVAL;
-    }
+	if (is_broadcast_ether_addr(&param->addr[0]) || (param->addr == NULL)) {
+		/* if broadcast, set the key as every key entry's group key */
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Groupe Key Assign.\n");
 
-    if (is_broadcast_ether_addr(&param->addr[0]) || (param->addr == NULL)) {
-	/* if broadcast, set the key as every key entry's group key */
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Groupe Key Assign.\n");
-
-        if ((KeybSetAllGroupKey(pDevice,
-                            &(pDevice->sKey),
-                            dwKeyIndex,
-                            param->u.wpa_key.key_len,
-                            (PQWORD) &(KeyRSC),
-                            (PBYTE)abyKey,
-                            byKeyDecMode
-                            ) == TRUE) &&
-            (KeybSetDefaultKey(pDevice,
-                            &(pDevice->sKey),
-                            dwKeyIndex,
-                            param->u.wpa_key.key_len,
-                            (PQWORD) &(KeyRSC),
-                            (PBYTE)abyKey,
-                            byKeyDecMode
-                            ) == TRUE) ) {
-             DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "GROUP Key Assign.\n");
-
-        } else {
-            //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA -KeybSetDefaultKey Fail.0\n"));
-            return -EINVAL;
-        }
-
-    } else {
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key Assign.\n");
-        // BSSID not 0xffffffffffff
-        // Pairwise Key can't be WEP
-        if (byKeyDecMode == KEY_CTL_WEP) {
-            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key can't be WEP\n");
-            return -EINVAL;
-        }
-
-        dwKeyIndex |= (1 << 30); // set pairwise key
-        if (pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) {
-            //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA - WMAC_CONFIG_IBSS_STA\n"));
-            return -EINVAL;
-        }
-        if (KeybSetKey(pDevice,
-                       &(pDevice->sKey),
-                       &param->addr[0],
-                       dwKeyIndex,
-                       param->u.wpa_key.key_len,
-                       (PQWORD) &(KeyRSC),
-                       (PBYTE)abyKey,
-                        byKeyDecMode
-                       ) == TRUE) {
-            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key Set\n");
-
-        } else {
-            // Key Table Full
-	    if (!compare_ether_addr(&param->addr[0], pDevice->abyBSSID)) {
-                //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA -Key Table Full.2\n"));
-                return -EINVAL;
-
-            } else {
-                // Save Key and configure just before associate/reassociate to BSSID
-                // we do not implement now
-                return -EINVAL;
-            }
-        }
-    } // BSSID not 0xffffffffffff
-    if ((ret == 0) && ((param->u.wpa_key.set_tx) != 0)) {
-        pDevice->byKeyIndex = (BYTE)param->u.wpa_key.key_index;
-        pDevice->bTransmitKey = TRUE;
-    }
-    pDevice->bEncryptionEnable = TRUE;
-
-/*
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " key=%x-%x-%x-%x-%x-xxxxx \n",
-               pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][0],
-               pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][1],
-               pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][2],
-               pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][3],
-               pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][4]
-              );
-*/
+		if ((KeybSetAllGroupKey(pDevice, &(pDevice->sKey), dwKeyIndex,
+							param->u.wpa_key.key_len,
+							(PQWORD) &(KeyRSC),
+							(PBYTE)abyKey,
+							byKeyDecMode
+					) == TRUE) &&
+			(KeybSetDefaultKey(pDevice,
+					&(pDevice->sKey),
+					dwKeyIndex,
+					param->u.wpa_key.key_len,
+					(PQWORD) &(KeyRSC),
+					(PBYTE)abyKey,
+					byKeyDecMode
+				) == TRUE) ) {
+			DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "GROUP Key Assign.\n");
+		} else {
+			return -EINVAL;
+		}
+	} else {
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key Assign.\n");
+		// BSSID not 0xffffffffffff
+		// Pairwise Key can't be WEP
+		if (byKeyDecMode == KEY_CTL_WEP) {
+			DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key can't be WEP\n");
+			return -EINVAL;
+		}
+		dwKeyIndex |= (1 << 30); // set pairwise key
+		if (pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) {
+			//DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA - WMAC_CONFIG_IBSS_STA\n"));
+			return -EINVAL;
+		}
+		if (KeybSetKey(pDevice, &(pDevice->sKey), &param->addr[0],
+				dwKeyIndex, param->u.wpa_key.key_len,
+				(PQWORD) &(KeyRSC), (PBYTE)abyKey, byKeyDecMode
+				) == TRUE) {
+			DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key Set\n");
+		} else {
+			// Key Table Full
+			if (!compare_ether_addr(&param->addr[0], pDevice->abyBSSID)) {
+				//DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA -Key Table Full.2\n"));
+				return -EINVAL;
+			} else {
+				// Save Key and configure just before associate/reassociate to BSSID
+				// we do not implement now
+				return -EINVAL;
+			}
+		}
+	} // BSSID not 0xffffffffffff
+	if ((ret == 0) && ((param->u.wpa_key.set_tx) != 0)) {
+		pDevice->byKeyIndex = (BYTE)param->u.wpa_key.key_index;
+		pDevice->bTransmitKey = TRUE;
+	}
+	pDevice->bEncryptionEnable = TRUE;
 
 	return ret;
-
 }
 
 
@@ -454,23 +412,17 @@
  * Return Value:
  *
  */
-
-static int wpa_set_wpa(PSDevice pDevice,
-				     struct viawget_wpa_param *param)
+static int wpa_set_wpa(PSDevice pDevice, struct viawget_wpa_param *param)
 {
-
-    PSMgmtObject    pMgmt = &(pDevice->sMgmtObj);
+	PSMgmtObject pMgmt = &pDevice->sMgmtObj;
 	int ret = 0;
 
-    pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
-    pMgmt->bShareKeyAlgorithm = FALSE;
+	pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
+	pMgmt->bShareKeyAlgorithm = FALSE;
 
-    return ret;
+	return ret;
 }
 
-
-
-
  /*
  * Description:
  *      set disassociate
@@ -484,25 +436,21 @@
  * Return Value:
  *
  */
-
-static int wpa_set_disassociate(PSDevice pDevice,
-				     struct viawget_wpa_param *param)
+static int wpa_set_disassociate(PSDevice pDevice, struct viawget_wpa_param *param)
 {
-    PSMgmtObject    pMgmt = &(pDevice->sMgmtObj);
+	PSMgmtObject pMgmt = &pDevice->sMgmtObj;
 	int ret = 0;
 
-    spin_lock_irq(&pDevice->lock);
-    if (pDevice->bLinkPass) {
-        if (!memcmp(param->addr, pMgmt->abyCurrBSSID, 6))
-		bScheduleCommand((void *) pDevice, WLAN_CMD_DISASSOCIATE, NULL);
-    }
-    spin_unlock_irq(&pDevice->lock);
+	spin_lock_irq(&pDevice->lock);
+	if (pDevice->bLinkPass) {
+		if (!memcmp(param->addr, pMgmt->abyCurrBSSID, 6))
+			bScheduleCommand((void *)pDevice, WLAN_CMD_DISASSOCIATE, NULL);
+	}
+	spin_unlock_irq(&pDevice->lock);
 
-    return ret;
+	return ret;
 }
 
-
-
 /*
  * Description:
  *      enable scan process
@@ -516,37 +464,31 @@
  * Return Value:
  *
  */
-
-static int wpa_set_scan(PSDevice pDevice,
-			struct viawget_wpa_param *param)
+static int wpa_set_scan(PSDevice pDevice, struct viawget_wpa_param *param)
 {
 	int ret = 0;
 
 /**set ap_scan=1&&scan_ssid=1 under hidden ssid mode**/
-        PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
-        PWLAN_IE_SSID       pItemSSID;
-printk("wpa_set_scan-->desired [ssid=%s,ssid_len=%d]\n",
-	     param->u.scan_req.ssid,param->u.scan_req.ssid_len);
+        PSMgmtObject pMgmt = &pDevice->sMgmtObj;
+        PWLAN_IE_SSID pItemSSID;
+	printk("wpa_set_scan-->desired [ssid=%s,ssid_len=%d]\n",
+		param->u.scan_req.ssid,param->u.scan_req.ssid_len);
 // Set the SSID
-memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
-pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
-pItemSSID->byElementID = WLAN_EID_SSID;
-memcpy(pItemSSID->abySSID, param->u.scan_req.ssid, param->u.scan_req.ssid_len);
-pItemSSID->len = param->u.scan_req.ssid_len;
+	memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
+	pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
+	pItemSSID->byElementID = WLAN_EID_SSID;
+	memcpy(pItemSSID->abySSID, param->u.scan_req.ssid, param->u.scan_req.ssid_len);
+	pItemSSID->len = param->u.scan_req.ssid_len;
 
-    spin_lock_irq(&pDevice->lock);
-    BSSvClearBSSList((void *) pDevice, pDevice->bLinkPass);
-    /* bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, NULL); */
-    bScheduleCommand((void *) pDevice,
-		     WLAN_CMD_BSSID_SCAN,
-		     pMgmt->abyDesireSSID);
-    spin_unlock_irq(&pDevice->lock);
+	spin_lock_irq(&pDevice->lock);
+	BSSvClearBSSList((void *) pDevice, pDevice->bLinkPass);
+	bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN,
+			pMgmt->abyDesireSSID);
+	spin_unlock_irq(&pDevice->lock);
 
-    return ret;
+	return ret;
 }
 
-
-
 /*
  * Description:
  *      get bssid
@@ -560,19 +502,15 @@
  * Return Value:
  *
  */
-
-static int wpa_get_bssid(PSDevice pDevice,
-				     struct viawget_wpa_param *param)
+static int wpa_get_bssid(PSDevice pDevice, struct viawget_wpa_param *param)
 {
-    PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
-	int ret = 0;
-	memcpy(param->u.wpa_associate.bssid, pMgmt->abyCurrBSSID , 6);
+    PSMgmtObject pMgmt = &pDevice->sMgmtObj;
+    int ret = 0;
+    memcpy(param->u.wpa_associate.bssid, pMgmt->abyCurrBSSID, 6);
 
     return ret;
-
 }
 
-
 /*
  * Description:
  *      get bssid
@@ -586,24 +524,20 @@
  * Return Value:
  *
  */
-
-static int wpa_get_ssid(PSDevice pDevice,
-				     struct viawget_wpa_param *param)
+static int wpa_get_ssid(PSDevice pDevice, struct viawget_wpa_param *param)
 {
-    PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
-	PWLAN_IE_SSID       pItemSSID;
+	PSMgmtObject pMgmt = &pDevice->sMgmtObj;
+	PWLAN_IE_SSID pItemSSID;
 	int ret = 0;
 
-    pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
+	pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
 
-	memcpy(param->u.wpa_associate.ssid, pItemSSID->abySSID , pItemSSID->len);
+	memcpy(param->u.wpa_associate.ssid, pItemSSID->abySSID, pItemSSID->len);
 	param->u.wpa_associate.ssid_len = pItemSSID->len;
 
-    return ret;
+	return ret;
 }
 
-
-
 /*
  * Description:
  *      get scan results
@@ -617,135 +551,114 @@
  * Return Value:
  *
  */
-
-static int wpa_get_scan(PSDevice pDevice,
-				     struct viawget_wpa_param *param)
+static int wpa_get_scan(PSDevice pDevice, struct viawget_wpa_param *param)
 {
 	struct viawget_scan_result *scan_buf;
-    PSMgmtObject    pMgmt = &(pDevice->sMgmtObj);
-    PWLAN_IE_SSID   pItemSSID;
-    PKnownBSS pBSS;
-	PBYTE  pBuf;
+	PSMgmtObject pMgmt = &pDevice->sMgmtObj;
+	PWLAN_IE_SSID pItemSSID;
+	PKnownBSS pBSS;
+	PBYTE pBuf;
 	int ret = 0;
 	u16 count = 0;
-	u16 ii, jj;
-	long ldBm;//James //add
+	u16 ii;
+	u16 jj;
+	long ldBm; //James //add
 
 //******mike:bubble sort by stronger RSSI*****//
+	PBYTE ptempBSS;
 
-    PBYTE ptempBSS;
+	ptempBSS = kmalloc(sizeof(KnownBSS), GFP_ATOMIC);
 
+	if (ptempBSS == NULL) {
+		printk("bubble sort kmalloc memory fail@@@\n");
+		ret = -ENOMEM;
+		return ret;
+	}
 
-
-    ptempBSS = kmalloc(sizeof(KnownBSS), (int)GFP_ATOMIC);
-
-    if (ptempBSS == NULL) {
-
-       printk("bubble sort kmalloc memory fail@@@\n");
-
-        ret = -ENOMEM;
-
-        return ret;
-
-    }
-
-    for (ii = 0; ii < MAX_BSS_NUM; ii++) {
-
-	for (jj = 0; jj < MAX_BSS_NUM - ii - 1; jj++) {
-
-		if ((pMgmt->sBSSList[jj].bActive != TRUE) ||
-
-                ((pMgmt->sBSSList[jj].uRSSI>pMgmt->sBSSList[jj+1].uRSSI) &&(pMgmt->sBSSList[jj+1].bActive!=FALSE))) {
-
-                 memcpy(ptempBSS,&pMgmt->sBSSList[jj],sizeof(KnownBSS));
-
-                 memcpy(&pMgmt->sBSSList[jj],&pMgmt->sBSSList[jj+1],sizeof(KnownBSS));
-
-                 memcpy(&pMgmt->sBSSList[jj+1],ptempBSS,sizeof(KnownBSS));
-
-              }
-
-         }
-
-    }
-
-  kfree(ptempBSS);
-
- // printk("bubble sort result:\n");
+	for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+		for (jj = 0; jj < MAX_BSS_NUM - ii - 1; jj++) {
+			if ((pMgmt->sBSSList[jj].bActive != TRUE)
+				|| ((pMgmt->sBSSList[jj].uRSSI > pMgmt->sBSSList[jj + 1].uRSSI)
+					&& (pMgmt->sBSSList[jj + 1].bActive != FALSE))) {
+				memcpy(ptempBSS,&pMgmt->sBSSList[jj], sizeof(KnownBSS));
+				memcpy(&pMgmt->sBSSList[jj], &pMgmt->sBSSList[jj + 1],
+					sizeof(KnownBSS));
+				memcpy(&pMgmt->sBSSList[jj + 1], ptempBSS, sizeof(KnownBSS));
+			}
+		}
+	}
+	kfree(ptempBSS);
 
 	count = 0;
 	pBSS = &(pMgmt->sBSSList[0]);
-    for (ii = 0; ii < MAX_BSS_NUM; ii++) {
-        pBSS = &(pMgmt->sBSSList[ii]);
-        if (!pBSS->bActive)
-            continue;
-        count++;
-    }
+	for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+		pBSS = &(pMgmt->sBSSList[ii]);
+		if (!pBSS->bActive)
+			continue;
+		count++;
+	}
 
-    pBuf = kcalloc(count, sizeof(struct viawget_scan_result), (int)GFP_ATOMIC);
+	pBuf = kcalloc(count, sizeof(struct viawget_scan_result), GFP_ATOMIC);
 
-    if (pBuf == NULL) {
-        ret = -ENOMEM;
-        return ret;
-    }
-    scan_buf = (struct viawget_scan_result *)pBuf;
+	if (pBuf == NULL) {
+		ret = -ENOMEM;
+		return ret;
+	}
+	scan_buf = (struct viawget_scan_result *)pBuf;
 	pBSS = &(pMgmt->sBSSList[0]);
-    for (ii = 0, jj = 0; ii < MAX_BSS_NUM ; ii++) {
-        pBSS = &(pMgmt->sBSSList[ii]);
-        if (pBSS->bActive) {
-            if (jj >= count)
-                break;
-            memcpy(scan_buf->bssid, pBSS->abyBSSID, WLAN_BSSID_LEN);
-            pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID;
-   		    memcpy(scan_buf->ssid, pItemSSID->abySSID, pItemSSID->len);
-   		    scan_buf->ssid_len = pItemSSID->len;
-            scan_buf->freq = frequency_list[pBSS->uChannel-1];
-            scan_buf->caps = pBSS->wCapInfo;    //DavidWang for sharemode
+	for (ii = 0, jj = 0; ii < MAX_BSS_NUM; ii++) {
+		pBSS = &(pMgmt->sBSSList[ii]);
+		if (pBSS->bActive) {
+			if (jj >= count)
+				break;
+			memcpy(scan_buf->bssid, pBSS->abyBSSID, WLAN_BSSID_LEN);
+			pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID;
+			memcpy(scan_buf->ssid, pItemSSID->abySSID, pItemSSID->len);
+			scan_buf->ssid_len = pItemSSID->len;
+			scan_buf->freq = frequency_list[pBSS->uChannel-1];
+			scan_buf->caps = pBSS->wCapInfo; // DavidWang for sharemode
 
-	        RFvRSSITodBm(pDevice, (BYTE)(pBSS->uRSSI), &ldBm);
-			if(-ldBm<50){
+			RFvRSSITodBm(pDevice, (BYTE)(pBSS->uRSSI), &ldBm);
+			if (-ldBm < 50)
 				scan_buf->qual = 100;
-			}else  if(-ldBm > 90) {
-				 scan_buf->qual = 0;
-			}else {
+			else if (-ldBm > 90)
+				scan_buf->qual = 0;
+			else
 				scan_buf->qual=(40-(-ldBm-50))*100/40;
-			}
 
 			//James
-            //scan_buf->caps = pBSS->wCapInfo;
-            //scan_buf->qual =
-            scan_buf->noise = 0;
-            scan_buf->level = ldBm;
+			//scan_buf->caps = pBSS->wCapInfo;
+			//scan_buf->qual =
+			scan_buf->noise = 0;
+			scan_buf->level = ldBm;
 
-            //scan_buf->maxrate =
-            if (pBSS->wWPALen != 0) {
-                scan_buf->wpa_ie_len = pBSS->wWPALen;
-                memcpy(scan_buf->wpa_ie, pBSS->byWPAIE, pBSS->wWPALen);
-            }
-            if (pBSS->wRSNLen != 0) {
-                scan_buf->rsn_ie_len = pBSS->wRSNLen;
-                memcpy(scan_buf->rsn_ie, pBSS->byRSNIE, pBSS->wRSNLen);
-            }
-            scan_buf = (struct viawget_scan_result *)((PBYTE)scan_buf + sizeof(struct viawget_scan_result));
-            jj ++;
-        }
-    }
-
-    if (jj < count)
-        count = jj;
-
-    if (copy_to_user(param->u.scan_results.buf, pBuf, sizeof(struct viawget_scan_result) * count)) {
-		ret = -EFAULT;
+			//scan_buf->maxrate =
+			if (pBSS->wWPALen != 0) {
+				scan_buf->wpa_ie_len = pBSS->wWPALen;
+				memcpy(scan_buf->wpa_ie, pBSS->byWPAIE, pBSS->wWPALen);
+			}
+			if (pBSS->wRSNLen != 0) {
+				scan_buf->rsn_ie_len = pBSS->wRSNLen;
+				memcpy(scan_buf->rsn_ie, pBSS->byRSNIE, pBSS->wRSNLen);
+			}
+			scan_buf = (struct viawget_scan_result *)((PBYTE)scan_buf + sizeof(struct viawget_scan_result));
+			jj ++;
+		}
 	}
+
+	if (jj < count)
+		count = jj;
+
+	if (copy_to_user(param->u.scan_results.buf, pBuf, sizeof(struct viawget_scan_result) * count))
+		ret = -EFAULT;
+
 	param->u.scan_results.scan_count = count;
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " param->u.scan_results.scan_count = %d\n", count)
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " param->u.scan_results.scan_count = %d\n", count);
 
-    kfree(pBuf);
-    return ret;
+	kfree(pBuf);
+	return ret;
 }
 
-
-
 /*
  * Description:
  *      set associate with AP
@@ -759,25 +672,23 @@
  * Return Value:
  *
  */
-
-static int wpa_set_associate(PSDevice pDevice,
-				     struct viawget_wpa_param *param)
+static int wpa_set_associate(PSDevice pDevice, struct viawget_wpa_param *param)
 {
-    PSMgmtObject    pMgmt = &(pDevice->sMgmtObj);
-    PWLAN_IE_SSID   pItemSSID;
-    BYTE    abyNullAddr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-    BYTE    abyWPAIE[64];
-    int ret = 0;
-    BOOL   bwepEnabled=FALSE;
+	PSMgmtObject pMgmt = &pDevice->sMgmtObj;
+	PWLAN_IE_SSID pItemSSID;
+	BYTE abyNullAddr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+	BYTE abyWPAIE[64];
+	int ret = 0;
+	BOOL bwepEnabled=FALSE;
 
 	// set key type & algorithm
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pairwise_suite = %d\n", param->u.wpa_associate.pairwise_suite);
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "group_suite = %d\n", param->u.wpa_associate.group_suite);
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "key_mgmt_suite = %d\n", param->u.wpa_associate.key_mgmt_suite);
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "auth_alg = %d\n", param->u.wpa_associate.auth_alg);
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "mode = %d\n", param->u.wpa_associate.mode);
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wpa_ie_len = %d\n", param->u.wpa_associate.wpa_ie_len);
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Roaming dBm = %d\n", param->u.wpa_associate.roam_dbm);  //Davidwang
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pairwise_suite = %d\n", param->u.wpa_associate.pairwise_suite);
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "group_suite = %d\n", param->u.wpa_associate.group_suite);
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "key_mgmt_suite = %d\n", param->u.wpa_associate.key_mgmt_suite);
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "auth_alg = %d\n", param->u.wpa_associate.auth_alg);
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "mode = %d\n", param->u.wpa_associate.mode);
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wpa_ie_len = %d\n", param->u.wpa_associate.wpa_ie_len);
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Roaming dBm = %d\n", param->u.wpa_associate.roam_dbm); // Davidwang
 
 	if (param->u.wpa_associate.wpa_ie) {
 		if (param->u.wpa_associate.wpa_ie_len > sizeof(abyWPAIE))
@@ -789,25 +700,25 @@
 	}
 
 	if (param->u.wpa_associate.mode == 1)
-	    pMgmt->eConfigMode = WMAC_CONFIG_IBSS_STA;
+		pMgmt->eConfigMode = WMAC_CONFIG_IBSS_STA;
 	else
-	    pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
+		pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
 
 	// set bssid
-    if (memcmp(param->u.wpa_associate.bssid, &abyNullAddr[0], 6) != 0)
-        memcpy(pMgmt->abyDesireBSSID, param->u.wpa_associate.bssid, 6);
-    // set ssid
+	if (memcmp(param->u.wpa_associate.bssid, &abyNullAddr[0], 6) != 0)
+		memcpy(pMgmt->abyDesireBSSID, param->u.wpa_associate.bssid, 6);
+	// set ssid
 	memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
-    pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
-    pItemSSID->byElementID = WLAN_EID_SSID;
+	pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
+	pItemSSID->byElementID = WLAN_EID_SSID;
 	pItemSSID->len = param->u.wpa_associate.ssid_len;
 	memcpy(pItemSSID->abySSID, param->u.wpa_associate.ssid, pItemSSID->len);
 
-    if (param->u.wpa_associate.wpa_ie_len == 0) {
-	    if (param->u.wpa_associate.auth_alg & AUTH_ALG_SHARED_KEY)
-            pMgmt->eAuthenMode = WMAC_AUTH_SHAREKEY;
-	    else
-            pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
+	if (param->u.wpa_associate.wpa_ie_len == 0) {
+		if (param->u.wpa_associate.auth_alg & AUTH_ALG_SHARED_KEY)
+			pMgmt->eAuthenMode = WMAC_AUTH_SHAREKEY;
+		else
+			pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
 	} else if (abyWPAIE[0] == RSN_INFO_ELEM) {
 		if (param->u.wpa_associate.key_mgmt_suite == KEY_MGMT_PSK)
 			pMgmt->eAuthenMode = WMAC_AUTH_WPA2PSK;
@@ -817,9 +728,9 @@
 		if (param->u.wpa_associate.key_mgmt_suite == KEY_MGMT_WPA_NONE)
 			pMgmt->eAuthenMode = WMAC_AUTH_WPANONE;
 		else if (param->u.wpa_associate.key_mgmt_suite == KEY_MGMT_PSK)
-		    pMgmt->eAuthenMode = WMAC_AUTH_WPAPSK;
+			pMgmt->eAuthenMode = WMAC_AUTH_WPAPSK;
 		else
-		    pMgmt->eAuthenMode = WMAC_AUTH_WPA;
+			pMgmt->eAuthenMode = WMAC_AUTH_WPA;
 	}
 
 	switch (param->u.wpa_associate.pairwise_suite) {
@@ -833,7 +744,6 @@
 	case CIPHER_WEP104:
 		pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
 		bwepEnabled = TRUE;
-	//	printk("****************wpa_set_associate:set CIPHER_WEP40_104\n");
 		break;
 	case CIPHER_NONE:
 		if (param->u.wpa_associate.group_suite == CIPHER_CCMP)
@@ -845,70 +755,64 @@
 		pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
 	}
 
-           pMgmt->Roam_dbm = param->u.wpa_associate.roam_dbm;
-         // if ((pMgmt->Roam_dbm > 40)&&(pMgmt->Roam_dbm<80))
-         //    pDevice->bEnableRoaming = TRUE;
-
-	    if (pMgmt->eAuthenMode == WMAC_AUTH_SHAREKEY) {   //@wep-sharekey
-            pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
-            pMgmt->bShareKeyAlgorithm = TRUE;
-             }
-	    else if (pMgmt->eAuthenMode == WMAC_AUTH_OPEN) {
-	       if(bwepEnabled==TRUE) {                                                         //@open-wep
-                       pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
+	pMgmt->Roam_dbm = param->u.wpa_associate.roam_dbm;
+	if (pMgmt->eAuthenMode == WMAC_AUTH_SHAREKEY) { // @wep-sharekey
+		pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
+		pMgmt->bShareKeyAlgorithm = TRUE;
+	} else if (pMgmt->eAuthenMode == WMAC_AUTH_OPEN) {
+		if(bwepEnabled==TRUE) { //@open-wep
+			pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
+	   	} else {
+			// @only open
+			pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
 	   	}
-	      else {                                                                                                 //@only open
-            pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
-	   	}
-           }
-//mike save old encryption status
+	}
+	// mike save old encryption status
 	pDevice->eOldEncryptionStatus = pDevice->eEncryptionStatus;
 
-    if (pDevice->eEncryptionStatus !=  Ndis802_11EncryptionDisabled)
-        pDevice->bEncryptionEnable = TRUE;
-    else
-        pDevice->bEncryptionEnable = FALSE;
+	if (pDevice->eEncryptionStatus !=  Ndis802_11EncryptionDisabled)
+		pDevice->bEncryptionEnable = TRUE;
+	else
+		pDevice->bEncryptionEnable = FALSE;
 
- if ((pMgmt->eAuthenMode == WMAC_AUTH_SHAREKEY) ||
-      ((pMgmt->eAuthenMode == WMAC_AUTH_OPEN) && (bwepEnabled==TRUE)))  {
- //mike re-comment:open-wep && sharekey-wep needn't do initial key!!
+	if ((pMgmt->eAuthenMode == WMAC_AUTH_SHAREKEY) ||
+		((pMgmt->eAuthenMode == WMAC_AUTH_OPEN) && (bwepEnabled==TRUE)))  {
+		// mike re-comment:open-wep && sharekey-wep needn't do initial key!!
+	} else {
+		KeyvInitTable(pDevice,&pDevice->sKey);
+	}
 
-     }
- else
-    KeyvInitTable(pDevice,&pDevice->sKey);
+	spin_lock_irq(&pDevice->lock);
+	pDevice->bLinkPass = FALSE;
+	ControlvMaskByte(pDevice, MESSAGE_REQUEST_MACREG, MAC_REG_PAPEDELAY, LEDSTS_STS, LEDSTS_SLOW);
+	memset(pMgmt->abyCurrBSSID, 0, 6);
+	pMgmt->eCurrState = WMAC_STATE_IDLE;
+	netif_stop_queue(pDevice->dev);
 
-    spin_lock_irq(&pDevice->lock);
-    pDevice->bLinkPass = FALSE;
-    ControlvMaskByte(pDevice,MESSAGE_REQUEST_MACREG,MAC_REG_PAPEDELAY,LEDSTS_STS,LEDSTS_SLOW);
-    memset(pMgmt->abyCurrBSSID, 0, 6);
-    pMgmt->eCurrState = WMAC_STATE_IDLE;
-    netif_stop_queue(pDevice->dev);
+/******* search if ap_scan=2, which is associating request in hidden ssid mode ****/
+	{
+		PKnownBSS pCurr = NULL;
+		pCurr = BSSpSearchBSSList(pDevice,
+					pMgmt->abyDesireBSSID,
+					pMgmt->abyDesireSSID,
+					pDevice->eConfigPHYMode
+			);
 
-/*******search if ap_scan=2 ,which is associating request in hidden ssid mode ****/
-{
-   PKnownBSS       pCurr = NULL;
-    pCurr = BSSpSearchBSSList(pDevice,
-                              pMgmt->abyDesireBSSID,
-                              pMgmt->abyDesireSSID,
-                              pDevice->eConfigPHYMode
-                              );
-
-    if (pCurr == NULL){
-    printk("wpa_set_associate---->hidden mode site survey before associate.......\n");
-    bScheduleCommand((void *) pDevice,
-		     WLAN_CMD_BSSID_SCAN,
-		     pMgmt->abyDesireSSID);
-  }
-}
+		if (pCurr == NULL){
+			printk("wpa_set_associate---->hidden mode site survey before associate.......\n");
+			bScheduleCommand((void *)pDevice,
+					WLAN_CMD_BSSID_SCAN,
+					pMgmt->abyDesireSSID);
+		}
+	}
 /****************************************************************/
 
-    bScheduleCommand((void *) pDevice, WLAN_CMD_SSID, NULL);
-    spin_unlock_irq(&pDevice->lock);
+	bScheduleCommand((void *)pDevice, WLAN_CMD_SSID, NULL);
+	spin_unlock_irq(&pDevice->lock);
 
-    return ret;
+	return ret;
 }
 
-
 /*
  * Description:
  *      wpa_ioctl main function supported for wpa supplicant
@@ -922,7 +826,6 @@
  * Return Value:
  *
  */
-
 int wpa_ioctl(PSDevice pDevice, struct iw_point *p)
 {
 	struct viawget_wpa_param *param;
@@ -930,10 +833,10 @@
 	int wpa_ioctl = 0;
 
 	if (p->length < sizeof(struct viawget_wpa_param) ||
-	    p->length > VIAWGET_WPA_MAX_BUF_SIZE || !p->pointer)
+		p->length > VIAWGET_WPA_MAX_BUF_SIZE || !p->pointer)
 		return -EINVAL;
 
-	param = kmalloc((int)p->length, (int)GFP_KERNEL);
+	param = kmalloc((int)p->length, GFP_KERNEL);
 	if (param == NULL)
 		return -ENOMEM;
 
@@ -944,63 +847,63 @@
 
 	switch (param->cmd) {
 	case VIAWGET_SET_WPA:
-        ret = wpa_set_wpa(pDevice, param);
-	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_WPA \n");
+		ret = wpa_set_wpa(pDevice, param);
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_WPA \n");
 		break;
 
 	case VIAWGET_SET_KEY:
-	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_KEY \n");
-	    spin_lock_irq(&pDevice->lock);
-        ret = wpa_set_keys(pDevice, param, FALSE);
-        spin_unlock_irq(&pDevice->lock);
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_KEY \n");
+		spin_lock_irq(&pDevice->lock);
+		ret = wpa_set_keys(pDevice, param, FALSE);
+		spin_unlock_irq(&pDevice->lock);
 		break;
 
 	case VIAWGET_SET_SCAN:
-	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_SCAN \n");
-        ret = wpa_set_scan(pDevice, param);
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_SCAN \n");
+		ret = wpa_set_scan(pDevice, param);
 		break;
 
 	case VIAWGET_GET_SCAN:
-	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_GET_SCAN\n");
-        ret = wpa_get_scan(pDevice, param);
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_GET_SCAN\n");
+		ret = wpa_get_scan(pDevice, param);
 		wpa_ioctl = 1;
 		break;
 
 	case VIAWGET_GET_SSID:
-	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_GET_SSID \n");
-        ret = wpa_get_ssid(pDevice, param);
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_GET_SSID \n");
+		ret = wpa_get_ssid(pDevice, param);
 		wpa_ioctl = 1;
 		break;
 
 	case VIAWGET_GET_BSSID:
-	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_GET_BSSID \n");
-        ret = wpa_get_bssid(pDevice, param);
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_GET_BSSID \n");
+		ret = wpa_get_bssid(pDevice, param);
 		wpa_ioctl = 1;
 		break;
 
 	case VIAWGET_SET_ASSOCIATE:
-	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_ASSOCIATE \n");
-        ret = wpa_set_associate(pDevice, param);
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_ASSOCIATE \n");
+		ret = wpa_set_associate(pDevice, param);
 		break;
 
 	case VIAWGET_SET_DISASSOCIATE:
-	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_DISASSOCIATE \n");
-        ret = wpa_set_disassociate(pDevice, param);
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_DISASSOCIATE \n");
+		ret = wpa_set_disassociate(pDevice, param);
 		break;
 
 	case VIAWGET_SET_DROP_UNENCRYPT:
-	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_DROP_UNENCRYPT \n");
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_DROP_UNENCRYPT \n");
 		break;
 
-    case VIAWGET_SET_DEAUTHENTICATE:
-	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_DEAUTHENTICATE \n");
+	case VIAWGET_SET_DEAUTHENTICATE:
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_DEAUTHENTICATE \n");
 		break;
 
 	default:
-	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wpa_ioctl: unknown cmd=%d\n",
-		       param->cmd);
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wpa_ioctl: unknown cmd=%d\n",
+			param->cmd);
+		kfree(param);
 		return -EOPNOTSUPP;
-		break;
 	}
 
 	if ((ret == 0) && wpa_ioctl) {
@@ -1012,7 +915,5 @@
 
 out:
 	kfree(param);
-
 	return ret;
 }
-
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index fb466f4..4cd3ba5 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -356,7 +356,7 @@
 	msg1.msgcode = DIDmsg_dot11req_scan;
 	msg1.bsstype.data = P80211ENUM_bsstype_any;
 
-	memset(&(msg1.bssid.data), 0xFF, sizeof(p80211item_pstr6_t));
+	memset(&msg1.bssid.data.data, 0xFF, sizeof(msg1.bssid.data.data));
 	msg1.bssid.data.len = 6;
 
 	if (request->n_ssids > 0) {
diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c
index 14bfeb2..0f51b4a 100644
--- a/drivers/staging/wlan-ng/p80211netdev.c
+++ b/drivers/staging/wlan-ng/p80211netdev.c
@@ -150,7 +150,7 @@
 * Returns:
 *	the address of the statistics structure
 ----------------------------------------------------------------*/
-static struct net_device_stats *p80211knetdev_get_stats(netdevice_t * netdev)
+static struct net_device_stats *p80211knetdev_get_stats(netdevice_t *netdev)
 {
 	wlandevice_t *wlandev = netdev->ml_priv;
 
diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c
index 6675c82..c3bb05d 100644
--- a/drivers/staging/wlan-ng/prism2mgmt.c
+++ b/drivers/staging/wlan-ng/prism2mgmt.c
@@ -406,6 +406,7 @@
 	/* SSID */
 	req->ssid.status = P80211ENUM_msgitem_status_data_ok;
 	req->ssid.data.len = le16_to_cpu(item->ssid.len);
+	req->ssid.data.len = min_t(u16, req->ssid.data.len, WLAN_BSSID_LEN);
 	memcpy(req->ssid.data.data, item->ssid.data, req->ssid.data.len);
 
 	/* supported rates */
diff --git a/drivers/staging/xgifb/XGI_main.h b/drivers/staging/xgifb/XGI_main.h
index 35f7b2a..e828fd4 100644
--- a/drivers/staging/xgifb/XGI_main.h
+++ b/drivers/staging/xgifb/XGI_main.h
@@ -7,47 +7,32 @@
 
 #include "XGIfb.h"
 #include "vb_struct.h"
+#include "../../video/sis/sis.h"
 #include "vb_def.h"
 
 #define XGIFAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
 
-#ifndef PCI_VENDOR_ID_XG
-#define PCI_VENDOR_ID_XG          0x18CA
+#ifndef PCI_DEVICE_ID_XGI_41
+#define PCI_DEVICE_ID_XGI_41      0x041
 #endif
-
-#ifndef PCI_DEVICE_ID_XG_40
-#define PCI_DEVICE_ID_XG_40      0x040
+#ifndef PCI_DEVICE_ID_XGI_42
+#define PCI_DEVICE_ID_XGI_42      0x042
 #endif
-#ifndef PCI_DEVICE_ID_XG_41
-#define PCI_DEVICE_ID_XG_41      0x041
-#endif
-#ifndef PCI_DEVICE_ID_XG_42
-#define PCI_DEVICE_ID_XG_42      0x042
-#endif
-#ifndef PCI_DEVICE_ID_XG_20
-#define PCI_DEVICE_ID_XG_20      0x020
-#endif
-#ifndef PCI_DEVICE_ID_XG_27
-#define PCI_DEVICE_ID_XG_27      0x027
+#ifndef PCI_DEVICE_ID_XGI_27
+#define PCI_DEVICE_ID_XGI_27      0x027
 #endif
 
 static DEFINE_PCI_DEVICE_TABLE(xgifb_pci_table) = {
-	{PCI_DEVICE(PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_20)},
-	{PCI_DEVICE(PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_27)},
-	{PCI_DEVICE(PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_40)},
-	{PCI_DEVICE(PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_42)},
+	{PCI_DEVICE(PCI_VENDOR_ID_XGI, PCI_DEVICE_ID_XGI_20)},
+	{PCI_DEVICE(PCI_VENDOR_ID_XGI, PCI_DEVICE_ID_XGI_27)},
+	{PCI_DEVICE(PCI_VENDOR_ID_XGI, PCI_DEVICE_ID_XGI_40)},
+	{PCI_DEVICE(PCI_VENDOR_ID_XGI, PCI_DEVICE_ID_XGI_42)},
 	{0}
 };
 
 MODULE_DEVICE_TABLE(pci, xgifb_pci_table);
 
 /* To be included in fb.h */
-#ifndef FB_ACCEL_XGI_XABRE
-#define FB_ACCEL_XGI_XABRE      41	/* XGI 330 ("Xabre")		*/
-#endif
-
-#define SEQ_DATA                  0x15
-
 #define XGISR			  (xgifb_info->dev_info.P3c4)
 #define XGICR			  (xgifb_info->dev_info.P3d4)
 #define XGIDACA			  (xgifb_info->dev_info.P3c8)
@@ -60,12 +45,6 @@
 #define XGIDAC2A                  XGIPART5
 #define XGIDAC2D                  (XGIPART5 + 1)
 
-#define IND_XGI_PASSWORD          0x05  /* SRs */
-#define IND_XGI_RAMDAC_CONTROL    0x07
-#define IND_XGI_DRAM_SIZE         0x14
-#define IND_XGI_MODULE_ENABLE     0x1E
-#define IND_XGI_PCI_ADDRESS_SET   0x20
-
 #define IND_XGI_SCRATCH_REG_CR30  0x30  /* CRs */
 #define IND_XGI_SCRATCH_REG_CR31  0x31
 #define IND_XGI_SCRATCH_REG_CR32  0x32
@@ -73,10 +52,6 @@
 #define IND_XGI_LCD_PANEL         0x36
 #define IND_XGI_SCRATCH_REG_CR37  0x37
 
-#define IND_XGI_CRT2_WRITE_ENABLE_315 0x2F
-
-#define XGI_PASSWORD              0x86  /* SR05 */
-
 #define XGI_DRAM_SIZE_MASK     0xF0  /*SR14 */
 #define XGI_DRAM_SIZE_1MB      0x00
 #define XGI_DRAM_SIZE_2MB      0x01
@@ -88,37 +63,6 @@
 #define XGI_DRAM_SIZE_128MB    0x07
 #define XGI_DRAM_SIZE_256MB    0x08
 
-#define XGI_ENABLE_2D             0x40  /* SR1E */
-
-#define XGI_MEM_MAP_IO_ENABLE     0x01  /* SR20 */
-#define XGI_PCI_ADDR_ENABLE       0x80
-
-#define XGI_SIMULTANEOUS_VIEW_ENABLE  0x01  /* CR30 */
-#define XGI_VB_OUTPUT_COMPOSITE   0x04
-#define XGI_VB_OUTPUT_SVIDEO      0x08
-#define XGI_VB_OUTPUT_SCART       0x10
-#define XGI_VB_OUTPUT_LCD         0x20
-#define XGI_VB_OUTPUT_CRT2        0x40
-#define XGI_VB_OUTPUT_HIVISION    0x80
-
-#define XGI_VB_OUTPUT_DISABLE     0x20  /* CR31 */
-#define XGI_DRIVER_MODE           0x40
-
-#define XGI_VB_COMPOSITE          0x01  /* CR32 */
-#define XGI_VB_SVIDEO             0x02
-#define XGI_VB_SCART              0x04
-#define XGI_VB_LCD                0x08
-#define XGI_VB_CRT2               0x10
-#define XGI_CRT1                  0x20
-#define XGI_VB_HIVISION           0x40
-#define XGI_VB_YPBPR              0x80
-#define XGI_VB_TV		  (XGI_VB_COMPOSITE | XGI_VB_SVIDEO | \
-				   XGI_VB_SCART | XGI_VB_HIVISION|XGI_VB_YPBPR)
-
-#define XGI_EXTERNAL_CHIP_MASK		   0x0E  /* CR37 */
-#define XGI310_EXTERNAL_CHIP_LVDS          0x02  /* in CR37 << 1 ! */
-#define XGI310_EXTERNAL_CHIP_LVDS_CHRONTEL 0x03  /* in CR37 << 1 ! */
-
 /* ------------------- Global Variables ----------------------------- */
 
 /* display status */
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
index 2502c49..21c0378 100644
--- a/drivers/staging/xgifb/XGI_main_26.c
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -4,6 +4,8 @@
  * Base on TW's sis fbdev code.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 /* #include <linux/config.h> */
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -55,7 +57,7 @@
 #undef XGIFBDEBUG
 
 #ifdef XGIFBDEBUG
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#define DPRINTK(fmt, args...) pr_debug("%s: " fmt, __func__ , ## args)
 #else
 #define DPRINTK(fmt, args...)
 #endif
@@ -142,7 +144,7 @@
 #if 1
 #define DEBUGPRN(x)
 #else
-#define DEBUGPRN(x) printk(KERN_INFO x "\n");
+#define DEBUGPRN(x) pr_info(x "\n");
 #endif
 
 /* --------------- Hardware Access Routines -------------------------- */
@@ -369,15 +371,15 @@
 	XGI_Pr->P3c9 = BaseAddr + 0x19;
 	XGI_Pr->P3da = BaseAddr + 0x2A;
 	/* Digital video interface registers (LCD) */
-	XGI_Pr->Part1Port = BaseAddr + XGI_CRT2_PORT_04;
+	XGI_Pr->Part1Port = BaseAddr + SIS_CRT2_PORT_04;
 	/* 301 TV Encoder registers */
-	XGI_Pr->Part2Port = BaseAddr + XGI_CRT2_PORT_10;
+	XGI_Pr->Part2Port = BaseAddr + SIS_CRT2_PORT_10;
 	/* 301 Macrovision registers */
-	XGI_Pr->Part3Port = BaseAddr + XGI_CRT2_PORT_12;
+	XGI_Pr->Part3Port = BaseAddr + SIS_CRT2_PORT_12;
 	/* 301 VGA2 (and LCD) registers */
-	XGI_Pr->Part4Port = BaseAddr + XGI_CRT2_PORT_14;
+	XGI_Pr->Part4Port = BaseAddr + SIS_CRT2_PORT_14;
 	/* 301 palette address port registers */
-	XGI_Pr->Part5Port = BaseAddr + XGI_CRT2_PORT_14 + 2;
+	XGI_Pr->Part5Port = BaseAddr + SIS_CRT2_PORT_14 + 2;
 
 }
 
@@ -424,7 +426,7 @@
 		i++;
 	}
 	if (!j)
-		printk(KERN_INFO "XGIfb: Invalid mode '%s'\n", name);
+		pr_info("Invalid mode '%s'\n", name);
 }
 
 static void XGIfb_search_vesamode(struct xgifb_video_info *xgifb_info,
@@ -449,7 +451,7 @@
 
 invalid:
 	if (!j)
-		printk(KERN_INFO "XGIfb: Invalid VESA mode 0x%x'\n", vesamode);
+		pr_info("Invalid VESA mode 0x%x'\n", vesamode);
 }
 
 static int XGIfb_validate_mode(struct xgifb_video_info *xgifb_info, int myindex)
@@ -526,12 +528,6 @@
 			xres = 1600;
 			yres = 1200;
 			break;
-		/* case LCD_320x480: */ /* TW: FSTN */
-			/*
-			xres =  320;
-			yres =  480;
-			break;
-			*/
 		default:
 			xres = 0;
 			yres = 0;
@@ -692,7 +688,7 @@
 		i++;
 	}
 	if (XGIfb_crt2type < 0)
-		printk(KERN_INFO "XGIfb: Invalid CRT2 type: %s\n", name);
+		pr_info("Invalid CRT2 type: %s\n", name);
 }
 
 static u8 XGIfb_search_refresh_rate(struct xgifb_video_info *xgifb_info,
@@ -742,7 +738,7 @@
 	if (xgifb_info->rate_idx > 0) {
 		return xgifb_info->rate_idx;
 	} else {
-		printk(KERN_INFO "XGIfb: Unsupported rate %d for %dx%d\n",
+		pr_info("Unsupported rate %d for %dx%d\n",
 		       rate, xres, yres);
 		return 0;
 	}
@@ -811,27 +807,27 @@
 
 	switch (xgifb_info->display2) {
 	case XGIFB_DISP_CRT:
-		cr30 = (XGI_VB_OUTPUT_CRT2 | XGI_SIMULTANEOUS_VIEW_ENABLE);
-		cr31 |= XGI_DRIVER_MODE;
+		cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		cr31 |= SIS_DRIVER_MODE;
 		break;
 	case XGIFB_DISP_LCD:
-		cr30 = (XGI_VB_OUTPUT_LCD | XGI_SIMULTANEOUS_VIEW_ENABLE);
-		cr31 |= XGI_DRIVER_MODE;
+		cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		cr31 |= SIS_DRIVER_MODE;
 		break;
 	case XGIFB_DISP_TV:
 		if (xgifb_info->TV_type == TVMODE_HIVISION)
-			cr30 = (XGI_VB_OUTPUT_HIVISION
-					| XGI_SIMULTANEOUS_VIEW_ENABLE);
+			cr30 = (SIS_VB_OUTPUT_HIVISION
+					| SIS_SIMULTANEOUS_VIEW_ENABLE);
 		else if (xgifb_info->TV_plug == TVPLUG_SVIDEO)
-			cr30 = (XGI_VB_OUTPUT_SVIDEO
-					| XGI_SIMULTANEOUS_VIEW_ENABLE);
+			cr30 = (SIS_VB_OUTPUT_SVIDEO
+					| SIS_SIMULTANEOUS_VIEW_ENABLE);
 		else if (xgifb_info->TV_plug == TVPLUG_COMPOSITE)
-			cr30 = (XGI_VB_OUTPUT_COMPOSITE
-					| XGI_SIMULTANEOUS_VIEW_ENABLE);
+			cr30 = (SIS_VB_OUTPUT_COMPOSITE
+					| SIS_SIMULTANEOUS_VIEW_ENABLE);
 		else if (xgifb_info->TV_plug == TVPLUG_SCART)
-			cr30 = (XGI_VB_OUTPUT_SCART
-					| XGI_SIMULTANEOUS_VIEW_ENABLE);
-		cr31 |= XGI_DRIVER_MODE;
+			cr30 = (SIS_VB_OUTPUT_SCART
+					| SIS_SIMULTANEOUS_VIEW_ENABLE);
+		cr31 |= SIS_DRIVER_MODE;
 
 		if (XGIfb_tvmode == 1 || xgifb_info->TV_type == TVMODE_PAL)
 			cr31 |= 0x01;
@@ -840,7 +836,7 @@
 		break;
 	default: /* disable CRT2 */
 		cr30 = 0x00;
-		cr31 |= (XGI_DRIVER_MODE | XGI_VB_OUTPUT_DISABLE);
+		cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
 	}
 
 	xgifb_reg_set(XGICR, IND_XGI_SCRATCH_REG_CR30, cr30);
@@ -854,7 +850,7 @@
 	u8 reg;
 	unsigned char doit = 1;
 	/*
-	xgifb_reg_set(XGISR,IND_XGI_PASSWORD,XGI_PASSWORD);
+	xgifb_reg_set(XGISR,IND_SIS_PASSWORD,SIS_PASSWORD);
 	xgifb_reg_set(XGICR, 0x13, 0x00);
 	xgifb_reg_and_or(XGISR,0x0E, 0xF0, 0x01);
 	*test*
@@ -890,7 +886,7 @@
 		reg |= 0x80;
 	xgifb_reg_set(XGICR, 0x17, reg);
 
-	xgifb_reg_and(XGISR, IND_XGI_RAMDAC_CONTROL, ~0x04);
+	xgifb_reg_and(XGISR, IND_SIS_RAMDAC_CONTROL, ~0x04);
 
 	if (xgifb_info->display2 == XGIFB_DISP_TV &&
 	    xgifb_info->hasVB == HASVB_301) {
@@ -923,7 +919,7 @@
 				break;
 			}
 			xgifb_reg_or(XGIPART1,
-				     IND_XGI_CRT2_WRITE_ENABLE_315,
+				     SIS_CRT2_WENABLE_315,
 				     0x01);
 
 			if (xgifb_info->TV_type == TVMODE_NTSC) {
@@ -1118,7 +1114,7 @@
 	if (!htotal || !vtotal) {
 		DPRINTK("XGIfb: Invalid 'var' information\n");
 		return -EINVAL;
-	} printk(KERN_DEBUG "XGIfb: var->pixclock=%d, htotal=%d, vtotal=%d\n",
+	} pr_debug("var->pixclock=%d, htotal=%d, vtotal=%d\n",
 			var->pixclock, htotal, vtotal);
 
 	if (var->pixclock && htotal && vtotal) {
@@ -1130,7 +1126,7 @@
 		xgifb_info->refresh_rate = 60;
 	}
 
-	printk(KERN_DEBUG "XGIfb: Change mode to %dx%dx%d-%dHz\n",
+	pr_debug("Change mode to %dx%dx%d-%dHz\n",
 	       var->xres,
 	       var->yres,
 	       var->bits_per_pixel,
@@ -1158,7 +1154,7 @@
 		xgifb_info->mode_idx = -1;
 
 	if (xgifb_info->mode_idx < 0) {
-		printk(KERN_ERR "XGIfb: Mode %dx%dx%d not supported\n",
+		pr_err("Mode %dx%dx%d not supported\n",
 		       var->xres, var->yres, var->bits_per_pixel);
 		xgifb_info->mode_idx = old_mode;
 		return -EINVAL;
@@ -1177,14 +1173,14 @@
 		if (XGISetModeNew(xgifb_info, hw_info,
 				  XGIbios_mode[xgifb_info->mode_idx].mode_no)
 					== 0) {
-			printk(KERN_ERR "XGIfb: Setting mode[0x%x] failed\n",
+			pr_err("Setting mode[0x%x] failed\n",
 			       XGIbios_mode[xgifb_info->mode_idx].mode_no);
 			return -EINVAL;
 		}
 		info->fix.line_length = ((info->var.xres_virtual
 				* info->var.bits_per_pixel) >> 6);
 
-		xgifb_reg_set(XGISR, IND_XGI_PASSWORD, XGI_PASSWORD);
+		xgifb_reg_set(XGISR, IND_SIS_PASSWORD, SIS_PASSWORD);
 
 		xgifb_reg_set(XGICR, 0x13, (info->fix.line_length & 0x00ff));
 		xgifb_reg_set(XGISR,
@@ -1239,7 +1235,7 @@
 			break;
 		default:
 			xgifb_info->video_cmap_len = 16;
-			printk(KERN_ERR "XGIfb: Unsupported depth %d",
+			pr_err("Unsupported depth %d",
 			       xgifb_info->video_bpp);
 			break;
 		}
@@ -1273,7 +1269,7 @@
 		break;
 	}
 
-	xgifb_reg_set(XGISR, IND_XGI_PASSWORD, XGI_PASSWORD);
+	xgifb_reg_set(XGISR, IND_SIS_PASSWORD, SIS_PASSWORD);
 
 	xgifb_reg_set(XGICR, 0x0D, base & 0xFF);
 	xgifb_reg_set(XGICR, 0x0C, (base >> 8) & 0xFF);
@@ -1282,7 +1278,7 @@
 	xgifb_reg_and_or(XGISR, 0x37, 0xDF, (base >> 21) & 0x04);
 
 	if (xgifb_info->display2 != XGIFB_DISP_NONE) {
-		xgifb_reg_or(XGIPART1, IND_XGI_CRT2_WRITE_ENABLE_315, 0x01);
+		xgifb_reg_or(XGIPART1, SIS_CRT2_WENABLE_315, 0x01);
 		xgifb_reg_set(XGIPART1, 0x06, (base & 0xFF));
 		xgifb_reg_set(XGIPART1, 0x05, ((base >> 8) & 0xFF));
 		xgifb_reg_set(XGIPART1, 0x04, ((base >> 16) & 0xFF));
@@ -1387,7 +1383,7 @@
 	fix->line_length = xgifb_info->video_linelength;
 	fix->mmio_start = xgifb_info->mmio_base;
 	fix->mmio_len = xgifb_info->mmio_size;
-	fix->accel = FB_ACCEL_XGI_XABRE;
+	fix->accel = FB_ACCEL_SIS_XABRE;
 
 	DEBUGPRN("end of get_fix");
 	return 0;
@@ -1441,7 +1437,7 @@
 		hrate = (drate * 1000) / htotal;
 		xgifb_info->refresh_rate =
 			(unsigned int) (hrate * 2 / vtotal);
-		printk(KERN_DEBUG
+		pr_debug(
 			"%s: pixclock = %d ,htotal=%d, vtotal=%d\n"
 			"%s: drate=%d, hrate=%d, refresh_rate=%d\n",
 			__func__, var->pixclock, htotal, vtotal,
@@ -1479,7 +1475,7 @@
 
 	if (!found_mode) {
 
-		printk(KERN_ERR "XGIfb: %dx%dx%d is no valid mode\n",
+		pr_err("%dx%dx%d is no valid mode\n",
 			var->xres, var->yres, var->bits_per_pixel);
 		search_idx = 0;
 		while (XGIbios_mode[search_idx].mode_no != 0) {
@@ -1498,11 +1494,11 @@
 		if (found_mode) {
 			var->xres = XGIbios_mode[search_idx].xres;
 			var->yres = XGIbios_mode[search_idx].yres;
-			printk(KERN_DEBUG "XGIfb: Adapted to mode %dx%dx%d\n",
+			pr_debug("Adapted to mode %dx%dx%d\n",
 				var->xres, var->yres, var->bits_per_pixel);
 
 		} else {
-			printk(KERN_ERR "XGIfb: Failed to find similar mode to %dx%dx%d\n",
+			pr_err("Failed to find similar mode to %dx%dx%d\n",
 				var->xres, var->yres, var->bits_per_pixel);
 			return -EINVAL;
 		}
@@ -1634,9 +1630,9 @@
 
 	/* xorg driver sets 32MB * 1 channel */
 	if (xgifb_info->chip == XG27)
-		xgifb_reg_set(XGISR, IND_XGI_DRAM_SIZE, 0x51);
+		xgifb_reg_set(XGISR, IND_SIS_DRAM_SIZE, 0x51);
 
-	reg = xgifb_reg_get(XGISR, IND_XGI_DRAM_SIZE);
+	reg = xgifb_reg_get(XGISR, IND_SIS_DRAM_SIZE);
 	switch ((reg & XGI_DRAM_SIZE_MASK) >> 4) {
 	case XGI_DRAM_SIZE_1MB:
 		xgifb_info->video_size = 0x100000;
@@ -1711,7 +1707,7 @@
 	/* xgifb_info->video_size = 0x200000; */ /* 1024x768x16 */
 	/* xgifb_info->video_size = 0x1000000; */ /* benchmark */
 
-	printk("XGIfb: SR14=%x DramSzie %x ChannelNum %x\n",
+	pr_info("SR14=%x DramSzie %x ChannelNum %x\n",
 	       reg,
 	       xgifb_info->video_size, ChannelNum);
 	return 0;
@@ -1736,7 +1732,7 @@
 
 	cr32 = xgifb_reg_get(XGICR, IND_XGI_SCRATCH_REG_CR32);
 
-	if ((cr32 & XGI_CRT1) && !XGIfb_crt1off)
+	if ((cr32 & SIS_CRT1) && !XGIfb_crt1off)
 		XGIfb_crt1off = 0;
 	else {
 		if (cr32 & 0x5F)
@@ -1746,11 +1742,11 @@
 	}
 
 	if (!xgifb_info->display2_force) {
-		if (cr32 & XGI_VB_TV)
+		if (cr32 & SIS_VB_TV)
 			xgifb_info->display2 = XGIFB_DISP_TV;
-		else if (cr32 & XGI_VB_LCD)
+		else if (cr32 & SIS_VB_LCD)
 			xgifb_info->display2 = XGIFB_DISP_LCD;
-		else if (cr32 & XGI_VB_CRT2)
+		else if (cr32 & SIS_VB_CRT2)
 			xgifb_info->display2 = XGIFB_DISP_CRT;
 		else
 			xgifb_info->display2 = XGIFB_DISP_NONE;
@@ -1759,14 +1755,14 @@
 	if (XGIfb_tvplug != -1)
 		/* PR/TW: Override with option */
 		xgifb_info->TV_plug = XGIfb_tvplug;
-	else if (cr32 & XGI_VB_HIVISION) {
+	else if (cr32 & SIS_VB_HIVISION) {
 		xgifb_info->TV_type = TVMODE_HIVISION;
 		xgifb_info->TV_plug = TVPLUG_SVIDEO;
-	} else if (cr32 & XGI_VB_SVIDEO)
+	} else if (cr32 & SIS_VB_SVIDEO)
 		xgifb_info->TV_plug = TVPLUG_SVIDEO;
-	else if (cr32 & XGI_VB_COMPOSITE)
+	else if (cr32 & SIS_VB_COMPOSITE)
 		xgifb_info->TV_plug = TVPLUG_COMPOSITE;
-	else if (cr32 & XGI_VB_SCART)
+	else if (cr32 & SIS_VB_SCART)
 		xgifb_info->TV_plug = TVPLUG_SCART;
 
 	if (xgifb_info->TV_type == 0) {
@@ -1811,11 +1807,11 @@
 
 	if (!XGIfb_has_VB(xgifb_info)) {
 		reg = xgifb_reg_get(XGICR, IND_XGI_SCRATCH_REG_CR37);
-		switch ((reg & XGI_EXTERNAL_CHIP_MASK) >> 1) {
-		case XGI310_EXTERNAL_CHIP_LVDS:
+		switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) {
+		case SIS_EXTERNAL_CHIP_LVDS:
 			xgifb_info->hasVB = HASVB_LVDS;
 			break;
-		case XGI310_EXTERNAL_CHIP_LVDS_CHRONTEL:
+		case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
 			xgifb_info->hasVB = HASVB_LVDS_CHRONTEL;
 			break;
 		default:
@@ -1917,7 +1913,7 @@
 	xgifb_info->vga_base = pci_resource_start(pdev, 2) + 0x30;
 	hw_info->pjIOAddress = (unsigned char *)xgifb_info->vga_base;
 	/* XGI_Pr.RelIO  = ioremap(pci_resource_start(pdev, 2), 128) + 0x30; */
-	printk("XGIfb: Relocate IO address: %lx [%08lx]\n",
+	pr_info("Relocate IO address: %lx [%08lx]\n",
 	       (unsigned long)pci_resource_start(pdev, 2),
 	       xgifb_info->dev_info.RelIO);
 
@@ -1933,17 +1929,17 @@
 
 	XGIRegInit(&xgifb_info->dev_info, (unsigned long)hw_info->pjIOAddress);
 
-	xgifb_reg_set(XGISR, IND_XGI_PASSWORD, XGI_PASSWORD);
-	reg1 = xgifb_reg_get(XGISR, IND_XGI_PASSWORD);
+	xgifb_reg_set(XGISR, IND_SIS_PASSWORD, SIS_PASSWORD);
+	reg1 = xgifb_reg_get(XGISR, IND_SIS_PASSWORD);
 
 	if (reg1 != 0xa1) { /*I/O error */
-		printk("\nXGIfb: I/O error!!!");
+		pr_err("I/O error!!!");
 		ret = -EIO;
 		goto error;
 	}
 
 	switch (xgifb_info->chip_id) {
-	case PCI_DEVICE_ID_XG_20:
+	case PCI_DEVICE_ID_XGI_20:
 		xgifb_reg_or(XGICR, Index_CR_GPIO_Reg3, GPIOG_EN);
 		CR48 = xgifb_reg_get(XGICR, Index_CR_GPIO_Reg1);
 		if (CR48&GPIOG_READ)
@@ -1951,16 +1947,16 @@
 		else
 			xgifb_info->chip = XG20;
 		break;
-	case PCI_DEVICE_ID_XG_40:
+	case PCI_DEVICE_ID_XGI_40:
 		xgifb_info->chip = XG40;
 		break;
-	case PCI_DEVICE_ID_XG_41:
+	case PCI_DEVICE_ID_XGI_41:
 		xgifb_info->chip = XG41;
 		break;
-	case PCI_DEVICE_ID_XG_42:
+	case PCI_DEVICE_ID_XGI_42:
 		xgifb_info->chip = XG42;
 		break;
-	case PCI_DEVICE_ID_XG_27:
+	case PCI_DEVICE_ID_XGI_27:
 		xgifb_info->chip = XG27;
 		break;
 	default:
@@ -1968,31 +1964,31 @@
 		goto error;
 	}
 
-	printk("XGIfb:chipid = %x\n", xgifb_info->chip);
+	pr_info("chipid = %x\n", xgifb_info->chip);
 	hw_info->jChipType = xgifb_info->chip;
 
 	if (XGIfb_get_dram_size(xgifb_info)) {
-		printk(KERN_INFO "XGIfb: Fatal error: Unable to determine RAM size.\n");
+		pr_err("Fatal error: Unable to determine RAM size.\n");
 		ret = -ENODEV;
 		goto error;
 	}
 
 	/* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
 	xgifb_reg_or(XGISR,
-		     IND_XGI_PCI_ADDRESS_SET,
-		     (XGI_PCI_ADDR_ENABLE | XGI_MEM_MAP_IO_ENABLE));
+		     IND_SIS_PCI_ADDRESS_SET,
+		     (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
 	/* Enable 2D accelerator engine */
-	xgifb_reg_or(XGISR, IND_XGI_MODULE_ENABLE, XGI_ENABLE_2D);
+	xgifb_reg_or(XGISR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
 
 	hw_info->ulVideoMemorySize = xgifb_info->video_size;
 
 	if (!request_mem_region(xgifb_info->video_base,
 				xgifb_info->video_size,
 				"XGIfb FB")) {
-		printk("unable request memory size %x",
+		pr_err("unable request memory size %x\n",
 		       xgifb_info->video_size);
-		printk(KERN_ERR "XGIfb: Fatal error: Unable to reserve frame buffer memory\n");
-		printk(KERN_ERR "XGIfb: Is there another framebuffer driver active?\n");
+		pr_err("Fatal error: Unable to reserve frame buffer memory\n");
+		pr_err("Is there another framebuffer driver active?\n");
 		ret = -ENODEV;
 		goto error;
 	}
@@ -2000,7 +1996,7 @@
 	if (!request_mem_region(xgifb_info->mmio_base,
 				xgifb_info->mmio_size,
 				"XGIfb MMIO")) {
-		printk(KERN_ERR "XGIfb: Fatal error: Unable to reserve MMIO region\n");
+		pr_err("Fatal error: Unable to reserve MMIO region\n");
 		ret = -ENODEV;
 		goto error_0;
 	}
@@ -2010,20 +2006,18 @@
 	xgifb_info->mmio_vbase = ioremap(xgifb_info->mmio_base,
 					    xgifb_info->mmio_size);
 
-	printk(KERN_INFO "XGIfb: Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
+	pr_info("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
 	       xgifb_info->video_base,
 	       xgifb_info->video_vbase,
 	       xgifb_info->video_size / 1024);
 
-	printk(KERN_INFO "XGIfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
+	pr_info("MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
 	       xgifb_info->mmio_base, xgifb_info->mmio_vbase,
 	       xgifb_info->mmio_size / 1024);
-	printk("XGIfb: XGIInitNew() ...");
+
 	pci_set_drvdata(pdev, xgifb_info);
-	if (XGIInitNew(pdev))
-		printk("OK\n");
-	else
-		printk("Fail\n");
+	if (!XGIInitNew(pdev))
+		pr_err("XGIInitNew() failed!\n");
 
 	xgifb_info->mtrr = (unsigned int) 0;
 
@@ -2033,13 +2027,12 @@
 		xgifb_info->hasVB = HASVB_NONE;
 	} else if (xgifb_info->chip == XG21) {
 		CR38 = xgifb_reg_get(XGICR, 0x38);
-		if ((CR38&0xE0) == 0xC0) {
+		if ((CR38&0xE0) == 0xC0)
 			xgifb_info->display2 = XGIFB_DISP_LCD;
-		} else if ((CR38&0xE0) == 0x60) {
+		else if ((CR38&0xE0) == 0x60)
 			xgifb_info->hasVB = HASVB_CHRONTEL;
-		} else {
+		else
 			xgifb_info->hasVB = HASVB_NONE;
-		}
 	} else {
 		XGIfb_get_VB_type(xgifb_info);
 	}
@@ -2053,10 +2046,10 @@
 		reg = xgifb_reg_get(XGIPART4, 0x01);
 		if (reg >= 0xE0) {
 			hw_info->ujVBChipID = VB_CHIP_302LV;
-			printk(KERN_INFO "XGIfb: XGI302LV bridge detected (revision 0x%02x)\n", reg);
+			pr_info("XGI302LV bridge detected (revision 0x%02x)\n", reg);
 		} else if (reg >= 0xD0) {
 			hw_info->ujVBChipID = VB_CHIP_301LV;
-			printk(KERN_INFO "XGIfb: XGI301LV bridge detected (revision 0x%02x)\n", reg);
+			pr_info("XGI301LV bridge detected (revision 0x%02x)\n", reg);
 		}
 		/* else if (reg >= 0xB0) {
 			hw_info->ujVBChipID = VB_CHIP_301B;
@@ -2065,17 +2058,17 @@
 		} */
 		else {
 			hw_info->ujVBChipID = VB_CHIP_301;
-			printk("XGIfb: XGI301 bridge detected\n");
+			pr_info("XGI301 bridge detected\n");
 		}
 		break;
 	case HASVB_302:
 		reg = xgifb_reg_get(XGIPART4, 0x01);
 		if (reg >= 0xE0) {
 			hw_info->ujVBChipID = VB_CHIP_302LV;
-			printk(KERN_INFO "XGIfb: XGI302LV bridge detected (revision 0x%02x)\n", reg);
+			pr_info("XGI302LV bridge detected (revision 0x%02x)\n", reg);
 		} else if (reg >= 0xD0) {
 			hw_info->ujVBChipID = VB_CHIP_301LV;
-			printk(KERN_INFO "XGIfb: XGI302LV bridge detected (revision 0x%02x)\n", reg);
+			pr_info("XGI302LV bridge detected (revision 0x%02x)\n", reg);
 		} else if (reg >= 0xB0) {
 			reg1 = xgifb_reg_get(XGIPART4, 0x23);
 
@@ -2083,27 +2076,27 @@
 
 		} else {
 			hw_info->ujVBChipID = VB_CHIP_302;
-			printk(KERN_INFO "XGIfb: XGI302 bridge detected\n");
+			pr_info("XGI302 bridge detected\n");
 		}
 		break;
 	case HASVB_LVDS:
 		hw_info->ulExternalChip = 0x1;
-		printk(KERN_INFO "XGIfb: LVDS transmitter detected\n");
+		pr_info("LVDS transmitter detected\n");
 		break;
 	case HASVB_TRUMPION:
 		hw_info->ulExternalChip = 0x2;
-		printk(KERN_INFO "XGIfb: Trumpion Zurac LVDS scaler detected\n");
+		pr_info("Trumpion Zurac LVDS scaler detected\n");
 		break;
 	case HASVB_CHRONTEL:
 		hw_info->ulExternalChip = 0x4;
-		printk(KERN_INFO "XGIfb: Chrontel TV encoder detected\n");
+		pr_info("Chrontel TV encoder detected\n");
 		break;
 	case HASVB_LVDS_CHRONTEL:
 		hw_info->ulExternalChip = 0x5;
-		printk(KERN_INFO "XGIfb: LVDS transmitter and Chrontel TV encoder detected\n");
+		pr_info("LVDS transmitter and Chrontel TV encoder detected\n");
 		break;
 	default:
-		printk(KERN_INFO "XGIfb: No or unknown bridge type detected\n");
+		pr_info("No or unknown bridge type detected\n");
 		break;
 	}
 
@@ -2117,10 +2110,6 @@
 			reg = xgifb_reg_get(XGICR, IND_XGI_LCD_PANEL);
 			reg &= 0x0f;
 			hw_info->ulCRT2LCDType = XGI310paneltype[reg];
-
-		} else {
-			/* TW: FSTN/DSTN */
-			hw_info->ulCRT2LCDType = LCD_320x480;
 		}
 	}
 
@@ -2147,9 +2136,6 @@
 					if (tmp & 0x20) {
 						tmp = xgifb_reg_get(
 							XGIPART1, 0x13);
-						if (tmp & 0x04) {
-							/* XGI_Pr.XGI_UseLCDA = 1; */
-						}
 					}
 				}
 			}
@@ -2222,12 +2208,12 @@
 		break;
 	default:
 		xgifb_info->video_cmap_len = 16;
-		printk(KERN_INFO "XGIfb: Unsupported depth %d",
+		pr_info("Unsupported depth %d\n",
 		       xgifb_info->video_bpp);
 		break;
 	}
 
-	printk(KERN_INFO "XGIfb: Default mode is %dx%dx%d (%dHz)\n",
+	pr_info("Default mode is %dx%dx%d (%dHz)\n",
 	       xgifb_info->video_width,
 	       xgifb_info->video_height,
 	       xgifb_info->video_bpp,
@@ -2404,7 +2390,7 @@
 static void __exit xgifb_remove_module(void)
 {
 	pci_unregister_driver(&xgifb_driver);
-	printk(KERN_DEBUG "xgifb: Module unloaded\n");
+	pr_debug("Module unloaded\n");
 }
 
 module_exit(xgifb_remove_module);
diff --git a/drivers/staging/xgifb/XGIfb.h b/drivers/staging/xgifb/XGIfb.h
index 2c866bb..37bb730 100644
--- a/drivers/staging/xgifb/XGIfb.h
+++ b/drivers/staging/xgifb/XGIfb.h
@@ -3,8 +3,8 @@
 #include <linux/ioctl.h>
 #include <linux/types.h>
 
-#include "vb_struct.h"
 #include "vgatypes.h"
+#include "vb_struct.h"
 
 enum xgifb_display_type {
 	XGIFB_DISP_NONE = 0,
diff --git a/drivers/staging/xgifb/vb_def.h b/drivers/staging/xgifb/vb_def.h
index 5beeef9..c731793 100644
--- a/drivers/staging/xgifb/vb_def.h
+++ b/drivers/staging/xgifb/vb_def.h
@@ -1,153 +1,48 @@
 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/xgi/initdef.h
  * ,v 1.4 2000/12/02 01:16:17 dawes Exp $*/
-#ifndef _INITDEF_
-#define _INITDEF_
+#ifndef _VB_DEF_
+#define _VB_DEF_
+#include "../../video/sis/initdef.h"
 
 #define VB_XGI301C      0x0020 /* for 301C */
-/*end 301b*/
-
-#define VB_YPbPr525p    0x01
-#define VB_YPbPr750p    0x02
 #define VB_YPbPr1080i   0x03
 
 #define LVDSCRT1Len     15
-
-#define SupportCHTV             0x0800
 #define SupportCRT2in301C       0x0100  /* for 301C */
 #define SetCHTVOverScan         0x8000
-#define PanelRGB18Bit           0x0100
-#define PanelRGB24Bit           0x0000
 
-#define Panel320x480            0x07 /*fstn*/
+#define Panel_320x480            0x07 /*fstn*/
 /* [ycchen] 02/12/03 Modify for Multi-Sync. LCD Support */
 #define PanelResInfo            0x1F /* CR36 Panel Type/LCDResInfo */
-#define Panel800x600            0x01
-#define Panel1024x768           0x02
-#define Panel1024x768x75        0x22
-#define Panel1280x1024          0x03
-#define Panel1280x1024x75       0x23
-#define Panel640x480            0x04
-#define Panel1280x960           0x07
-#define Panel1400x1050          0x09
-#define Panel1600x1200          0x0B
+#define Panel_1024x768x75        0x22
+#define Panel_1280x1024x75       0x23
 
 #define PanelRef60Hz            0x00
 #define PanelRef75Hz            0x20
 
-#define CRT2DisplayFlag         0x2000
-
 #define YPbPr525iVCLK           0x03B
 #define YPbPr525iVCLK_2         0x03A
 
 #define XGI_CRT2_PORT_00        (0x00 - 0x030)
-#define XGI_CRT2_PORT_04        (0x04 - 0x030)
-#define XGI_CRT2_PORT_10        (0x10 - 0x30)
-#define XGI_CRT2_PORT_12        (0x12 - 0x30)
-#define XGI_CRT2_PORT_14        (0x14 - 0x30)
-
-#define _PanelType00             0x00
-#define _PanelType01             0x08
-#define _PanelType02             0x10
-#define _PanelType03             0x18
-#define _PanelType04             0x20
-#define _PanelType05             0x28
-#define _PanelType06             0x30
-#define _PanelType07             0x38
-#define _PanelType08             0x40
-#define _PanelType09             0x48
-#define _PanelType0A             0x50
-#define _PanelType0B             0x58
-#define _PanelType0C             0x60
-#define _PanelType0D             0x68
-#define _PanelType0E             0x70
-#define _PanelType0F             0x78
 
 /* =============================================================
    for 310
 ============================================================== */
-/* add LCDDataList for GetLCDPtr */
-#define LCDDataList               (VBIOSTablePointerStart+0x22)
-/*  */
-/* Modify from 310.inc */
-/*  */
-/*  */
-
 #define ModeSoftSetting              0x04
 
-#define BoardTVType                  0x02
-
-#define SoftDRAMType                 0x80    /* DRAMSetting */
-
 /* ---------------- SetMode Stack */
 #define CRT1Len           15
 #define VCLKLen           4
-#define VGA_XGI340        0x0001       /* 340 series */
-
-#define VB_XGI301         0x0001       /* VB Type Info */
-#define VB_XGI301B        0x0002       /* 301 series */
-#define VB_XGI302B        0x0004
-#define VB_NoLCD          0x8000
-#define VB_XGI301LV       0x0008
-#define VB_XGI302LV       0x0010
-#define VB_LVDS_NS        0x0001       /* 3rd party chip */
-
-#define ModeInfoFlag      0x0007
-#define ModeText          0x0000
-#define ModeEGA           0x0002    /* 16 colors mode */
-#define ModeVGA           0x0003    /* 256 colors mode */
-
-#define DACInfoFlag       0x0018
-
-#define MemoryInfoFlag    0x01e0
-#define MemorySizeShift   5
-
-#define Charx8Dot         0x0200
-#define LineCompareOff    0x0400
-#define CRT2Mode          0x0800
-#define HalfDCLK          0x1000
-#define NoSupportSimuTV   0x2000
-#define DoubleScanMode    0x8000
-
-/* -------------- Ext_InfoFlag */
-#define Support16Bpp        0x0005
-#define Support32Bpp        0x0007
 
 #define SupportAllCRT2      0x0078
-#define SupportTV           0x0008
-#define SupportHiVisionTV   0x0010
-#define SupportLCD          0x0020
-#define SupportRAMDAC2      0x0040
 #define NoSupportTV         0x0070
 #define NoSupportHiVisionTV 0x0060
 #define NoSupportLCD        0x0058
-#define SupportTV1024       0x0800 /* 301btest */
-#define SupportYPbPr        0x1000 /* 301lv */
-#define InterlaceMode       0x0080
-#define SyncPP              0x0000
-#define SyncPN              0x4000
-#define SyncNP              0x8000
-#define SyncNN              0xC000
 
 /* -------------- SetMode Stack/Scratch */
-#define SetSimuScanMode     0x0001    /* VBInfo/CR30 & CR31 */
-#define SwitchToCRT2        0x0002
-#define SetCRT2ToTV         0x089C
-#define SetCRT2ToAVIDEO     0x0004
-#define SetCRT2ToSVIDEO     0x0008
-#define SetCRT2ToSCART      0x0010
-#define SetCRT2ToLCD        0x0020
-#define SetCRT2ToRAMDAC     0x0040
-#define SetCRT2ToHiVisionTV 0x0080
-#define SetCRT2ToLCDA       0x0100
-#define SetInSlaveMode      0x0200
-#define SetNotSimuMode      0x0400
-#define SetCRT2ToYPbPr      0x0800
-#define LoadDACFlag         0x1000
-#define DisableCRT2Display  0x2000
-#define DriverMode          0x4000
+#define XGI_SetCRT2ToLCDA   0x0100
 #define SetCRT2ToDualEdge   0x8000
 
-#define ProgrammingCRT2     0x0001       /* Set Flag */
 #define ReserveTVOption     0x0008
 #define GatingCRT           0x0800
 #define DisableChB          0x1000
@@ -155,23 +50,14 @@
 #define DisableChA          0x4000
 #define EnableChA           0x8000
 
-#define SetNTSCTV           0x0000 /* TV Info */
-#define SetPALTV            0x0001
-#define SetNTSCJ            0x0002
-#define SetPALMTV           0x0004
-#define SetPALNTV           0x0008
-#define SetYPbPrMode525i     0x0020
-#define SetYPbPrMode525p     0x0040
-#define SetYPbPrMode750p     0x0080
-#define SetYPbPrMode1080i    0x0100
 #define SetTVLowResolution   0x0400
 #define TVSimuMode           0x0800
 #define RPLLDIV2XO           0x1000
 #define NTSC1024x768         0x2000
 #define SetTVLockMode        0x4000
 
-#define LCDVESATiming        0x0001 /* LCD Info/CR37 */
-#define EnableLVDSDDA        0x0002
+#define XGI_LCDVESATiming    0x0001 /* LCD Info/CR37 */
+#define XGI_EnableLVDSDDA    0x0002
 #define EnableScalingLCD     0x0008
 #define SetPWDEnable         0x0004
 #define SetLCDtoNonExpanding 0x0010
@@ -184,7 +70,7 @@
 #define EnableLCD24bpp       0x0004 /* default */
 #define DisableLCD24bpp      0x0000
 #define LCDPolarity          0x00c0 /* default: SyncNN */
-#define LCDDualLink          0x0100
+#define XGI_LCDDualLink      0x0100
 #define EnableSpectrum       0x0200
 #define PWDEnable            0x0400
 #define EnableVBCLKDRVLOW    0x4000
@@ -206,31 +92,21 @@
 
 #define TVSense              0xc7
 
-#define TVOverScan           0x10               /* CR35 */
-
 #define YPbPrMode            0xe0
 #define YPbPrMode525i        0x00
 #define YPbPrMode525p        0x20
 #define YPbPrMode750p        0x40
 #define YPbPrMode1080i       0x60
 
-
-#define LCDRGB18Bit          0x01               /* CR37 */
-#define LCDNonExpanding      0x10
-#define LCDSync              0x20
-#define LCDSyncBit           0xe0 /* H/V polarity & sync ID */
-
 #define ScalingLCD           0x08
 
-#define EnableDualEdge       0x01 /* CR38 */
-#define SetToLCDA            0x02
 #define SetYPbPr             0x04
 
 /* ---------------------- VUMA Information */
 #define DisplayDeviceFromCMOS 0x10
 
 /* ---------------------- HK Evnet Definition */
-#define ModeSwitchStatus      0xf0
+#define XGI_ModeSwitchStatus  0xf0
 #define ActiveCRT1            0x10
 #define ActiveLCD             0x0020
 #define ActiveTV              0x40
@@ -246,28 +122,13 @@
 /* translated from asm code 301def.h */
 /*  */
 /* --------------------------------------------------------- */
-#define LCDDataLen           8
-#define TVDataLen            12
 #define LVDSCRT1Len_H        8
 #define LVDSCRT1Len_V        7
-#define LVDSDataLen          6
-#define LVDSDesDataLen       6
 #define LCDDesDataLen        6
 #define LVDSDesDataLen2      8
 #define LCDDesDataLen2       8
-#define CHTVRegLen           16
 
-#define StHiTVHT             892
-#define StHiTVVT             1126
-#define StHiTextTVHT         1000
-#define StHiTextTVVT         1126
-#define ExtHiTVHT            2100
-#define ExtHiTVVT            1125
-#define NTSCHT               1716
-#define NTSCVT                525
 #define NTSC1024x768HT       1908
-#define PALHT                1728
-#define PALVT                 625
 
 #define YPbPrTV525iHT        1716 /* YPbPr */
 #define YPbPrTV525iVT         525
@@ -276,22 +137,16 @@
 #define YPbPrTV750pHT        1650
 #define YPbPrTV750pVT         750
 
-#define CRT2Delay1           0x04 /* XGI301 */
-#define CRT2Delay2           0x0A /* 301B,302 */
-
-
 #define VCLK25_175           0x00
 #define VCLK28_322           0x01
 #define VCLK31_5             0x02
 #define VCLK36               0x03
-#define VCLK40               0x04
 #define VCLK43_163           0x05
 #define VCLK44_9             0x06
 #define VCLK49_5             0x07
 #define VCLK50               0x08
 #define VCLK52_406           0x09
 #define VCLK56_25            0x0A
-#define VCLK65               0x0B
 #define VCLK68_179           0x0D
 #define VCLK72_852           0x0E
 #define VCLK75               0x0F
@@ -300,7 +155,6 @@
 #define VCLK83_95            0x13
 #define VCLK86_6             0x15
 #define VCLK94_5             0x16
-#define VCLK108_2            0x19
 #define VCLK113_309          0x1B
 #define VCLK116_406          0x1C
 #define VCLK135_5            0x1E
@@ -327,16 +181,10 @@
 #define VCLK125_999          0x51
 #define VCLK148_5            0x52
 #define VCLK217_325          0x55
-#define YPbPr750pVCLK        0x57
+#define XGI_YPbPr750pVCLK    0x57
 
-#define TVVCLKDIV2           0x3A
-#define TVVCLK               0x3B
-#define HiTVVCLKDIV2         0x3C
-#define HiTVVCLK             0x3D
-#define HiTVSimuVCLK         0x3E
-#define HiTVTextVCLK         0x3F
 #define VCLK39_77            0x40
-#define YPbPr525pVCLK           0x3A
+#define YPbPr525pVCLK        0x3A
 #define NTSC1024VCLK         0x41
 #define VCLK35_2             0x49 /* ; 800x480 */
 #define VCLK122_61           0x4A
diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c
index 4ccd988..94d5c35 100644
--- a/drivers/staging/xgifb/vb_init.c
+++ b/drivers/staging/xgifb/vb_init.c
@@ -3,8 +3,8 @@
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 
-#include "vgatypes.h"
 #include "XGIfb.h"
+#include "vgatypes.h"
 
 #include "vb_def.h"
 #include "vb_struct.h"
@@ -1268,7 +1268,7 @@
 
 				if (pVBInfo->IF_DEF_HiVision == 1) {
 					if ((temp >> 8) & ActiveHiTV)
-						tempcl |= SetCRT2ToHiVisionTV;
+						tempcl |= SetCRT2ToHiVision;
 				}
 
 				if (pVBInfo->IF_DEF_YPbPr == 1) {
@@ -1287,7 +1287,7 @@
 
 		if (pVBInfo->IF_DEF_HiVision == 1) {
 			if ((temp >> 8) & ActiveHiTV)
-				tempcl |= SetCRT2ToHiVisionTV;
+				tempcl |= SetCRT2ToHiVision;
 		}
 
 		if (pVBInfo->IF_DEF_YPbPr == 1) {
@@ -1299,9 +1299,9 @@
 	tempcl |= SetSimuScanMode;
 	if ((!(temp & ActiveCRT1)) && ((temp & ActiveLCD) || (temp & ActiveTV)
 			|| (temp & ActiveCRT2)))
-		tempcl ^= (SetSimuScanMode | SwitchToCRT2);
+		tempcl ^= (SetSimuScanMode | SwitchCRT2);
 	if ((temp & ActiveLCD) && (temp & ActiveTV))
-		tempcl ^= (SetSimuScanMode | SwitchToCRT2);
+		tempcl ^= (SetSimuScanMode | SwitchCRT2);
 	xgifb_reg_set(pVBInfo->P3d4, 0x30, tempcl);
 
 	CR31Data = xgifb_reg_get(pVBInfo->P3d4, 0x31);
@@ -1516,11 +1516,11 @@
 	pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19;
 	pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A;
 	pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00;
-	pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04;
-	pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10;
-	pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12;
-	pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14;
-	pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2;
+	pVBInfo->Part1Port = pVBInfo->BaseAddr + SIS_CRT2_PORT_04;
+	pVBInfo->Part2Port = pVBInfo->BaseAddr + SIS_CRT2_PORT_10;
+	pVBInfo->Part3Port = pVBInfo->BaseAddr + SIS_CRT2_PORT_12;
+	pVBInfo->Part4Port = pVBInfo->BaseAddr + SIS_CRT2_PORT_14;
+	pVBInfo->Part5Port = pVBInfo->BaseAddr + SIS_CRT2_PORT_14 + 2;
 	printk("5");
 
 	if (HwDeviceExtension->jChipType < XG20) /* kuku 2004/06/25 */
diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c
index 67a316c..2919924 100644
--- a/drivers/staging/xgifb/vb_setmode.c
+++ b/drivers/staging/xgifb/vb_setmode.c
@@ -61,20 +61,20 @@
 void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo)
 {
 	pVBInfo->SModeIDTable = (struct XGI_StStruct *) XGI330_SModeIDTable;
-	pVBInfo->StandTable = (struct XGI_StandTableStruct *) XGI330_StandTable;
+	pVBInfo->StandTable = (struct SiS_StandTable_S *) XGI330_StandTable;
 	pVBInfo->EModeIDTable = (struct XGI_ExtStruct *) XGI330_EModeIDTable;
 	pVBInfo->RefIndex = (struct XGI_Ext2Struct *) XGI330_RefIndex;
 	pVBInfo->XGINEWUB_CRT1Table
 			= (struct XGI_CRT1TableStruct *) XGI_CRT1Table;
 
-	pVBInfo->MCLKData = (struct XGI_MCLKDataStruct *) XGI340New_MCLKData;
+	pVBInfo->MCLKData = (struct SiS_MCLKData *) XGI340New_MCLKData;
 	pVBInfo->ECLKData = (struct XGI_ECLKDataStruct *) XGI340_ECLKData;
-	pVBInfo->VCLKData = (struct XGI_VCLKDataStruct *) XGI_VCLKData;
-	pVBInfo->VBVCLKData = (struct XGI_VBVCLKDataStruct *) XGI_VBVCLKData;
+	pVBInfo->VCLKData = (struct SiS_VCLKData *) XGI_VCLKData;
+	pVBInfo->VBVCLKData = (struct SiS_VBVCLKData *) XGI_VBVCLKData;
 	pVBInfo->ScreenOffset = XGI330_ScreenOffset;
-	pVBInfo->StResInfo = (struct XGI_StResInfoStruct *) XGI330_StResInfo;
+	pVBInfo->StResInfo = (struct SiS_StResInfo_S *) XGI330_StResInfo;
 	pVBInfo->ModeResInfo
-			= (struct XGI_ModeResInfoStruct *) XGI330_ModeResInfo;
+			= (struct SiS_ModeResInfo_S *) XGI330_ModeResInfo;
 
 	pVBInfo->pOutputSelect = &XGI330_OutputSelect;
 	pVBInfo->pSoftSetting = &XGI330_SoftSetting;
@@ -138,7 +138,7 @@
 	pVBInfo->UpdateCRT1 = (struct XGI_XG21CRT1Struct *) XGI_UpdateCRT1Table;
 
 	/* 310 customization related */
-	if ((pVBInfo->VBType & VB_XGI301LV) || (pVBInfo->VBType & VB_XGI302LV))
+	if ((pVBInfo->VBType & VB_SIS301LV) || (pVBInfo->VBType & VB_SIS302LV))
 		pVBInfo->LCDCapList = XGI_LCDDLCapList;
 	else
 		pVBInfo->LCDCapList = XGI_LCDCapList;
@@ -153,7 +153,7 @@
 
 	if (ChipType == XG27) {
 		pVBInfo->MCLKData
-			= (struct XGI_MCLKDataStruct *) XGI27New_MCLKData;
+			= (struct SiS_MCLKData *) XGI27New_MCLKData;
 		pVBInfo->CR40 = XGI27_cr41;
 		pVBInfo->pXGINew_CR97 = &XG27_CR97;
 		pVBInfo->pSR36 = &XG27_SR36;
@@ -208,8 +208,8 @@
 	xgifb_reg_set(pVBInfo->P3c4, 0x00, 0x03); /* Set SR0 */
 	tempah = pVBInfo->StandTable[StandTableIndex].SR[0];
 
-	i = SetCRT2ToLCDA;
-	if (pVBInfo->VBInfo & SetCRT2ToLCDA) {
+	i = XGI_SetCRT2ToLCDA;
+	if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
 		tempah |= 0x01;
 	} else {
 		if (pVBInfo->VBInfo & (SetCRT2ToTV | SetCRT2ToLCD)) {
@@ -263,7 +263,7 @@
 		ARdata = pVBInfo->StandTable[StandTableIndex].ATTR[i];
 		if (modeflag & Charx8Dot) { /* ifndef Dot9 */
 			if (i == 0x13) {
-				if (pVBInfo->VBInfo & SetCRT2ToLCDA) {
+				if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
 					ARdata = 0;
 				} else {
 					if (pVBInfo->VBInfo & (SetCRT2ToTV
@@ -356,11 +356,11 @@
 		}
 
 		/* 301b */
-		if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+		if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
 			tempax |= SupportLCD;
 
-			if (pVBInfo->LCDResInfo != Panel1280x1024) {
-				if (pVBInfo->LCDResInfo != Panel1280x960) {
+			if (pVBInfo->LCDResInfo != Panel_1280x1024) {
+				if (pVBInfo->LCDResInfo != Panel_1280x960) {
 					if (pVBInfo->LCDInfo &
 					    LCDNonExpanding) {
 						if (resinfo >= 9) {
@@ -372,10 +372,10 @@
 			}
 		}
 
-		if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV) { /* for HiTV */
-			if ((pVBInfo->VBType & VB_XGI301LV) &&
+		if (pVBInfo->VBInfo & SetCRT2ToHiVision) { /* for HiTV */
+			if ((pVBInfo->VBType & VB_SIS301LV) &&
 			    (pVBInfo->VBExtInfo == VB_YPbPr1080i)) {
-				tempax |= SupportYPbPr;
+				tempax |= SupportYPbPr750p;
 				if (pVBInfo->VBInfo & SetInSlaveMode) {
 					if (resinfo == 4)
 						return 0;
@@ -387,7 +387,7 @@
 						return 0;
 				}
 			} else {
-				tempax |= SupportHiVisionTV;
+				tempax |= SupportHiVision;
 				if (pVBInfo->VBInfo & SetInSlaveMode) {
 					if (resinfo == 4)
 						return 0;
@@ -406,17 +406,17 @@
 			if (pVBInfo->VBInfo & (SetCRT2ToAVIDEO |
 					       SetCRT2ToSVIDEO |
 					       SetCRT2ToSCART |
-					       SetCRT2ToYPbPr |
-					       SetCRT2ToHiVisionTV)) {
+					       SetCRT2ToYPbPr525750 |
+					       SetCRT2ToHiVision)) {
 				tempax |= SupportTV;
 
-				if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B
-						| VB_XGI301LV | VB_XGI302LV
+				if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B
+						| VB_SIS301LV | VB_SIS302LV
 						| VB_XGI301C)) {
 					tempax |= SupportTV1024;
 				}
 
-				if (!(pVBInfo->VBInfo & SetPALTV)) {
+				if (!(pVBInfo->VBInfo & TVSetPAL)) {
 					if (modeflag & NoSupportSimuTV) {
 						if (pVBInfo->VBInfo &
 						    SetInSlaveMode) {
@@ -436,7 +436,7 @@
 			if (resinfo > 0x08)
 				return 0; /* 1024x768 */
 
-			if (pVBInfo->LCDResInfo < Panel1024x768) {
+			if (pVBInfo->LCDResInfo < Panel_1024x768) {
 				if (resinfo > 0x07)
 					return 0; /* 800x600 */
 
@@ -1230,23 +1230,23 @@
 		struct xgi_hw_device_info *HwDeviceExtension,
 		struct vb_device_info *pVBInfo)
 {
-	unsigned short LCDXlat1VCLK[4] = { VCLK65 + 2,
-					   VCLK65 + 2,
-					   VCLK65 + 2,
-					   VCLK65 + 2 };
-	unsigned short LCDXlat2VCLK[4] = { VCLK108_2 + 5,
-					   VCLK108_2 + 5,
-					   VCLK108_2 + 5,
-					   VCLK108_2 + 5 };
+	unsigned short LCDXlat1VCLK[4] = { VCLK65_315 + 2,
+					   VCLK65_315 + 2,
+					   VCLK65_315 + 2,
+					   VCLK65_315 + 2 };
+	unsigned short LCDXlat2VCLK[4] = { VCLK108_2_315 + 5,
+					   VCLK108_2_315 + 5,
+					   VCLK108_2_315 + 5,
+					   VCLK108_2_315 + 5 };
 	unsigned short LVDSXlat1VCLK[4] = { VCLK40, VCLK40, VCLK40, VCLK40 };
-	unsigned short LVDSXlat2VCLK[4] = { VCLK65 + 2,
-					    VCLK65 + 2,
-					    VCLK65 + 2,
-					    VCLK65 + 2 };
-	unsigned short LVDSXlat3VCLK[4] = { VCLK65 + 2,
-					    VCLK65 + 2,
-					    VCLK65 + 2,
-					    VCLK65 + 2 };
+	unsigned short LVDSXlat2VCLK[4] = { VCLK65_315 + 2,
+					    VCLK65_315 + 2,
+					    VCLK65_315 + 2,
+					    VCLK65_315 + 2 };
+	unsigned short LVDSXlat3VCLK[4] = { VCLK65_315 + 2,
+					    VCLK65_315 + 2,
+					    VCLK65_315 + 2,
+					    VCLK65_315 + 2 };
 
 	unsigned short CRT2Index, VCLKIndex;
 	unsigned short modeflag, resinfo;
@@ -1266,36 +1266,36 @@
 
 	if (pVBInfo->IF_DEF_LVDS == 0) {
 		CRT2Index = CRT2Index >> 6; /*  for LCD */
-		if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { /*301b*/
-			if (pVBInfo->LCDResInfo != Panel1024x768)
+		if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) { /*301b*/
+			if (pVBInfo->LCDResInfo != Panel_1024x768)
 				VCLKIndex = LCDXlat2VCLK[CRT2Index];
 			else
 				VCLKIndex = LCDXlat1VCLK[CRT2Index];
-		} else if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV) {
+		} else if (pVBInfo->VBInfo & SetCRT2ToHiVision) {
 			if (pVBInfo->SetFlag & RPLLDIV2XO) {
-				VCLKIndex = HiTVVCLKDIV2;
+				VCLKIndex = TVCLKBASE_315 + HiTVVCLKDIV2;
 				VCLKIndex += 25;
 			} else {
-				VCLKIndex = HiTVVCLK;
+				VCLKIndex = TVCLKBASE_315 + HiTVVCLK;
 				VCLKIndex += 25;
 			}
 
 			if (pVBInfo->SetFlag & TVSimuMode) {
 				if (modeflag & Charx8Dot) {
-					VCLKIndex = HiTVSimuVCLK;
+					VCLKIndex = TVCLKBASE_315 + HiTVSimuVCLK;
 					VCLKIndex += 25;
 				} else {
-					VCLKIndex = HiTVTextVCLK;
+					VCLKIndex = TVCLKBASE_315 + HiTVTextVCLK;
 					VCLKIndex += 25;
 				}
 			}
 
 			/* 301lv */
-			if ((pVBInfo->VBType & VB_XGI301LV) &&
+			if ((pVBInfo->VBType & VB_SIS301LV) &&
 			    !(pVBInfo->VBExtInfo == VB_YPbPr1080i)) {
-				if (pVBInfo->VBExtInfo == VB_YPbPr750p)
-					VCLKIndex = YPbPr750pVCLK;
-				else if (pVBInfo->VBExtInfo == VB_YPbPr525p)
+				if (pVBInfo->VBExtInfo == YPbPr750p)
+					VCLKIndex = XGI_YPbPr750pVCLK;
+				else if (pVBInfo->VBExtInfo == YPbPr525p)
 					VCLKIndex = YPbPr525pVCLK;
 				else if (pVBInfo->SetFlag & RPLLDIV2XO)
 					VCLKIndex = YPbPr525iVCLK_2;
@@ -1304,10 +1304,10 @@
 			}
 		} else if (pVBInfo->VBInfo & SetCRT2ToTV) {
 			if (pVBInfo->SetFlag & RPLLDIV2XO) {
-				VCLKIndex = TVVCLKDIV2;
+				VCLKIndex = TVCLKBASE_315 + TVVCLKDIV2;
 				VCLKIndex += 25;
 			} else {
-				VCLKIndex = TVVCLK;
+				VCLKIndex = TVCLKBASE_315 + TVVCLK;
 				VCLKIndex += 25;
 			}
 		} else { /* for CRT2 */
@@ -1329,11 +1329,11 @@
 			VCLKIndex = CRT2Index;
 
 		VCLKIndex = VCLKIndex >> 6;
-		if ((pVBInfo->LCDResInfo == Panel800x600) ||
-		    (pVBInfo->LCDResInfo == Panel320x480))
+		if ((pVBInfo->LCDResInfo == Panel_800x600) ||
+		    (pVBInfo->LCDResInfo == Panel_320x480))
 			VCLKIndex = LVDSXlat1VCLK[VCLKIndex];
-		else if ((pVBInfo->LCDResInfo == Panel1024x768) ||
-			 (pVBInfo->LCDResInfo == Panel1024x768x75))
+		else if ((pVBInfo->LCDResInfo == Panel_1024x768) ||
+			 (pVBInfo->LCDResInfo == Panel_1024x768x75))
 			VCLKIndex = LVDSXlat2VCLK[VCLKIndex];
 		else
 			VCLKIndex = LVDSXlat3VCLK[VCLKIndex];
@@ -1360,9 +1360,9 @@
 		xgifb_reg_set(pVBInfo->P3c4, 0x2C,
 				pVBInfo->VCLKData[index].SR2C);
 		xgifb_reg_set(pVBInfo->P3c4, 0x2D, 0x01);
-	} else if ((pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-			| VB_XGI302LV | VB_XGI301C)) && (pVBInfo->VBInfo
-			& SetCRT2ToLCDA)) {
+	} else if ((pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+			| VB_SIS302LV | VB_XGI301C)) && (pVBInfo->VBInfo
+			& XGI_SetCRT2ToLCDA)) {
 		vclkindex = XGI_GetVCLK2Ptr(ModeNo, ModeIdIndex,
 				RefreshRateTableIndex, HwDeviceExtension,
 				pVBInfo);
@@ -1801,7 +1801,7 @@
 					Ext_CRT2CRTC;
 		}
 
-		if (pVBInfo->VBInfo & SetCRT2ToLCDA) {
+		if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
 			if (ModeNo <= 0x13)
 				tempal = pVBInfo->SModeIDTable[ModeIdIndex].
 						St_CRT2CRTC2;
@@ -2128,30 +2128,30 @@
 			return &XGI_CetLCDDes1024x768Data[tempal];
 			break;
 		case 3:
-			if ((pVBInfo->VBType & VB_XGI301LV) ||
-				(pVBInfo->VBType & VB_XGI302LV))
+			if ((pVBInfo->VBType & VB_SIS301LV) ||
+				(pVBInfo->VBType & VB_SIS302LV))
 				return &XGI_ExtLCDDLDes1280x1024Data[tempal];
 			else
 				return &XGI_ExtLCDDes1280x1024Data[tempal];
 			break;
 		case 4:
-			if ((pVBInfo->VBType & VB_XGI301LV) ||
-			    (pVBInfo->VBType & VB_XGI302LV))
+			if ((pVBInfo->VBType & VB_SIS301LV) ||
+			    (pVBInfo->VBType & VB_SIS302LV))
 				return &XGI_StLCDDLDes1280x1024Data[tempal];
 			else
 				return &XGI_StLCDDes1280x1024Data[tempal];
 			break;
 		case 5:
-			if ((pVBInfo->VBType & VB_XGI301LV) ||
-			    (pVBInfo->VBType & VB_XGI302LV))
+			if ((pVBInfo->VBType & VB_SIS301LV) ||
+			    (pVBInfo->VBType & VB_SIS302LV))
 				return &XGI_CetLCDDLDes1280x1024Data[tempal];
 			else
 				return &XGI_CetLCDDes1280x1024Data[tempal];
 			break;
 		case 6:
 		case 7:
-			if ((pVBInfo->VBType & VB_XGI301LV) ||
-			    (pVBInfo->VBType & VB_XGI302LV))
+			if ((pVBInfo->VBType & VB_SIS301LV) ||
+			    (pVBInfo->VBType & VB_SIS302LV))
 				return &xgifb_lcddldes_1400x1050[tempal];
 			else
 				return &xgifb_lcddes_1400x1050[tempal];
@@ -2163,15 +2163,15 @@
 			return &XGI_CetLCDDes1400x1050Data2[tempal];
 			break;
 		case 10:
-			if ((pVBInfo->VBType & VB_XGI301LV) ||
-			    (pVBInfo->VBType & VB_XGI302LV))
+			if ((pVBInfo->VBType & VB_SIS301LV) ||
+			    (pVBInfo->VBType & VB_SIS302LV))
 				return &XGI_ExtLCDDLDes1600x1200Data[tempal];
 			else
 				return &XGI_ExtLCDDes1600x1200Data[tempal];
 			break;
 		case 11:
-			if ((pVBInfo->VBType & VB_XGI301LV) ||
-			    (pVBInfo->VBType & VB_XGI302LV))
+			if ((pVBInfo->VBType & VB_SIS301LV) ||
+			    (pVBInfo->VBType & VB_SIS302LV))
 				return &XGI_StLCDDLDes1600x1200Data[tempal];
 			else
 				return &XGI_StLCDDes1600x1200Data[tempal];
@@ -2188,15 +2188,15 @@
 			break;
 		case 16:
 		case 17:
-			if ((pVBInfo->VBType & VB_XGI301LV) ||
-			    (pVBInfo->VBType & VB_XGI302LV))
+			if ((pVBInfo->VBType & VB_SIS301LV) ||
+			    (pVBInfo->VBType & VB_SIS302LV))
 				return &xgifb_lcddldes_1280x1024x75[tempal];
 			else
 				return &xgifb_lcddes_1280x1024x75[tempal];
 			break;
 		case 18:
-			if ((pVBInfo->VBType & VB_XGI301LV) ||
-			    (pVBInfo->VBType & VB_XGI302LV))
+			if ((pVBInfo->VBType & VB_SIS301LV) ||
+			    (pVBInfo->VBType & VB_SIS302LV))
 				return &XGI_CetLCDDLDes1280x1024x75Data[tempal];
 			else
 				return &XGI_CetLCDDes1280x1024x75Data[tempal];
@@ -2364,7 +2364,7 @@
 
 	tempbx = 2;
 
-	if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+	if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
 		LCDPtr = (struct XGI330_LVDSDataStruct *) XGI_GetLcdPtr(tempbx,
 				ModeNo, ModeIdIndex, RefreshRateTableIndex,
 				pVBInfo);
@@ -2374,18 +2374,18 @@
 		pVBInfo->VT = LCDPtr->LCDVT;
 	}
 
-	if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+	if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
 		if (!(pVBInfo->LCDInfo & (SetLCDtoNonExpanding
 				| EnableScalingLCD))) {
-			if ((pVBInfo->LCDResInfo == Panel1024x768) ||
-			    (pVBInfo->LCDResInfo == Panel1024x768x75)) {
+			if ((pVBInfo->LCDResInfo == Panel_1024x768) ||
+			    (pVBInfo->LCDResInfo == Panel_1024x768x75)) {
 				pVBInfo->HDE = 1024;
 				pVBInfo->VDE = 768;
-			} else if ((pVBInfo->LCDResInfo == Panel1280x1024) ||
-				   (pVBInfo->LCDResInfo == Panel1280x1024x75)) {
+			} else if ((pVBInfo->LCDResInfo == Panel_1280x1024) ||
+				   (pVBInfo->LCDResInfo == Panel_1280x1024x75)) {
 				pVBInfo->HDE = 1280;
 				pVBInfo->VDE = 1024;
-			} else if (pVBInfo->LCDResInfo == Panel1400x1050) {
+			} else if (pVBInfo->LCDResInfo == Panel_1400x1050) {
 				pVBInfo->HDE = 1400;
 				pVBInfo->VDE = 1050;
 			} else {
@@ -2415,7 +2415,7 @@
 
 	tempbx = 0;
 
-	if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+	if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
 		LCDPtr = (struct XGI_LVDSCRT1HDataStruct *)
 				XGI_GetLcdPtr(tempbx, ModeNo,
 					      ModeIdIndex,
@@ -2430,7 +2430,7 @@
 
 	tempbx = 1;
 
-	if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+	if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
 		LCDPtr1 = (struct XGI_LVDSCRT1VDataStruct *)
 				XGI_GetLcdPtr(
 					tempbx,
@@ -2496,7 +2496,7 @@
 	}
 
 	if (tempbl == 0xFF) {
-		pVBInfo->LCDResInfo = Panel1024x768;
+		pVBInfo->LCDResInfo = Panel_1024x768;
 		pVBInfo->LCDTypeInfo = 0;
 		i = 0;
 	}
@@ -2556,15 +2556,15 @@
 	push2 = tempax;
 
 	/* GetLCDResInfo */
-	if ((pVBInfo->LCDResInfo == Panel1024x768) ||
-	    (pVBInfo->LCDResInfo == Panel1024x768x75)) {
+	if ((pVBInfo->LCDResInfo == Panel_1024x768) ||
+	    (pVBInfo->LCDResInfo == Panel_1024x768x75)) {
 		tempax = 1024;
 		tempbx = 768;
-	} else if ((pVBInfo->LCDResInfo == Panel1280x1024) ||
-		   (pVBInfo->LCDResInfo == Panel1280x1024x75)) {
+	} else if ((pVBInfo->LCDResInfo == Panel_1280x1024) ||
+		   (pVBInfo->LCDResInfo == Panel_1280x1024x75)) {
 		tempax = 1280;
 		tempbx = 1024;
-	} else if (pVBInfo->LCDResInfo == Panel1400x1050) {
+	} else if (pVBInfo->LCDResInfo == Panel_1400x1050) {
 		tempax = 1400;
 		tempbx = 1050;
 	} else {
@@ -2682,7 +2682,7 @@
 	if (tempbx != pVBInfo->VDE)
 		tempax |= 0x40;
 
-	if (pVBInfo->LCDInfo & EnableLVDSDDA)
+	if (pVBInfo->LCDInfo & XGI_EnableLVDSDDA)
 		tempax |= 0x40;
 
 	xgifb_reg_and_or(pVBInfo->Part1Port, 0x1a, 0x07,
@@ -2768,7 +2768,7 @@
 	temp1 = temp1 / push3;
 	tempbx = (unsigned short) (temp1 & 0xffff);
 
-	if (pVBInfo->LCDResInfo == Panel1024x768)
+	if (pVBInfo->LCDResInfo == Panel_1024x768)
 		tempbx -= 1;
 
 	tempax = ((tempbx >> 8) & 0xff) << 3;
@@ -2800,7 +2800,7 @@
 {
 	unsigned short index;
 
-	if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+	if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
 		index = XGI_GetLCDCapPtr1(pVBInfo);
 
 		if (pVBInfo->VBInfo & SetCRT2ToLCD) { /* LCDB */
@@ -2834,35 +2834,35 @@
 		index = XGI_GetLCDCapPtr(pVBInfo);
 		tempal = pVBInfo->LCDCapList[index].LCD_VCLK;
 
-		if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA))
+		if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA))
 			return tempal;
 
 		/* {TV} */
 		if (pVBInfo->VBType &
-		    (VB_XGI301B |
-		     VB_XGI302B |
-		     VB_XGI301LV |
-		     VB_XGI302LV |
+		    (VB_SIS301B |
+		     VB_SIS302B |
+		     VB_SIS301LV |
+		     VB_SIS302LV |
 		     VB_XGI301C)) {
-			if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV) {
-				tempal = HiTVVCLKDIV2;
+			if (pVBInfo->VBInfo & SetCRT2ToHiVision) {
+				tempal = TVCLKBASE_315 + HiTVVCLKDIV2;
 				if (!(pVBInfo->TVInfo & RPLLDIV2XO))
-					tempal = HiTVVCLK;
+					tempal = TVCLKBASE_315 + HiTVVCLK;
 				if (pVBInfo->TVInfo & TVSimuMode) {
-					tempal = HiTVSimuVCLK;
+					tempal = TVCLKBASE_315 + HiTVSimuVCLK;
 					if (!(modeflag & Charx8Dot))
-						tempal = HiTVTextVCLK;
+						tempal = TVCLKBASE_315 + HiTVTextVCLK;
 
 				}
 				return tempal;
 			}
 
-			if (pVBInfo->TVInfo & SetYPbPrMode750p) {
-				tempal = YPbPr750pVCLK;
+			if (pVBInfo->TVInfo & TVSetYPbPr750p) {
+				tempal = XGI_YPbPr750pVCLK;
 				return tempal;
 			}
 
-			if (pVBInfo->TVInfo & SetYPbPrMode525p) {
+			if (pVBInfo->TVInfo & TVSetYPbPr525p) {
 				tempal = YPbPr525pVCLK;
 				return tempal;
 			}
@@ -2870,9 +2870,9 @@
 			tempal = NTSC1024VCLK;
 
 			if (!(pVBInfo->TVInfo & NTSC1024x768)) {
-				tempal = TVVCLKDIV2;
+				tempal = TVCLKBASE_315 + TVVCLKDIV2;
 				if (!(pVBInfo->TVInfo & RPLLDIV2XO))
-					tempal = TVVCLK;
+					tempal = TVCLKBASE_315 + TVVCLK;
 			}
 
 			if (pVBInfo->VBInfo & SetCRT2ToTV)
@@ -2898,9 +2898,9 @@
 static void XGI_GetVCLKLen(unsigned char tempal, unsigned char *di_0,
 		unsigned char *di_1, struct vb_device_info *pVBInfo)
 {
-	if (pVBInfo->VBType & (VB_XGI301 | VB_XGI301B | VB_XGI302B
-			| VB_XGI301LV | VB_XGI302LV | VB_XGI301C)) {
-		if ((!(pVBInfo->VBInfo & SetCRT2ToLCDA)) && (pVBInfo->SetFlag
+	if (pVBInfo->VBType & (VB_SIS301 | VB_SIS301B | VB_SIS302B
+			| VB_SIS301LV | VB_SIS302LV | VB_XGI301C)) {
+		if ((!(pVBInfo->VBInfo & XGI_SetCRT2ToLCDA)) && (pVBInfo->SetFlag
 				& ProgrammingCRT2)) {
 			*di_0 = (unsigned char) XGI_VBVCLKData[tempal].SR2B;
 			*di_1 = XGI_VBVCLKData[tempal].SR2C;
@@ -2926,7 +2926,7 @@
 	for (i = 0; i < 4; i++) {
 		xgifb_reg_and_or(pVBInfo->P3d4, 0x31, ~0x30,
 				(unsigned short) (0x10 * i));
-		if ((!(pVBInfo->VBInfo & SetCRT2ToLCDA))
+		if ((!(pVBInfo->VBInfo & XGI_SetCRT2ToLCDA))
 				&& (!(pVBInfo->VBInfo & SetInSlaveMode))) {
 			xgifb_reg_set(pVBInfo->P3c4, 0x2e, di_0);
 			xgifb_reg_set(pVBInfo->P3c4, 0x2f, di_1);
@@ -2942,8 +2942,8 @@
 {
 	unsigned short tempcl, tempch, temp, tempbl, tempax;
 
-	if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-			| VB_XGI302LV | VB_XGI301C)) {
+	if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+			| VB_SIS302LV | VB_XGI301C)) {
 		tempcl = 0;
 		tempch = 0;
 		temp = xgifb_reg_get(pVBInfo->P3c4, 0x01);
@@ -2987,12 +2987,12 @@
 				if (temp & 0x02)
 					tempch |= ActiveSCART;
 
-				if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV) {
+				if (pVBInfo->VBInfo & SetCRT2ToHiVision) {
 					if (temp & 0x01)
 						tempch |= ActiveHiTV;
 				}
 
-				if (pVBInfo->VBInfo & SetCRT2ToYPbPr) {
+				if (pVBInfo->VBInfo & SetCRT2ToYPbPr525750) {
 					temp = xgifb_reg_get(
 							pVBInfo->Part2Port,
 							0x4d);
@@ -3014,7 +3014,7 @@
 			}
 		}
 		temp = tempcl;
-		tempbl = ~ModeSwitchStatus;
+		tempbl = ~XGI_ModeSwitchStatus;
 		xgifb_reg_and_or(pVBInfo->P3d4, 0x3d, tempbl, temp);
 
 		if (!(pVBInfo->SetFlag & ReserveTVOption))
@@ -3029,19 +3029,19 @@
 	unsigned short flag, tempbx, tempah;
 
 	if (pVBInfo->IF_DEF_LVDS == 0) {
-		tempbx = VB_XGI302B;
+		tempbx = VB_SIS302B;
 		flag = xgifb_reg_get(pVBInfo->Part4Port, 0x00);
 		if (flag != 0x02) {
-			tempbx = VB_XGI301;
+			tempbx = VB_SIS301;
 			flag = xgifb_reg_get(pVBInfo->Part4Port, 0x01);
 			if (flag >= 0xB0) {
-				tempbx = VB_XGI301B;
+				tempbx = VB_SIS301B;
 				if (flag >= 0xC0) {
 					tempbx = VB_XGI301C;
 					if (flag >= 0xD0) {
-						tempbx = VB_XGI301LV;
+						tempbx = VB_SIS301LV;
 						if (flag >= 0xE0) {
-							tempbx = VB_XGI302LV;
+							tempbx = VB_SIS302LV;
 							tempah = xgifb_reg_get(
 							    pVBInfo->Part4Port,
 							    0x39);
@@ -3052,7 +3052,7 @@
 					}
 				}
 
-				if (tempbx & (VB_XGI301B | VB_XGI302B)) {
+				if (tempbx & (VB_SIS301B | VB_SIS302B)) {
 					flag = xgifb_reg_get(
 							pVBInfo->Part4Port,
 							0x23);
@@ -3078,7 +3078,7 @@
 		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
 	pVBInfo->SetFlag = 0;
-	pVBInfo->ModeType = modeflag & ModeInfoFlag;
+	pVBInfo->ModeType = modeflag & ModeTypeMask;
 	tempbx = 0;
 
 	if (pVBInfo->VBType & 0xFFFF) {
@@ -3090,7 +3090,7 @@
 		push = push << 8;
 		tempax = temp << 8;
 		tempbx = tempbx | tempax;
-		temp = (SetCRT2ToDualEdge | SetCRT2ToYPbPr | SetCRT2ToLCDA
+		temp = (SetCRT2ToDualEdge | SetCRT2ToYPbPr525750 | XGI_SetCRT2ToLCDA
 				| SetInSlaveMode | DisableCRT2Display);
 		temp = 0xFFFF ^ temp;
 		tempbx &= temp;
@@ -3103,9 +3103,9 @@
 			    (HwDeviceExtension->jChipType >= XG40)) {
 				if (pVBInfo->IF_DEF_LVDS == 0) {
 					if (pVBInfo->VBType &
-					    (VB_XGI302B |
-					     VB_XGI301LV |
-					     VB_XGI302LV |
+					    (VB_SIS302B |
+					     VB_SIS301LV |
+					     VB_SIS302LV |
 					     VB_XGI301C)) {
 						if (temp & EnableDualEdge) {
 							tempbx |=
@@ -3113,7 +3113,7 @@
 
 							if (temp & SetToLCDA)
 								tempbx |=
-								  SetCRT2ToLCDA;
+								  XGI_SetCRT2ToLCDA;
 						}
 					}
 				}
@@ -3123,8 +3123,8 @@
 		if (pVBInfo->IF_DEF_YPbPr == 1) {
 			/* [Billy] 07/05/04 */
 			if (((pVBInfo->IF_DEF_LVDS == 0) &&
-			    ((pVBInfo->VBType & VB_XGI301LV) ||
-			    (pVBInfo->VBType & VB_XGI302LV) ||
+			    ((pVBInfo->VBType & VB_SIS301LV) ||
+			    (pVBInfo->VBType & VB_SIS302LV) ||
 			    (pVBInfo->VBType & VB_XGI301C)))) {
 				if (temp & SetYPbPr) {
 					if (pVBInfo->IF_DEF_HiVision == 1) {
@@ -3134,13 +3134,13 @@
 								pVBInfo->P3d4,
 								0x35);
 						temp &= YPbPrMode;
-						tempbx |= SetCRT2ToHiVisionTV;
+						tempbx |= SetCRT2ToHiVision;
 
 						if (temp != YPbPrMode1080i) {
 							tempbx &=
-							 (~SetCRT2ToHiVisionTV);
+							 (~SetCRT2ToHiVision);
 							tempbx |=
-							 SetCRT2ToYPbPr;
+							 SetCRT2ToYPbPr525750;
 						}
 					}
 				}
@@ -3172,30 +3172,30 @@
 
 		if (pVBInfo->IF_DEF_LCDA == 1) { /* Select Display Device */
 			if (!(pVBInfo->VBType & VB_NoLCD)) {
-				if (tempbx & SetCRT2ToLCDA) {
+				if (tempbx & XGI_SetCRT2ToLCDA) {
 					if (tempbx & SetSimuScanMode)
 						tempbx &= (~(SetCRT2ToLCD |
 							   SetCRT2ToRAMDAC |
-							   SwitchToCRT2));
+							   SwitchCRT2));
 					else
 						tempbx &= (~(SetCRT2ToLCD |
 							     SetCRT2ToRAMDAC |
 							     SetCRT2ToTV |
-							     SwitchToCRT2));
+							     SwitchCRT2));
 				}
 			}
 		}
 
 		/* shampoo add */
 		/* for driver abnormal */
-		if (!(tempbx & (SwitchToCRT2 | SetSimuScanMode))) {
+		if (!(tempbx & (SwitchCRT2 | SetSimuScanMode))) {
 			if (pVBInfo->IF_DEF_CRT2Monitor == 1) {
 				if (tempbx & SetCRT2ToRAMDAC) {
 					tempbx &= (0xFF00 |
 						   SetCRT2ToRAMDAC |
-						   SwitchToCRT2 |
+						   SwitchCRT2 |
 						   SetSimuScanMode);
-					tempbx &= (0x00FF | (~SetCRT2ToYPbPr));
+					tempbx &= (0x00FF | (~SetCRT2ToYPbPr525750));
 				}
 			} else {
 				tempbx &= (~(SetCRT2ToRAMDAC |
@@ -3208,37 +3208,37 @@
 			if (tempbx & SetCRT2ToLCD) {
 				tempbx &= (0xFF00 |
 					   SetCRT2ToLCD |
-					   SwitchToCRT2 |
+					   SwitchCRT2 |
 					   SetSimuScanMode);
-				tempbx &= (0x00FF | (~SetCRT2ToYPbPr));
+				tempbx &= (0x00FF | (~SetCRT2ToYPbPr525750));
 			}
 		}
 
 		if (tempbx & SetCRT2ToSCART) {
 			tempbx &= (0xFF00 |
 				   SetCRT2ToSCART |
-				   SwitchToCRT2 |
+				   SwitchCRT2 |
 				   SetSimuScanMode);
-			tempbx &= (0x00FF | (~SetCRT2ToYPbPr));
+			tempbx &= (0x00FF | (~SetCRT2ToYPbPr525750));
 		}
 
 		if (pVBInfo->IF_DEF_YPbPr == 1) {
-			if (tempbx & SetCRT2ToYPbPr)
+			if (tempbx & SetCRT2ToYPbPr525750)
 				tempbx &= (0xFF00 |
-					   SwitchToCRT2 |
+					   SwitchCRT2 |
 					   SetSimuScanMode);
 		}
 
 		if (pVBInfo->IF_DEF_HiVision == 1) {
-			if (tempbx & SetCRT2ToHiVisionTV)
+			if (tempbx & SetCRT2ToHiVision)
 				tempbx &= (0xFF00 |
-					   SetCRT2ToHiVisionTV |
-					   SwitchToCRT2 |
+					   SetCRT2ToHiVision |
+					   SwitchCRT2 |
 					   SetSimuScanMode);
 		}
 
 		if (tempax & DisableCRT2Display) { /* Set Display Device Info */
-			if (!(tempbx & (SwitchToCRT2 | SetSimuScanMode)))
+			if (!(tempbx & (SwitchCRT2 | SetSimuScanMode)))
 				tempbx = DisableCRT2Display;
 		}
 
@@ -3246,7 +3246,7 @@
 			if ((!(tempbx & DriverMode)) ||
 			    (!(modeflag & CRT2Mode))) {
 				if (pVBInfo->IF_DEF_LCDA == 1) {
-					if (!(tempbx & SetCRT2ToLCDA))
+					if (!(tempbx & XGI_SetCRT2ToLCDA))
 						tempbx |= (SetInSlaveMode |
 							   SetSimuScanMode);
 				}
@@ -3255,9 +3255,9 @@
 			/* LCD+TV can't support in slave mode
 			 * (Force LCDA+TV->LCDB) */
 			if ((tempbx & SetInSlaveMode) &&
-			    (tempbx & SetCRT2ToLCDA)) {
+			    (tempbx & XGI_SetCRT2ToLCDA)) {
 				tempbx ^= (SetCRT2ToLCD |
-					  SetCRT2ToLCDA |
+					  XGI_SetCRT2ToLCDA |
 					  SetCRT2ToDualEdge);
 				pVBInfo->SetFlag |= ReserveTVOption;
 			}
@@ -3291,43 +3291,43 @@
 		if (pVBInfo->VBInfo & SetCRT2ToTV) {
 			temp = xgifb_reg_get(pVBInfo->P3d4, 0x35);
 			tempbx = temp;
-			if (tempbx & SetPALTV) {
+			if (tempbx & TVSetPAL) {
 				tempbx &= (SetCHTVOverScan |
-					   SetPALMTV |
-					   SetPALNTV |
-					   SetPALTV);
-				if (tempbx & SetPALMTV)
+					   TVSetPALM |
+					   TVSetPALN |
+					   TVSetPAL);
+				if (tempbx & TVSetPALM)
 					/* set to NTSC if PAL-M */
-					tempbx &= ~SetPALTV;
+					tempbx &= ~TVSetPAL;
 			} else
 				tempbx &= (SetCHTVOverScan |
-					   SetNTSCJ |
-					   SetPALTV);
+					   TVSetNTSCJ |
+					   TVSetPAL);
 		}
 
 		if (pVBInfo->IF_DEF_LVDS == 0) {
 			if (pVBInfo->VBInfo & SetCRT2ToSCART)
-				tempbx |= SetPALTV;
+				tempbx |= TVSetPAL;
 		}
 
 		if (pVBInfo->IF_DEF_YPbPr == 1) {
-			if (pVBInfo->VBInfo & SetCRT2ToYPbPr) {
+			if (pVBInfo->VBInfo & SetCRT2ToYPbPr525750) {
 				index1 = xgifb_reg_get(pVBInfo->P3d4, 0x35);
 				index1 &= YPbPrMode;
 
 				if (index1 == YPbPrMode525i)
-					tempbx |= SetYPbPrMode525i;
+					tempbx |= TVSetYPbPr525i;
 
 				if (index1 == YPbPrMode525p)
-					tempbx = tempbx | SetYPbPrMode525p;
+					tempbx = tempbx | TVSetYPbPr525p;
 				if (index1 == YPbPrMode750p)
-					tempbx = tempbx | SetYPbPrMode750p;
+					tempbx = tempbx | TVSetYPbPr750p;
 			}
 		}
 
 		if (pVBInfo->IF_DEF_HiVision == 1) {
-			if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV)
-				tempbx = tempbx | SetYPbPrMode1080i | SetPALTV;
+			if (pVBInfo->VBInfo & SetCRT2ToHiVision)
+				tempbx = tempbx | TVSetHiVision | TVSetPAL;
 		}
 
 		if (pVBInfo->IF_DEF_LVDS == 0) { /* shampoo */
@@ -3335,25 +3335,25 @@
 			    (!(pVBInfo->VBInfo & SetNotSimuMode)))
 				tempbx |= TVSimuMode;
 
-			if (!(tempbx & SetPALTV) &&
+			if (!(tempbx & TVSetPAL) &&
 			    (modeflag > 13) &&
 			    (resinfo == 8)) /* NTSC 1024x768, */
 				tempbx |= NTSC1024x768;
 
 			tempbx |= RPLLDIV2XO;
 
-			if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV) {
+			if (pVBInfo->VBInfo & SetCRT2ToHiVision) {
 				if (pVBInfo->VBInfo & SetInSlaveMode)
 					tempbx &= (~RPLLDIV2XO);
 			} else {
 				if (tempbx &
-				    (SetYPbPrMode525p | SetYPbPrMode750p))
+				    (TVSetYPbPr525p | TVSetYPbPr750p))
 					tempbx &= (~RPLLDIV2XO);
 				else if (!(pVBInfo->VBType &
-					 (VB_XGI301B |
-					  VB_XGI302B |
-					  VB_XGI301LV |
-					  VB_XGI302LV |
+					 (VB_SIS301B |
+					  VB_SIS302B |
+					  VB_SIS301LV |
+					  VB_SIS302LV |
 					  VB_XGI301C))) {
 					if (tempbx & TVSimuMode)
 						tempbx &= (~RPLLDIV2XO);
@@ -3386,13 +3386,13 @@
 	tempbx = temp & 0x0F;
 
 	if (tempbx == 0)
-		tempbx = Panel1024x768; /* default */
+		tempbx = Panel_1024x768; /* default */
 
 	/* LCD75 [2003/8/22] Vicent */
-	if ((tempbx == Panel1024x768) || (tempbx == Panel1280x1024)) {
+	if ((tempbx == Panel_1024x768) || (tempbx == Panel_1280x1024)) {
 		if (pVBInfo->VBInfo & DriverMode) {
 			tempax = xgifb_reg_get(pVBInfo->P3d4, 0x33);
-			if (pVBInfo->VBInfo & SetCRT2ToLCDA)
+			if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA)
 				tempax &= 0x0F;
 			else
 				tempax = tempax >> 4;
@@ -3411,7 +3411,7 @@
 
 	/* End of LCD75 */
 
-	if (!(pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)))
+	if (!(pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)))
 		return 0;
 
 	tempbx = 0;
@@ -3427,30 +3427,30 @@
 	tempax = pVBInfo->LCDCapList[LCDIdIndex].LCD_Capability;
 
 	if (pVBInfo->IF_DEF_LVDS == 0) { /* shampoo */
-		if (((pVBInfo->VBType & VB_XGI302LV) || (pVBInfo->VBType
-				& VB_XGI301C)) && (tempax & LCDDualLink)) {
+		if (((pVBInfo->VBType & VB_SIS302LV) || (pVBInfo->VBType
+				& VB_XGI301C)) && (tempax & XGI_LCDDualLink)) {
 			tempbx |= SetLCDDualLink;
 		}
 	}
 
 	if (pVBInfo->IF_DEF_LVDS == 0) {
-		if ((pVBInfo->LCDResInfo == Panel1400x1050) && (pVBInfo->VBInfo
+		if ((pVBInfo->LCDResInfo == Panel_1400x1050) && (pVBInfo->VBInfo
 				& SetCRT2ToLCD) && (ModeNo > 0x13) && (resinfo
 				== 9) && (!(tempbx & EnableScalingLCD)))
-			/* set to center in 1280x1024 LCDB for Panel1400x1050 */
+			/* set to center in 1280x1024 LCDB for Panel_1400x1050 */
 			tempbx |= SetLCDtoNonExpanding;
 	}
 
 	if (pVBInfo->IF_DEF_ExpLink == 1) {
 		if (modeflag & HalfDCLK) {
 			if (!(tempbx & SetLCDtoNonExpanding)) {
-				tempbx |= EnableLVDSDDA;
+				tempbx |= XGI_EnableLVDSDDA;
 			} else {
 				if (ModeNo > 0x13) {
 					if (pVBInfo->LCDResInfo
-							== Panel1024x768) {
+							== Panel_1024x768) {
 						if (resinfo == 4) {/* 512x384 */
-							tempbx |= EnableLVDSDDA;
+							tempbx |= XGI_EnableLVDSDDA;
 						}
 					}
 				}
@@ -3460,9 +3460,9 @@
 
 	if (pVBInfo->VBInfo & SetInSlaveMode) {
 		if (pVBInfo->VBInfo & SetNotSimuMode)
-			tempbx |= LCDVESATiming;
+			tempbx |= XGI_LCDVESATiming;
 	} else {
-		tempbx |= LCDVESATiming;
+		tempbx |= XGI_LCDVESATiming;
 	}
 
 	pVBInfo->LCDInfo = tempbx;
@@ -3477,7 +3477,7 @@
 							  SetInSlaveMode |
 							  SetCRT2ToLCD);
 						pVBInfo->VBInfo |=
-							SetCRT2ToLCDA |
+							XGI_SetCRT2ToLCDA |
 							SetCRT2ToDualEdge;
 					}
 				}
@@ -3801,27 +3801,27 @@
 
 	if (pVBInfo->VBInfo & SetCRT2ToLCD) {
 		if (pVBInfo->IF_DEF_LVDS == 0) {
-			if (pVBInfo->LCDResInfo == Panel1600x1200) {
-				if (!(pVBInfo->LCDInfo & LCDVESATiming)) {
+			if (pVBInfo->LCDResInfo == Panel_1600x1200) {
+				if (!(pVBInfo->LCDInfo & XGI_LCDVESATiming)) {
 					if (yres == 1024)
 						yres = 1056;
 				}
 			}
 
-			if (pVBInfo->LCDResInfo == Panel1280x1024) {
+			if (pVBInfo->LCDResInfo == Panel_1280x1024) {
 				if (yres == 400)
 					yres = 405;
 				else if (yres == 350)
 					yres = 360;
 
-				if (pVBInfo->LCDInfo & LCDVESATiming) {
+				if (pVBInfo->LCDInfo & XGI_LCDVESATiming) {
 					if (yres == 360)
 						yres = 375;
 				}
 			}
 
-			if (pVBInfo->LCDResInfo == Panel1024x768) {
-				if (!(pVBInfo->LCDInfo & LCDVESATiming)) {
+			if (pVBInfo->LCDResInfo == Panel_1024x768) {
+				if (!(pVBInfo->LCDInfo & XGI_LCDVESATiming)) {
 					if (!(pVBInfo->LCDInfo
 							& LCDNonExpanding)) {
 						if (yres == 350)
@@ -3848,7 +3848,7 @@
 static unsigned char XGI_IsLCDDualLink(struct vb_device_info *pVBInfo)
 {
 
-	if ((pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) &&
+	if ((pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) &&
 			(pVBInfo->LCDInfo & SetLCDDualLink)) /* shampoo0129 */
 		return 1;
 
@@ -3918,8 +3918,8 @@
 {
 	unsigned short tempax = 0, tempbx, modeflag, resinfo;
 
-	struct XGI_LCDDataStruct *LCDPtr = NULL;
-	struct XGI_TVDataStruct *TVPtr = NULL;
+	struct SiS_LCDData *LCDPtr = NULL;
+	struct SiS_TVData *TVPtr = NULL;
 
 	if (ModeNo <= 0x13) {
 		/* si+St_ResInfo */
@@ -3942,8 +3942,8 @@
 
 	tempbx = 4;
 
-	if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
-		LCDPtr = (struct XGI_LCDDataStruct *) XGI_GetLcdPtr(tempbx,
+	if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
+		LCDPtr = (struct SiS_LCDData *) XGI_GetLcdPtr(tempbx,
 				ModeNo, ModeIdIndex, RefreshRateTableIndex,
 				pVBInfo);
 
@@ -3954,11 +3954,11 @@
 		pVBInfo->HT = LCDPtr->LCDHT;
 		pVBInfo->VT = LCDPtr->LCDVT;
 
-		if (pVBInfo->LCDResInfo == Panel1024x768) {
+		if (pVBInfo->LCDResInfo == Panel_1024x768) {
 			tempax = 1024;
 			tempbx = 768;
 
-			if (!(pVBInfo->LCDInfo & LCDVESATiming)) {
+			if (!(pVBInfo->LCDInfo & XGI_LCDVESATiming)) {
 				if (pVBInfo->VGAVDE == 357)
 					tempbx = 527;
 				else if (pVBInfo->VGAVDE == 420)
@@ -3971,10 +3971,10 @@
 					tempbx = 768;
 			} else
 				tempbx = 768;
-		} else if (pVBInfo->LCDResInfo == Panel1024x768x75) {
+		} else if (pVBInfo->LCDResInfo == Panel_1024x768x75) {
 			tempax = 1024;
 			tempbx = 768;
-		} else if (pVBInfo->LCDResInfo == Panel1280x1024) {
+		} else if (pVBInfo->LCDResInfo == Panel_1280x1024) {
 			tempax = 1280;
 			if (pVBInfo->VGAVDE == 360)
 				tempbx = 768;
@@ -3984,10 +3984,10 @@
 				tempbx = 864;
 			else
 				tempbx = 1024;
-		} else if (pVBInfo->LCDResInfo == Panel1280x1024x75) {
+		} else if (pVBInfo->LCDResInfo == Panel_1280x1024x75) {
 			tempax = 1280;
 			tempbx = 1024;
-		} else if (pVBInfo->LCDResInfo == Panel1280x960) {
+		} else if (pVBInfo->LCDResInfo == Panel_1280x960) {
 			tempax = 1280;
 			if (pVBInfo->VGAVDE == 350)
 				tempbx = 700;
@@ -3997,7 +3997,7 @@
 				tempbx = 960;
 			else
 				tempbx = 960;
-		} else if (pVBInfo->LCDResInfo == Panel1400x1050) {
+		} else if (pVBInfo->LCDResInfo == Panel_1400x1050) {
 			tempax = 1400;
 			tempbx = 1050;
 
@@ -4005,10 +4005,10 @@
 				tempax = 1280;
 				tempbx = 1024;
 			}
-		} else if (pVBInfo->LCDResInfo == Panel1600x1200) {
+		} else if (pVBInfo->LCDResInfo == Panel_1600x1200) {
 			tempax = 1600;
 			tempbx = 1200; /* alan 10/14/2003 */
-			if (!(pVBInfo->LCDInfo & LCDVESATiming)) {
+			if (!(pVBInfo->LCDInfo & XGI_LCDVESATiming)) {
 				if (pVBInfo->VGAVDE == 350)
 					tempbx = 875;
 				else if (pVBInfo->VGAVDE == 400)
@@ -4028,7 +4028,7 @@
 
 	if (pVBInfo->VBInfo & (SetCRT2ToTV)) {
 		tempbx = 4;
-		TVPtr = (struct XGI_TVDataStruct *) XGI_GetTVPtr(tempbx,
+		TVPtr = (struct SiS_TVData *) XGI_GetTVPtr(tempbx,
 				ModeNo, ModeIdIndex, RefreshRateTableIndex,
 				pVBInfo);
 
@@ -4041,7 +4041,7 @@
 		pVBInfo->RVBHRS = TVPtr->RVBHRS;
 		pVBInfo->NewFlickerMode = TVPtr->FlickerMode;
 
-		if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV) {
+		if (pVBInfo->VBInfo & SetCRT2ToHiVision) {
 			if (resinfo == 0x08)
 				pVBInfo->NewFlickerMode = 0x40;
 			else if (resinfo == 0x09)
@@ -4066,16 +4066,16 @@
 					}
 				}
 			}
-		} else if (pVBInfo->VBInfo & SetCRT2ToYPbPr) {
-			if (pVBInfo->TVInfo & SetYPbPrMode750p) {
+		} else if (pVBInfo->VBInfo & SetCRT2ToYPbPr525750) {
+			if (pVBInfo->TVInfo & TVSetYPbPr750p) {
 				tempax = YPbPrTV750pHT; /* Ext750pTVHT */
 				tempbx = YPbPrTV750pVT; /* Ext750pTVVT */
 			}
 
-			if (pVBInfo->TVInfo & SetYPbPrMode525p) {
+			if (pVBInfo->TVInfo & TVSetYPbPr525p) {
 				tempax = YPbPrTV525pHT; /* Ext525pTVHT */
 				tempbx = YPbPrTV525pVT; /* Ext525pTVVT */
-			} else if (pVBInfo->TVInfo & SetYPbPrMode525i) {
+			} else if (pVBInfo->TVInfo & TVSetYPbPr525i) {
 				tempax = YPbPrTV525iHT; /* Ext525iTVHT */
 				tempbx = YPbPrTV525iVT; /* Ext525iTVVT */
 				if (pVBInfo->TVInfo & NTSC1024x768)
@@ -4084,7 +4084,7 @@
 		} else {
 			tempax = PALHT;
 			tempbx = PALVT;
-			if (!(pVBInfo->TVInfo & SetPALTV)) {
+			if (!(pVBInfo->TVInfo & TVSetPAL)) {
 				tempax = NTSCHT;
 				tempbx = NTSCVT;
 				if (pVBInfo->TVInfo & NTSC1024x768)
@@ -4109,7 +4109,7 @@
 	XGI_GetVCLKLen(tempal, &di_0, &di_1, pVBInfo);
 	XGI_GetLCDVCLKPtr(&di_0, &di_1, pVBInfo);
 
-	if (pVBInfo->VBType & VB_XGI301) { /* shampoo 0129 */
+	if (pVBInfo->VBType & VB_SIS301) { /* shampoo 0129 */
 		/* 301 */
 		xgifb_reg_set(pVBInfo->Part4Port, 0x0A, 0x10);
 		xgifb_reg_set(pVBInfo->Part4Port, 0x0B, di_1);
@@ -4139,7 +4139,7 @@
 	else
 		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
-	index = (modeflag & ModeInfoFlag) - ModeEGA;
+	index = (modeflag & ModeTypeMask) - ModeEGA;
 
 	if (index < 0)
 		index = 0;
@@ -4435,7 +4435,7 @@
 	xgifb_reg_set(pVBInfo->Part1Port, 0x03, temp);
 	tempcx = 0x08;
 
-	if (pVBInfo->VBType & (VB_XGI301LV | VB_XGI302LV | VB_XGI301C))
+	if (pVBInfo->VBType & (VB_SIS301LV | VB_SIS302LV | VB_XGI301C))
 		modeflag |= Charx8Dot;
 
 	tempax = pVBInfo->VGAHDE; /* 0x04 Horizontal Display End */
@@ -4451,12 +4451,12 @@
 	temp = (tempbx & 0xFF00) >> 8;
 
 	if (pVBInfo->VBInfo & SetCRT2ToTV) {
-		if (!(pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-				| VB_XGI302LV | VB_XGI301C)))
+		if (!(pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+				| VB_SIS302LV | VB_XGI301C)))
 			temp += 2;
 
-		if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV) {
-			if (pVBInfo->VBType & VB_XGI301LV) {
+		if (pVBInfo->VBInfo & SetCRT2ToHiVision) {
+			if (pVBInfo->VBType & VB_SIS301LV) {
 				if (pVBInfo->VBExtInfo == VB_YPbPr1080i) {
 					if (resinfo == 7)
 						temp -= 2;
@@ -4487,7 +4487,7 @@
 
 	tempax = (tempax / tempcx) - 5;
 	tempcx = tempax; /* 20030401 0x07 horizontal Retrace Start */
-	if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV) {
+	if (pVBInfo->VBInfo & SetCRT2ToHiVision) {
 		temp = (tempbx & 0x00FF) - 1;
 		if (!(modeflag & HalfDCLK)) {
 			temp -= 6;
@@ -4513,19 +4513,19 @@
 			}
 		} else if (!(modeflag & HalfDCLK)) {
 			temp -= 4;
-			if (pVBInfo->LCDResInfo != Panel1280x960 &&
+			if (pVBInfo->LCDResInfo != Panel_1280x960 &&
 			    pVBInfo->VGAHDE >= 800) {
 				temp -= 7;
 				if (pVBInfo->ModeType == ModeEGA &&
 				    pVBInfo->VGAVDE == 1024) {
 					temp += 15;
 					if (pVBInfo->LCDResInfo !=
-						Panel1280x1024)
+						Panel_1280x1024)
 						temp += 7;
 				}
 
 				if (pVBInfo->VGAHDE >= 1280 &&
-				    pVBInfo->LCDResInfo != Panel1280x960 &&
+				    pVBInfo->LCDResInfo != Panel_1280x960 &&
 				    (pVBInfo->LCDInfo & LCDNonExpanding))
 					temp += 28;
 			}
@@ -4619,8 +4619,8 @@
 	push2 = tempbx;
 
 	if (pVBInfo->VBInfo & SetCRT2ToLCD) {
-		if (pVBInfo->LCDResInfo == Panel1024x768) {
-			if (!(pVBInfo->LCDInfo & LCDVESATiming)) {
+		if (pVBInfo->LCDResInfo == Panel_1024x768) {
+			if (!(pVBInfo->LCDInfo & XGI_LCDVESATiming)) {
 				if (tempbx == 350)
 					tempbx += 5;
 				if (tempbx == 480)
@@ -4669,19 +4669,19 @@
 		tempbx += tempax;
 	}
 
-	if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV) {
-		if (pVBInfo->VBType & VB_XGI301LV) {
-			if (pVBInfo->TVInfo & SetYPbPrMode1080i) {
+	if (pVBInfo->VBInfo & SetCRT2ToHiVision) {
+		if (pVBInfo->VBType & VB_SIS301LV) {
+			if (pVBInfo->TVInfo & TVSetHiVision) {
 				tempbx -= 10;
 			} else {
 				if (pVBInfo->TVInfo & TVSimuMode) {
-					if (pVBInfo->TVInfo & SetPALTV) {
+					if (pVBInfo->TVInfo & TVSetPAL) {
 						if (pVBInfo->VBType &
-						    VB_XGI301LV) {
+						    VB_SIS301LV) {
 							if (!(pVBInfo->TVInfo &
-							    (SetYPbPrMode525p |
-							    SetYPbPrMode750p |
-							    SetYPbPrMode1080i)))
+							    (TVSetYPbPr525p |
+							    TVSetYPbPr750p |
+							    TVSetHiVision)))
 								tempbx += 40;
 						} else {
 							tempbx += 40;
@@ -4694,12 +4694,12 @@
 		}
 	} else {
 		if (pVBInfo->TVInfo & TVSimuMode) {
-			if (pVBInfo->TVInfo & SetPALTV) {
-				if (pVBInfo->VBType & VB_XGI301LV) {
+			if (pVBInfo->TVInfo & TVSetPAL) {
+				if (pVBInfo->VBType & VB_SIS301LV) {
 					if (!(pVBInfo->TVInfo &
-					    (SetYPbPrMode525p |
-					     SetYPbPrMode750p |
-					     SetYPbPrMode1080i)))
+					    (TVSetYPbPr525p |
+					     TVSetYPbPr750p |
+					     TVSetHiVision)))
 						tempbx += 40;
 				} else {
 					tempbx += 40;
@@ -4713,7 +4713,7 @@
 	tempax += tempbx;
 	push1 = tempax; /* push ax */
 
-	if ((pVBInfo->TVInfo & SetPALTV)) {
+	if ((pVBInfo->TVInfo & TVSetPAL)) {
 		if (tempbx <= 513) {
 			if (tempax >= 513)
 				tempbx = 513;
@@ -4761,7 +4761,7 @@
 
 	temp = (temp >> 1) & 0x09;
 
-	if (pVBInfo->VBType & (VB_XGI301LV | VB_XGI302LV | VB_XGI301C))
+	if (pVBInfo->VBType & (VB_SIS301LV | VB_SIS302LV | VB_XGI301C))
 		temp |= 0x01;
 
 	xgifb_reg_set(pVBInfo->Part1Port, 0x16, temp); /* 0x16 SR01 */
@@ -4813,13 +4813,13 @@
 	if (pVBInfo->VBInfo & SetCRT2ToSCART)
 		tempax |= 0x0200;
 
-	if (!(pVBInfo->TVInfo & SetPALTV))
+	if (!(pVBInfo->TVInfo & TVSetPAL))
 		tempax |= 0x1000;
 
-	if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV)
+	if (pVBInfo->VBInfo & SetCRT2ToHiVision)
 		tempax |= 0x0100;
 
-	if (pVBInfo->TVInfo & (SetYPbPrMode525p | SetYPbPrMode750p))
+	if (pVBInfo->TVInfo & (TVSetYPbPr525p | TVSetYPbPr750p))
 		tempax &= 0xfe00;
 
 	tempax = (tempax & 0xff00) >> 8;
@@ -4827,10 +4827,10 @@
 	xgifb_reg_set(pVBInfo->Part2Port, 0x0, tempax);
 	TimingPoint = pVBInfo->NTSCTiming;
 
-	if (pVBInfo->TVInfo & SetPALTV)
+	if (pVBInfo->TVInfo & TVSetPAL)
 		TimingPoint = pVBInfo->PALTiming;
 
-	if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV) {
+	if (pVBInfo->VBInfo & SetCRT2ToHiVision) {
 		TimingPoint = pVBInfo->HiTVExtTiming;
 
 		if (pVBInfo->VBInfo & SetInSlaveMode)
@@ -4843,14 +4843,14 @@
 			TimingPoint = pVBInfo->HiTVTextTiming;
 	}
 
-	if (pVBInfo->VBInfo & SetCRT2ToYPbPr) {
-		if (pVBInfo->TVInfo & SetYPbPrMode525i)
+	if (pVBInfo->VBInfo & SetCRT2ToYPbPr525750) {
+		if (pVBInfo->TVInfo & TVSetYPbPr525i)
 			TimingPoint = pVBInfo->YPbPr525iTiming;
 
-		if (pVBInfo->TVInfo & SetYPbPrMode525p)
+		if (pVBInfo->TVInfo & TVSetYPbPr525p)
 			TimingPoint = pVBInfo->YPbPr525pTiming;
 
-		if (pVBInfo->TVInfo & SetYPbPrMode750p)
+		if (pVBInfo->TVInfo & TVSetYPbPr750p)
 			TimingPoint = pVBInfo->YPbPr750pTiming;
 	}
 
@@ -4868,10 +4868,10 @@
 	temp &= 0x80;
 	xgifb_reg_and_or(pVBInfo->Part2Port, 0x0A, 0xFF, temp);
 
-	if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV)
+	if (pVBInfo->VBInfo & SetCRT2ToHiVision)
 		tempax = 950;
 
-	if (pVBInfo->TVInfo & SetPALTV)
+	if (pVBInfo->TVInfo & TVSetPAL)
 		tempax = 520;
 	else
 		tempax = 440;
@@ -4884,15 +4884,15 @@
 		temp = (tempax & 0xFF00) >> 8;
 		temp += (unsigned short) TimingPoint[0];
 
-		if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-				| VB_XGI302LV | VB_XGI301C)) {
+		if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+				| VB_SIS302LV | VB_XGI301C)) {
 			if (pVBInfo->VBInfo & (SetCRT2ToAVIDEO
 					| SetCRT2ToSVIDEO | SetCRT2ToSCART
-					| SetCRT2ToYPbPr)) {
+					| SetCRT2ToYPbPr525750)) {
 				tempcx = pVBInfo->VGAHDE;
 				if (tempcx >= 1024) {
 					temp = 0x17; /* NTSC */
-					if (pVBInfo->TVInfo & SetPALTV)
+					if (pVBInfo->TVInfo & TVSetPAL)
 						temp = 0x19; /* PAL */
 				}
 			}
@@ -4903,15 +4903,15 @@
 		temp = (tempax & 0xFF00) >> 8;
 		temp += TimingPoint[1];
 
-		if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-				| VB_XGI302LV | VB_XGI301C)) {
+		if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+				| VB_SIS302LV | VB_XGI301C)) {
 			if ((pVBInfo->VBInfo & (SetCRT2ToAVIDEO
 					| SetCRT2ToSVIDEO | SetCRT2ToSCART
-					| SetCRT2ToYPbPr))) {
+					| SetCRT2ToYPbPr525750))) {
 				tempcx = pVBInfo->VGAHDE;
 				if (tempcx >= 1024) {
 					temp = 0x1D; /* NTSC */
-					if (pVBInfo->TVInfo & SetPALTV)
+					if (pVBInfo->TVInfo & TVSetPAL)
 						temp = 0x52; /* PAL */
 				}
 			}
@@ -4936,7 +4936,7 @@
 	push1 = tempcx; /* push cx */
 	tempcx += 7;
 
-	if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV)
+	if (pVBInfo->VBInfo & SetCRT2ToHiVision)
 		tempcx -= 4;
 
 	temp = tempcx & 0x00FF;
@@ -4954,7 +4954,7 @@
 
 	tempbx = push2;
 	tempbx = tempbx + 8;
-	if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV) {
+	if (pVBInfo->VBInfo & SetCRT2ToHiVision) {
 		tempbx = tempbx - 4;
 		tempcx = tempbx;
 	}
@@ -4970,7 +4970,7 @@
 	xgifb_reg_and_or(pVBInfo->Part2Port, 0x28, 0x0F, temp);
 
 	tempcx += 8;
-	if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV)
+	if (pVBInfo->VBInfo & SetCRT2ToHiVision)
 		tempcx -= 4;
 
 	temp = tempcx & 0xFF;
@@ -5005,9 +5005,9 @@
 
 	if (pVBInfo->VBInfo & SetCRT2ToTV) {
 		if (pVBInfo->VBType &
-		    (VB_XGI301LV | VB_XGI302LV | VB_XGI301C)) {
+		    (VB_SIS301LV | VB_SIS302LV | VB_XGI301C)) {
 			if (!(pVBInfo->TVInfo &
-			    (SetYPbPrMode525p | SetYPbPrMode750p)))
+			    (TVSetYPbPr525p | TVSetYPbPr750p)))
 				tempbx = tempbx >> 1;
 		} else
 			tempbx = tempbx >> 1;
@@ -5016,9 +5016,9 @@
 	tempbx -= 2;
 	temp = tempbx & 0x00FF;
 
-	if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV) {
-		if (pVBInfo->VBType & VB_XGI301LV) {
-			if (pVBInfo->TVInfo & SetYPbPrMode1080i) {
+	if (pVBInfo->VBInfo & SetCRT2ToHiVision) {
+		if (pVBInfo->VBType & VB_SIS301LV) {
+			if (pVBInfo->TVInfo & TVSetHiVision) {
 				if (pVBInfo->VBInfo & SetInSlaveMode) {
 					if (ModeNo == 0x2f)
 						temp += 1;
@@ -5037,9 +5037,9 @@
 	temp = (tempcx & 0xFF00) >> 8;
 	temp |= ((tempbx & 0xFF00) >> 8) << 6;
 
-	if (!(pVBInfo->VBInfo & SetCRT2ToHiVisionTV)) {
-		if (pVBInfo->VBType & VB_XGI301LV) {
-			if (pVBInfo->TVInfo & SetYPbPrMode1080i) {
+	if (!(pVBInfo->VBInfo & SetCRT2ToHiVision)) {
+		if (pVBInfo->VBType & VB_SIS301LV) {
+			if (pVBInfo->TVInfo & TVSetHiVision) {
 				temp |= 0x10;
 
 				if (!(pVBInfo->VBInfo & SetCRT2ToSVIDEO))
@@ -5054,18 +5054,18 @@
 
 	xgifb_reg_set(pVBInfo->Part2Port, 0x30, temp);
 
-	if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-			| VB_XGI302LV | VB_XGI301C)) { /* TV gatingno */
+	if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+			| VB_SIS302LV | VB_XGI301C)) { /* TV gatingno */
 		tempbx = pVBInfo->VDE;
 		tempcx = tempbx - 2;
 
 		if (pVBInfo->VBInfo & SetCRT2ToTV) {
-			if (!(pVBInfo->TVInfo & (SetYPbPrMode525p
-					| SetYPbPrMode750p)))
+			if (!(pVBInfo->TVInfo & (TVSetYPbPr525p
+					| TVSetYPbPr750p)))
 				tempbx = tempbx >> 1;
 		}
 
-		if (pVBInfo->VBType & (VB_XGI302LV | VB_XGI301C)) {
+		if (pVBInfo->VBType & (VB_SIS302LV | VB_XGI301C)) {
 			temp = 0;
 			if (tempcx & 0x0400)
 				temp |= 0x20;
@@ -5118,8 +5118,8 @@
 		/* 301b */
 		tempecx = 8 * 1024;
 
-		if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-				| VB_XGI302LV | VB_XGI301C)) {
+		if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+				| VB_SIS302LV | VB_XGI301C)) {
 			tempecx = tempecx * 8;
 		}
 
@@ -5133,8 +5133,8 @@
 		tempax = (unsigned short) tempeax;
 
 		/* 301b */
-		if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-				| VB_XGI302LV | VB_XGI301C)) {
+		if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+				| VB_SIS302LV | VB_XGI301C)) {
 			tempcx = ((tempax & 0xFF00) >> 5) >> 8;
 		}
 		/* end 301b */
@@ -5161,7 +5161,7 @@
 		temp |= 0x18;
 
 	xgifb_reg_and_or(pVBInfo->Part2Port, 0x46, ~0x1F, temp);
-	if (pVBInfo->TVInfo & SetPALTV) {
+	if (pVBInfo->TVInfo & TVSetPAL) {
 		tempbx = 0x0382;
 		tempcx = 0x007e;
 	} else {
@@ -5178,13 +5178,13 @@
 	temp = temp << 2;
 	temp |= ((tempbx & 0xFF00) >> 8) & 0x03;
 
-	if (pVBInfo->VBInfo & SetCRT2ToYPbPr) {
+	if (pVBInfo->VBInfo & SetCRT2ToYPbPr525750) {
 		temp |= 0x10;
 
-		if (pVBInfo->TVInfo & SetYPbPrMode525p)
+		if (pVBInfo->TVInfo & TVSetYPbPr525p)
 			temp |= 0x20;
 
-		if (pVBInfo->TVInfo & SetYPbPrMode750p)
+		if (pVBInfo->TVInfo & TVSetYPbPr750p)
 			temp |= 0x60;
 	}
 
@@ -5192,7 +5192,7 @@
 	temp = xgifb_reg_get(pVBInfo->Part2Port, 0x43); /* 301b change */
 	xgifb_reg_set(pVBInfo->Part2Port, 0x43, (unsigned short) (temp - 3));
 
-	if (!(pVBInfo->TVInfo & (SetYPbPrMode525p | SetYPbPrMode750p))) {
+	if (!(pVBInfo->TVInfo & (TVSetYPbPr525p | TVSetYPbPr750p))) {
 		if (pVBInfo->TVInfo & NTSC1024x768) {
 			TimingPoint = XGI_NTSC1024AdjTime;
 			for (i = 0x1c, j = 0; i <= 0x30; i++, j++) {
@@ -5205,12 +5205,12 @@
 
 	/* [ycchen] 01/14/03 Modify for 301C PALM Support */
 	if (pVBInfo->VBType & VB_XGI301C) {
-		if (pVBInfo->TVInfo & SetPALMTV)
+		if (pVBInfo->TVInfo & TVSetPALM)
 			xgifb_reg_and_or(pVBInfo->Part2Port, 0x4E, ~0x08,
 					0x08); /* PALM Mode */
 	}
 
-	if (pVBInfo->TVInfo & SetPALMTV) {
+	if (pVBInfo->TVInfo & TVSetPALM) {
 		tempax = (unsigned char) xgifb_reg_get(pVBInfo->Part2Port,
 				0x01);
 		tempax--;
@@ -5219,7 +5219,7 @@
 		xgifb_reg_and(pVBInfo->Part2Port, 0x00, 0xEF);
 	}
 
-	if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV) {
+	if (pVBInfo->VBInfo & SetCRT2ToHiVision) {
 		if (!(pVBInfo->VBInfo & SetInSlaveMode))
 			xgifb_reg_set(pVBInfo->Part2Port, 0x0B, 0x00);
 	}
@@ -5267,11 +5267,11 @@
 	xgifb_reg_and_or(pVBInfo->Part2Port, 0x2B, 0x0F, temp);
 	temp = 0x01;
 
-	if (pVBInfo->LCDResInfo == Panel1280x1024) {
+	if (pVBInfo->LCDResInfo == Panel_1280x1024) {
 		if (pVBInfo->ModeType == ModeEGA) {
 			if (pVBInfo->VGAHDE >= 1024) {
 				temp = 0x02;
-				if (pVBInfo->LCDInfo & LCDVESATiming)
+				if (pVBInfo->LCDInfo & XGI_LCDVESATiming)
 					temp = 0x01;
 			}
 		}
@@ -5305,14 +5305,14 @@
 	tempah = pVBInfo->LCDResInfo;
 	tempah &= PanelResInfo;
 
-	if ((tempah == Panel1024x768) || (tempah == Panel1024x768x75)) {
+	if ((tempah == Panel_1024x768) || (tempah == Panel_1024x768x75)) {
 		tempbx = 1024;
 		tempcx = 768;
-	} else if ((tempah == Panel1280x1024) ||
-		   (tempah == Panel1280x1024x75)) {
+	} else if ((tempah == Panel_1280x1024) ||
+		   (tempah == Panel_1280x1024x75)) {
 		tempbx = 1280;
 		tempcx = 1024;
-	} else if (tempah == Panel1400x1050) {
+	} else if (tempah == Panel_1400x1050) {
 		tempbx = 1400;
 		tempcx = 1050;
 	} else {
@@ -5375,7 +5375,7 @@
 		tempcx = tempcx >> 1;
 	}
 
-	if (pVBInfo->VBType & VB_XGI302LV)
+	if (pVBInfo->VBType & VB_SIS302LV)
 		tempbx += 1;
 
 	if (pVBInfo->VBType & VB_XGI301C) /* tap4 */
@@ -5405,7 +5405,7 @@
 		tempcx = tempcx >> 1;
 	}
 
-	if (pVBInfo->VBType & VB_XGI302LV)
+	if (pVBInfo->VBType & VB_SIS302LV)
 		tempbx += 1;
 
 	tempcx += tempbx;
@@ -5422,10 +5422,10 @@
 	temp = tempcx & 0x00FF; /* RHSYEXP2S=lcdhre */
 	xgifb_reg_set(pVBInfo->Part2Port, 0x21, temp);
 
-	if (!(pVBInfo->LCDInfo & LCDVESATiming)) {
+	if (!(pVBInfo->LCDInfo & XGI_LCDVESATiming)) {
 		if (pVBInfo->VGAVDE == 525) {
-			if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B
-					| VB_XGI301LV | VB_XGI302LV
+			if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B
+					| VB_SIS301LV | VB_SIS302LV
 					| VB_XGI301C)) {
 				temp = 0xC6;
 			} else
@@ -5436,8 +5436,8 @@
 		}
 
 		if (pVBInfo->VGAVDE == 420) {
-			if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B
-					| VB_XGI301LV | VB_XGI302LV
+			if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B
+					| VB_SIS301LV | VB_SIS302LV
 					| VB_XGI301C)) {
 				temp = 0x4F;
 			} else
@@ -5473,18 +5473,18 @@
 	else
 		Tap4TimingPtr = xgifb_ntsc_525_tap4_timing; /* NTSC */
 
-	if (pVBInfo->TVInfo & SetPALTV)
+	if (pVBInfo->TVInfo & TVSetPAL)
 		Tap4TimingPtr = PALTap4Timing;
 
-	if (pVBInfo->VBInfo & SetCRT2ToYPbPr) {
-		if ((pVBInfo->TVInfo & SetYPbPrMode525i) ||
-			(pVBInfo->TVInfo & SetYPbPrMode525p))
+	if (pVBInfo->VBInfo & SetCRT2ToYPbPr525750) {
+		if ((pVBInfo->TVInfo & TVSetYPbPr525i) ||
+			(pVBInfo->TVInfo & TVSetYPbPr525p))
 			Tap4TimingPtr = xgifb_ntsc_525_tap4_timing;
-		if (pVBInfo->TVInfo & SetYPbPrMode750p)
+		if (pVBInfo->TVInfo & TVSetYPbPr750p)
 			Tap4TimingPtr = YPbPr750pTap4Timing;
 	}
 
-	if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV)
+	if (pVBInfo->VBInfo & SetCRT2ToHiVision)
 		Tap4TimingPtr = xgifb_tap4_timing;
 
 	i = 0;
@@ -5510,7 +5510,7 @@
 		xgifb_reg_set(pVBInfo->Part2Port, i, Tap4TimingPtr->Reg[j]);
 
 	if ((pVBInfo->VBInfo & SetCRT2ToTV) &&
-	    (!(pVBInfo->VBInfo & SetCRT2ToHiVisionTV))) {
+	    (!(pVBInfo->VBInfo & SetCRT2ToHiVision))) {
 		/* Set Vertical Scaling */
 		Tap4TimingPtr = XGI_GetTap4Ptr(1, pVBInfo);
 		for (i = 0xC0, j = 0; i < 0xFF; i++, j++)
@@ -5520,7 +5520,7 @@
 	}
 
 	if ((pVBInfo->VBInfo & SetCRT2ToTV) &&
-	    (!(pVBInfo->VBInfo & SetCRT2ToHiVisionTV)))
+	    (!(pVBInfo->VBInfo & SetCRT2ToHiVision)))
 		/* Enable V.Scaling */
 		xgifb_reg_and_or(pVBInfo->Part2Port, 0x4E, ~0x14, 0x04);
 	else
@@ -5543,7 +5543,7 @@
 		modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
 	xgifb_reg_set(pVBInfo->Part3Port, 0x00, 0x00);
-	if (pVBInfo->TVInfo & SetPALTV) {
+	if (pVBInfo->TVInfo & TVSetPAL) {
 		xgifb_reg_set(pVBInfo->Part3Port, 0x13, 0xFA);
 		xgifb_reg_set(pVBInfo->Part3Port, 0x14, 0xC8);
 	} else {
@@ -5554,15 +5554,15 @@
 	if (!(pVBInfo->VBInfo & SetCRT2ToTV))
 		return;
 
-	if (pVBInfo->TVInfo & SetPALMTV) {
+	if (pVBInfo->TVInfo & TVSetPALM) {
 		xgifb_reg_set(pVBInfo->Part3Port, 0x13, 0xFA);
 		xgifb_reg_set(pVBInfo->Part3Port, 0x14, 0xC8);
 		xgifb_reg_set(pVBInfo->Part3Port, 0x3D, 0xA8);
 	}
 
-	if ((pVBInfo->VBInfo & SetCRT2ToHiVisionTV) || (pVBInfo->VBInfo
-			& SetCRT2ToYPbPr)) {
-		if (pVBInfo->TVInfo & SetYPbPrMode525i)
+	if ((pVBInfo->VBInfo & SetCRT2ToHiVision) || (pVBInfo->VBInfo
+			& SetCRT2ToYPbPr525750)) {
+		if (pVBInfo->TVInfo & TVSetYPbPr525i)
 			return;
 
 		tempdi = pVBInfo->HiTVGroup3Data;
@@ -5572,17 +5572,17 @@
 				tempdi = pVBInfo->HiTVGroup3Text;
 		}
 
-		if (pVBInfo->TVInfo & SetYPbPrMode525p)
+		if (pVBInfo->TVInfo & TVSetYPbPr525p)
 			tempdi = pVBInfo->Ren525pGroup3;
 
-		if (pVBInfo->TVInfo & SetYPbPrMode750p)
+		if (pVBInfo->TVInfo & TVSetYPbPr750p)
 			tempdi = pVBInfo->Ren750pGroup3;
 
 		for (i = 0; i <= 0x3E; i++)
 			xgifb_reg_set(pVBInfo->Part3Port, i, tempdi[i]);
 
 		if (pVBInfo->VBType & VB_XGI301C) { /* Marcovision */
-			if (pVBInfo->TVInfo & SetYPbPrMode525p)
+			if (pVBInfo->TVInfo & TVSetYPbPr525p)
 				xgifb_reg_set(pVBInfo->Part3Port, 0x28, 0x3f);
 		}
 	}
@@ -5637,7 +5637,7 @@
 	if (XGI_IsLCDDualLink(pVBInfo))
 		tempbx = tempbx >> 1;
 
-	if (tempcx & SetCRT2ToHiVisionTV) {
+	if (tempcx & SetCRT2ToHiVision) {
 		temp = 0;
 		if (tempbx <= 1024)
 			temp = 0xA0;
@@ -5656,7 +5656,7 @@
 		}
 	}
 
-	if (pVBInfo->TVInfo & (SetYPbPrMode525p | SetYPbPrMode750p)) {
+	if (pVBInfo->TVInfo & (TVSetYPbPr525p | TVSetYPbPr750p)) {
 		temp = 0x00;
 		if (pVBInfo->VGAHDE == 1280)
 			temp = 0x40;
@@ -5667,7 +5667,7 @@
 
 	tempebx = pVBInfo->VDE;
 
-	if (tempcx & SetCRT2ToHiVisionTV) {
+	if (tempcx & SetCRT2ToHiVision) {
 		if (!(temp & 0xE000))
 			tempbx = tempbx >> 1;
 	}
@@ -5705,8 +5705,8 @@
 	xgifb_reg_set(pVBInfo->Part4Port, 0x19, temp);
 
 	/* 301b */
-	if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-			| VB_XGI302LV | VB_XGI301C)) {
+	if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+			| VB_SIS302LV | VB_XGI301C)) {
 		temp = 0x0028;
 		xgifb_reg_set(pVBInfo->Part4Port, 0x1C, temp);
 		tempax = pVBInfo->VGAHDE;
@@ -5735,7 +5735,7 @@
 		temp = (tempax & 0x00FF);
 		xgifb_reg_set(pVBInfo->Part4Port, 0x1D, temp);
 
-		if (pVBInfo->VBInfo & (SetCRT2ToTV | SetCRT2ToHiVisionTV)) {
+		if (pVBInfo->VBInfo & (SetCRT2ToTV | SetCRT2ToHiVision)) {
 			if (pVBInfo->VGAHDE > 800)
 				xgifb_reg_or(pVBInfo->Part4Port, 0x1E, 0x08);
 
@@ -5744,8 +5744,8 @@
 
 		if (pVBInfo->VBInfo & SetCRT2ToTV) {
 			if (!(pVBInfo->TVInfo & (NTSC1024x768
-					| SetYPbPrMode525p | SetYPbPrMode750p
-					| SetYPbPrMode1080i))) {
+					| TVSetYPbPr525p | TVSetYPbPr750p
+					| TVSetHiVision))) {
 				temp |= 0x0001;
 				if ((pVBInfo->VBInfo & SetInSlaveMode)
 						&& (!(pVBInfo->TVInfo
@@ -5785,7 +5785,7 @@
 	Pdata = pVBInfo->Part5Port + 1;
 	if (pVBInfo->ModeType == ModeVGA) {
 		if (!(pVBInfo->VBInfo & (SetInSlaveMode | LoadDACFlag
-				| CRT2DisplayFlag))) {
+				| DisableCRT2Display))) {
 			XGINew_EnableCRT2(pVBInfo);
 		}
 	}
@@ -6074,7 +6074,7 @@
 	tempax = pVBInfo->VBInfo;
 	if (tempax & SetCRT2ToDualEdge)
 		return 0;
-	else if (tempax & (DisableCRT2Display | SwitchToCRT2 | SetSimuScanMode))
+	else if (tempax & (DisableCRT2Display | SwitchCRT2 | SetSimuScanMode))
 		return 1;
 
 	return 0;
@@ -6140,15 +6140,15 @@
 {
 	unsigned short tempah = 0;
 
-	if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-			| VB_XGI302LV | VB_XGI301C)) {
+	if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+			| VB_SIS302LV | VB_XGI301C)) {
 		tempah = 0x3F;
 		if (!(pVBInfo->VBInfo &
 		    (DisableCRT2Display | SetSimuScanMode))) {
-			if (pVBInfo->VBInfo & SetCRT2ToLCDA) {
+			if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
 				if (pVBInfo->VBInfo & SetCRT2ToDualEdge) {
 					tempah = 0x7F; /* Disable Channel A */
-					if (!(pVBInfo->VBInfo & SetCRT2ToLCDA))
+					if (!(pVBInfo->VBInfo & XGI_SetCRT2ToLCDA))
 						/* Disable Channel B */
 						tempah = 0xBF;
 
@@ -6166,8 +6166,8 @@
 		/* disable part4_1f */
 		xgifb_reg_and(pVBInfo->Part4Port, 0x1F, tempah);
 
-		if (pVBInfo->VBType & (VB_XGI302LV | VB_XGI301C)) {
-			if (((pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)))
+		if (pVBInfo->VBType & (VB_SIS302LV | VB_XGI301C)) {
+			if (((pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)))
 					|| (XGI_DisableChISLCD(pVBInfo))
 					|| (XGI_IsLCDON(pVBInfo)))
 				/* LVDS Driver power down */
@@ -6175,16 +6175,16 @@
 		}
 
 		if ((pVBInfo->SetFlag & DisableChA) || (pVBInfo->VBInfo
-				& (DisableCRT2Display | SetCRT2ToLCDA
+				& (DisableCRT2Display | XGI_SetCRT2ToLCDA
 						| SetSimuScanMode))) {
 			if (pVBInfo->SetFlag & GatingCRT)
 				XGI_EnableGatingCRT(HwDeviceExtension, pVBInfo);
 			XGI_DisplayOff(xgifb_info, HwDeviceExtension, pVBInfo);
 		}
 
-		if (pVBInfo->VBInfo & SetCRT2ToLCDA) {
+		if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
 			if ((pVBInfo->SetFlag & DisableChA) || (pVBInfo->VBInfo
-					& SetCRT2ToLCDA))
+					& XGI_SetCRT2ToLCDA))
 				/* Power down */
 				xgifb_reg_and(pVBInfo->Part1Port, 0x1e, 0xdf);
 		}
@@ -6198,7 +6198,7 @@
 		if ((pVBInfo->SetFlag & DisableChB) ||
 		    (pVBInfo->VBInfo &
 			(DisableCRT2Display | SetSimuScanMode)) ||
-		    ((!(pVBInfo->VBInfo & SetCRT2ToLCDA)) &&
+		    ((!(pVBInfo->VBInfo & XGI_SetCRT2ToLCDA)) &&
 		    (pVBInfo->VBInfo &
 			(SetCRT2ToRAMDAC | SetCRT2ToLCD | SetCRT2ToTV))))
 			xgifb_reg_or(pVBInfo->Part1Port, 0x00, 0x80);
@@ -6206,7 +6206,7 @@
 		if ((pVBInfo->SetFlag & DisableChB) ||
 		    (pVBInfo->VBInfo &
 			(DisableCRT2Display | SetSimuScanMode)) ||
-		    (!(pVBInfo->VBInfo & SetCRT2ToLCDA)) ||
+		    (!(pVBInfo->VBInfo & XGI_SetCRT2ToLCDA)) ||
 		    (pVBInfo->VBInfo &
 			(SetCRT2ToRAMDAC | SetCRT2ToLCD | SetCRT2ToTV))) {
 			/* save Part1 index 0 */
@@ -6227,7 +6227,7 @@
 			xgifb_reg_and(pVBInfo->P3c4, 0x32, 0xDF);
 		}
 
-		if (pVBInfo->VBInfo & (DisableCRT2Display | SetCRT2ToLCDA
+		if (pVBInfo->VBInfo & (DisableCRT2Display | XGI_SetCRT2ToLCDA
 				| SetSimuScanMode))
 			XGI_DisplayOff(xgifb_info, HwDeviceExtension, pVBInfo);
 	}
@@ -6254,15 +6254,15 @@
 {
 	unsigned short tempbx = 0;
 
-	if (pVBInfo->TVInfo & SetPALTV)
+	if (pVBInfo->TVInfo & TVSetPAL)
 		tempbx = 2;
-	if (pVBInfo->TVInfo & SetYPbPrMode1080i)
+	if (pVBInfo->TVInfo & TVSetHiVision)
 		tempbx = 4;
-	if (pVBInfo->TVInfo & SetYPbPrMode525i)
+	if (pVBInfo->TVInfo & TVSetYPbPr525i)
 		tempbx = 6;
-	if (pVBInfo->TVInfo & SetYPbPrMode525p)
+	if (pVBInfo->TVInfo & TVSetYPbPr525p)
 		tempbx = 8;
-	if (pVBInfo->TVInfo & SetYPbPrMode750p)
+	if (pVBInfo->TVInfo & TVSetYPbPr750p)
 		tempbx = 10;
 	if (pVBInfo->TVInfo & TVSimuMode)
 		tempbx++;
@@ -6293,23 +6293,23 @@
 	*tempcl = 0;
 	*tempch = 0;
 
-	if (pVBInfo->TVInfo & SetPALTV)
+	if (pVBInfo->TVInfo & TVSetPAL)
 		*tempbx = 1;
 
-	if (pVBInfo->TVInfo & SetPALMTV)
+	if (pVBInfo->TVInfo & TVSetPALM)
 		*tempbx = 2;
 
-	if (pVBInfo->TVInfo & SetPALNTV)
+	if (pVBInfo->TVInfo & TVSetPALN)
 		*tempbx = 3;
 
 	if (pVBInfo->TVInfo & NTSC1024x768) {
 		*tempbx = 4;
-		if (pVBInfo->TVInfo & SetPALMTV)
+		if (pVBInfo->TVInfo & TVSetPALM)
 			*tempbx = 5;
 	}
 
-	if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-			| VB_XGI302LV | VB_XGI301C)) {
+	if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+			| VB_SIS302LV | VB_XGI301C)) {
 		if ((!(pVBInfo->VBInfo & SetInSlaveMode)) || (pVBInfo->TVInfo
 				& TVSimuMode)) {
 			*tempbx += 8;
@@ -6317,8 +6317,8 @@
 		}
 	}
 
-	if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-			| VB_XGI302LV | VB_XGI301C))
+	if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+			| VB_SIS302LV | VB_XGI301C))
 		(*tempch)++;
 }
 
@@ -6328,9 +6328,9 @@
 
 	unsigned char tempah, tempbl, tempbh;
 
-	if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-			| VB_XGI302LV | VB_XGI301C)) {
-		if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA
+	if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+			| VB_SIS302LV | VB_XGI301C)) {
+		if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA
 				| SetCRT2ToTV | SetCRT2ToRAMDAC)) {
 			tempbl = 0;
 			tempbh = 0;
@@ -6338,20 +6338,20 @@
 			index = XGI_GetTVPtrIndex(pVBInfo); /* Get TV Delay */
 			tempbl = pVBInfo->XGI_TVDelayList[index];
 
-			if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B
-					| VB_XGI301LV | VB_XGI302LV
+			if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B
+					| VB_SIS301LV | VB_SIS302LV
 					| VB_XGI301C))
 				tempbl = pVBInfo->XGI_TVDelayList2[index];
 
 			if (pVBInfo->VBInfo & SetCRT2ToDualEdge)
 				tempbl = tempbl >> 4;
-			if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+			if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
 				/* Get LCD Delay */
 				index = XGI_GetLCDCapPtr(pVBInfo);
 				tempbh = pVBInfo->LCDCapList[index].
 						LCD_DelayCompensation;
 
-				if (!(pVBInfo->VBInfo & SetCRT2ToLCDA))
+				if (!(pVBInfo->VBInfo & XGI_SetCRT2ToLCDA))
 					tempbl = tempbh;
 			}
 
@@ -6365,7 +6365,7 @@
 				tempah |= tempbl;
 			}
 
-			if (pVBInfo->VBInfo & SetCRT2ToLCDA) { /* Channel A */
+			if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) { /* Channel A */
 				tempah &= 0x0F;
 				tempah |= tempbh;
 			}
@@ -6475,13 +6475,13 @@
 	tempcx = pVBInfo->LCDCapList[XGI_GetLCDCapPtr(pVBInfo)].LCD_Capability;
 
 	if (pVBInfo->VBType &
-	    (VB_XGI301B |
-	     VB_XGI302B |
-	     VB_XGI301LV |
-	     VB_XGI302LV |
+	    (VB_SIS301B |
+	     VB_SIS302B |
+	     VB_SIS301LV |
+	     VB_SIS302LV |
 	     VB_XGI301C)) { /* 301LV/302LV only */
 		if (pVBInfo->VBType &
-		    (VB_XGI301LV | VB_XGI302LV | VB_XGI301C)) {
+		    (VB_SIS301LV | VB_SIS302LV | VB_XGI301C)) {
 			/* Set 301LV Capability */
 			xgifb_reg_set(pVBInfo->Part4Port, 0x24,
 					(unsigned char) (tempcx & 0x1F));
@@ -6493,14 +6493,14 @@
 						| EnablePLLSPLOW)) >> 8));
 	}
 
-	if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-			| VB_XGI302LV | VB_XGI301C)) {
+	if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+			| VB_SIS302LV | VB_XGI301C)) {
 		if (pVBInfo->VBInfo & SetCRT2ToLCD)
 			XGI_SetLCDCap_B(tempcx, pVBInfo);
-		else if (pVBInfo->VBInfo & SetCRT2ToLCDA)
+		else if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA)
 			XGI_SetLCDCap_A(tempcx, pVBInfo);
 
-		if (pVBInfo->VBType & (VB_XGI302LV | VB_XGI301C)) {
+		if (pVBInfo->VBType & (VB_SIS302LV | VB_XGI301C)) {
 			if (tempcx & EnableSpectrum)
 				SetSpectrum(pVBInfo);
 		}
@@ -6524,7 +6524,7 @@
 
 	unsigned char tempah;
 
-	if (pVBInfo->TVInfo & (SetYPbPrMode525p | SetYPbPrMode750p))
+	if (pVBInfo->TVInfo & (TVSetYPbPr525p | TVSetYPbPr750p))
 		return;
 
 	tempbx = XGI_GetTVPtrIndex(pVBInfo);
@@ -6648,8 +6648,8 @@
 		xgifb_reg_set(pVBInfo->Part2Port, 0x38, filterPtr[index++]);
 	}
 
-	if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-			| VB_XGI302LV | VB_XGI301C)) {
+	if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+			| VB_SIS302LV | VB_XGI301C)) {
 		xgifb_reg_set(pVBInfo->Part2Port, 0x48, filterPtr[index++]);
 		xgifb_reg_set(pVBInfo->Part2Port, 0x49, filterPtr[index++]);
 		xgifb_reg_set(pVBInfo->Part2Port, 0x4A, filterPtr[index++]);
@@ -6668,7 +6668,7 @@
 {
 	XGI_SetDelayComp(pVBInfo);
 
-	if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA))
+	if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA))
 		XGI_SetLCDCap(pVBInfo);
 
 	if (pVBInfo->VBInfo & SetCRT2ToTV) {
@@ -6676,7 +6676,7 @@
 		XGI_SetYFilter(ModeNo, ModeIdIndex, pVBInfo);
 		XGI_SetAntiFlicker(ModeNo, ModeIdIndex, pVBInfo);
 
-		if (pVBInfo->VBType & VB_XGI301)
+		if (pVBInfo->VBType & VB_SIS301)
 			XGI_SetEdgeEnhance(ModeNo, ModeIdIndex, pVBInfo);
 	}
 }
@@ -6732,15 +6732,15 @@
 		tempbl = 0xff;
 
 		if (pVBInfo->VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToTV
-				| SetCRT2ToLCD | SetCRT2ToLCDA)) {
-			if ((pVBInfo->VBInfo & SetCRT2ToLCDA) &&
+				| SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
+			if ((pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) &&
 			    (!(pVBInfo->VBInfo & SetSimuScanMode))) {
 				tempbl &= 0xf7;
 				tempah |= 0x01;
 				xgifb_reg_and_or(pVBInfo->Part1Port, 0x2e,
 						tempbl, tempah);
 			} else {
-				if (pVBInfo->VBInfo & SetCRT2ToLCDA) {
+				if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
 					tempbl &= 0xf7;
 					tempah |= 0x01;
 				}
@@ -6780,7 +6780,7 @@
 	}
 
 	if (pVBInfo->VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToTV | SetCRT2ToLCD
-			| SetCRT2ToLCDA)) {
+			| XGI_SetCRT2ToLCDA)) {
 		tempah &= (~0x08);
 		if ((pVBInfo->ModeType == ModeVGA) && (!(pVBInfo->VBInfo
 				& SetInSlaveMode))) {
@@ -6807,24 +6807,24 @@
 				tempah |= 0x40;
 		}
 
-		if ((pVBInfo->LCDResInfo == Panel1280x1024)
-				|| (pVBInfo->LCDResInfo == Panel1280x1024x75))
+		if ((pVBInfo->LCDResInfo == Panel_1280x1024)
+				|| (pVBInfo->LCDResInfo == Panel_1280x1024x75))
 			tempah |= 0x80;
 
-		if (pVBInfo->LCDResInfo == Panel1280x960)
+		if (pVBInfo->LCDResInfo == Panel_1280x960)
 			tempah |= 0x80;
 
 		xgifb_reg_set(pVBInfo->Part4Port, 0x0C, tempah);
 	}
 
-	if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-			| VB_XGI302LV | VB_XGI301C)) {
+	if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+			| VB_SIS302LV | VB_XGI301C)) {
 		tempah = 0;
 		tempbl = 0xfb;
 
 		if (pVBInfo->VBInfo & SetCRT2ToDualEdge) {
 			tempbl = 0xff;
-			if (pVBInfo->VBInfo & SetCRT2ToLCDA)
+			if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA)
 				tempah |= 0x04; /* shampoo 0129 */
 		}
 
@@ -6849,7 +6849,7 @@
 
 	tempah = 0;
 	tempbl = 0x7f;
-	if (!(pVBInfo->VBInfo & SetCRT2ToLCDA)) {
+	if (!(pVBInfo->VBInfo & XGI_SetCRT2ToLCDA)) {
 		tempbl = 0xff;
 		if (!(pVBInfo->VBInfo & SetCRT2ToDualEdge))
 			tempah |= 0x80;
@@ -6857,7 +6857,7 @@
 
 	xgifb_reg_and_or(pVBInfo->Part4Port, 0x23, tempbl, tempah);
 
-	if (pVBInfo->VBType & (VB_XGI302LV | VB_XGI301C)) {
+	if (pVBInfo->VBType & (VB_SIS302LV | VB_XGI301C)) {
 		if (pVBInfo->LCDInfo & SetLCDDualLink) {
 			xgifb_reg_or(pVBInfo->Part4Port, 0x27, 0x20);
 			xgifb_reg_or(pVBInfo->Part4Port, 0x34, 0x10);
@@ -6872,7 +6872,7 @@
 
 	tempbx = 0;
 
-	if (pVBInfo->VBInfo & SetCRT2ToLCDA)
+	if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA)
 		tempbx = 0x08A0;
 
 }
@@ -6937,10 +6937,10 @@
 		index--;
 
 	if (pVBInfo->SetFlag & ProgrammingCRT2) {
-		if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+		if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
 			if (pVBInfo->IF_DEF_LVDS == 0) {
-				if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B
-						| VB_XGI301LV | VB_XGI302LV
+				if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B
+						| VB_SIS301LV | VB_SIS302LV
 						| VB_XGI301C))
 					/* 301b */
 					temp = LCDARefreshIndex[
@@ -6983,7 +6983,7 @@
 			break;
 		temp = pVBInfo->RefIndex[RefreshRateTableIndex + i].
 			Ext_InfoFlag;
-		temp &= ModeInfoFlag;
+		temp &= ModeTypeMask;
 		if (temp < pVBInfo->ModeType)
 			break;
 		i++;
@@ -7163,8 +7163,8 @@
 {
 	unsigned short tempah;
 
-	if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-			| VB_XGI302LV | VB_XGI301C)) {
+	if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+			| VB_SIS302LV | VB_XGI301C)) {
 		if (!(pVBInfo->SetFlag & DisableChA)) {
 			if (pVBInfo->SetFlag & EnableChA) {
 				/* Power on */
@@ -7207,11 +7207,11 @@
 				|| (!(pVBInfo->VBInfo & DisableCRT2Display))) {
 			xgifb_reg_and_or(pVBInfo->Part2Port, 0x00, ~0xE0,
 					0x20); /* shampoo 0129 */
-			if (pVBInfo->VBType & (VB_XGI302LV | VB_XGI301C)) {
+			if (pVBInfo->VBType & (VB_SIS302LV | VB_XGI301C)) {
 				if (!XGI_DisableChISLCD(pVBInfo)) {
 					if (XGI_EnableChISLCD(pVBInfo) ||
 					    (pVBInfo->VBInfo &
-					    (SetCRT2ToLCD | SetCRT2ToLCDA)))
+					    (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)))
 						/* LVDS PLL power on */
 						xgifb_reg_and(
 							pVBInfo->Part4Port,
@@ -7229,12 +7229,12 @@
 			tempah = 0xc0;
 
 			if (!(pVBInfo->VBInfo & SetSimuScanMode)) {
-				if (pVBInfo->VBInfo & SetCRT2ToLCDA) {
+				if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
 					if (pVBInfo->VBInfo &
 					    SetCRT2ToDualEdge) {
 						tempah = tempah & 0x40;
 						if (pVBInfo->VBInfo &
-						    SetCRT2ToLCDA)
+						    XGI_SetCRT2ToLCDA)
 							tempah = tempah ^ 0xC0;
 
 						if (pVBInfo->SetFlag &
@@ -7271,7 +7271,7 @@
 	} /* 301 */
 	else { /* LVDS */
 		if (pVBInfo->VBInfo & (SetCRT2ToTV | SetCRT2ToLCD
-				| SetCRT2ToLCDA))
+				| XGI_SetCRT2ToLCDA))
 			/* enable CRT2 */
 			xgifb_reg_or(pVBInfo->Part1Port, 0x1E, 0x20);
 
@@ -7311,9 +7311,9 @@
 	pVBInfo->SetFlag &= temp;
 	pVBInfo->SelectCRT2Rate = 0;
 
-	if (pVBInfo->VBType & (VB_XGI301B | VB_XGI302B | VB_XGI301LV
-			| VB_XGI302LV | VB_XGI301C)) {
-		if (pVBInfo->VBInfo & (SetSimuScanMode | SetCRT2ToLCDA
+	if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
+			| VB_SIS302LV | VB_XGI301C)) {
+		if (pVBInfo->VBInfo & (SetSimuScanMode | XGI_SetCRT2ToLCDA
 				| SetInSlaveMode)) {
 			pVBInfo->SetFlag |= ProgrammingCRT2;
 		}
@@ -7415,11 +7415,11 @@
 	pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19;
 	pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A;
 	pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00;
-	pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04;
-	pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10;
-	pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12;
-	pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14;
-	pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2;
+	pVBInfo->Part1Port = pVBInfo->BaseAddr + SIS_CRT2_PORT_04;
+	pVBInfo->Part2Port = pVBInfo->BaseAddr + SIS_CRT2_PORT_10;
+	pVBInfo->Part3Port = pVBInfo->BaseAddr + SIS_CRT2_PORT_12;
+	pVBInfo->Part4Port = pVBInfo->BaseAddr + SIS_CRT2_PORT_14;
+	pVBInfo->Part5Port = pVBInfo->BaseAddr + SIS_CRT2_PORT_14 + 2;
 
 	/* for x86 Linux, XG21 LVDS */
 	if (HwDeviceExtension->jChipType == XG21) {
@@ -7452,20 +7452,20 @@
 		XGI_GetLCDInfo(ModeNo, ModeIdIndex, pVBInfo);
 		XGI_DisableBridge(xgifb_info, HwDeviceExtension, pVBInfo);
 
-		if (pVBInfo->VBInfo & (SetSimuScanMode | SetCRT2ToLCDA)) {
+		if (pVBInfo->VBInfo & (SetSimuScanMode | XGI_SetCRT2ToLCDA)) {
 			XGI_SetCRT1Group(xgifb_info, HwDeviceExtension, ModeNo,
 					ModeIdIndex, pVBInfo);
 
-			if (pVBInfo->VBInfo & SetCRT2ToLCDA) {
+			if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
 				XGI_SetLCDAGroup(ModeNo, ModeIdIndex,
 						HwDeviceExtension, pVBInfo);
 			}
 		} else {
-			if (!(pVBInfo->VBInfo & SwitchToCRT2)) {
+			if (!(pVBInfo->VBInfo & SwitchCRT2)) {
 				XGI_SetCRT1Group(xgifb_info,
 						HwDeviceExtension, ModeNo,
 						ModeIdIndex, pVBInfo);
-				if (pVBInfo->VBInfo & SetCRT2ToLCDA) {
+				if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
 					XGI_SetLCDAGroup(ModeNo, ModeIdIndex,
 							HwDeviceExtension,
 							pVBInfo);
@@ -7473,7 +7473,7 @@
 			}
 		}
 
-		if (pVBInfo->VBInfo & (SetSimuScanMode | SwitchToCRT2)) {
+		if (pVBInfo->VBInfo & (SetSimuScanMode | SwitchCRT2)) {
 			switch (HwDeviceExtension->ujVBChipID) {
 			case VB_CHIP_301:
 				XGI_SetCRT2Group301(ModeNo, HwDeviceExtension,
@@ -7504,10 +7504,10 @@
 
 		if (ModeNo <= 0x13) {
 			pVBInfo->ModeType = pVBInfo->SModeIDTable[ModeIdIndex].
-						St_ModeFlag & ModeInfoFlag;
+						St_ModeFlag & ModeTypeMask;
 		} else {
 			pVBInfo->ModeType = pVBInfo->EModeIDTable[ModeIdIndex].
-						Ext_ModeFlag & ModeInfoFlag;
+						Ext_ModeFlag & ModeTypeMask;
 		}
 
 		pVBInfo->SetFlag = 0;
diff --git a/drivers/staging/xgifb/vb_struct.h b/drivers/staging/xgifb/vb_struct.h
index 6556a0d..a5bd56a 100644
--- a/drivers/staging/xgifb/vb_struct.h
+++ b/drivers/staging/xgifb/vb_struct.h
@@ -1,15 +1,6 @@
 #ifndef _VB_STRUCT_
 #define _VB_STRUCT_
-
-struct XGI_LCDDataStruct {
-	unsigned short RVBHCMAX;
-	unsigned short RVBHCFACT;
-	unsigned short VGAHT;
-	unsigned short VGAVT;
-	unsigned short LCDHT;
-	unsigned short LCDVT;
-};
-
+#include "../../video/sis/vstruct.h"
 
 struct XGI_LVDSCRT1HDataStruct {
 	unsigned char Reg[8];
@@ -19,22 +10,6 @@
 	unsigned char Reg[7];
 };
 
-struct XGI_TVDataStruct {
-	unsigned short RVBHCMAX;
-	unsigned short RVBHCFACT;
-	unsigned short VGAHT;
-	unsigned short VGAVT;
-	unsigned short TVHDE;
-	unsigned short TVVDE;
-	unsigned short RVBHRS;
-	unsigned char FlickerMode;
-	unsigned short HALFRVBHRS;
-	unsigned char RY1COE;
-	unsigned char RY2COE;
-	unsigned char RY3COE;
-	unsigned char RY4COE;
-};
-
 struct XGI_StStruct {
 	unsigned char St_ModeID;
 	unsigned short St_ModeFlag;
@@ -47,18 +22,6 @@
 	unsigned char VB_StTVYFilterIndex;
 };
 
-struct XGI_StandTableStruct {
-	unsigned char CRT_COLS;
-	unsigned char ROWS;
-	unsigned char CHAR_HEIGHT;
-	unsigned short CRT_LEN;
-	unsigned char SR[4];
-	unsigned char MISC;
-	unsigned char CRTC[0x19];
-	unsigned char ATTR[0x14];
-	unsigned char GRC[9];
-};
-
 struct XGI_ExtStruct {
 	unsigned char Ext_ModeID;
 	unsigned short Ext_ModeFlag;
@@ -85,39 +48,11 @@
 	/* unsigned short ROM_OFFSET; */
 };
 
-
-struct XGI_MCLKDataStruct {
-	unsigned char SR28, SR29, SR2A;
-	unsigned short CLOCK;
-};
-
 struct XGI_ECLKDataStruct {
 	unsigned char SR2E, SR2F, SR30;
 	unsigned short CLOCK;
 };
 
-struct XGI_VCLKDataStruct {
-	unsigned char SR2B, SR2C;
-	unsigned short CLOCK;
-};
-
-struct XGI_VBVCLKDataStruct {
-	unsigned char Part4_A, Part4_B;
-	unsigned short CLOCK;
-};
-
-struct XGI_StResInfoStruct {
-	unsigned short HTotal;
-	unsigned short VTotal;
-};
-
-struct XGI_ModeResInfoStruct {
-	unsigned short HTotal;
-	unsigned short VTotal;
-	unsigned char  XChar;
-	unsigned char  YChar;
-};
-
 /*add for new UNIVGABIOS*/
 struct XGI_LCDDesStruct {
 	unsigned short LCDHDES;
@@ -350,7 +285,7 @@
 	unsigned char  *pCRT2Data_4_D;
 	unsigned char  *pCRT2Data_4_E;
 	unsigned char  *pCRT2Data_4_10;
-	struct XGI_MCLKDataStruct  *MCLKData;
+	struct SiS_MCLKData  *MCLKData;
 	struct XGI_ECLKDataStruct  *ECLKData;
 
 	unsigned char   *XGI_TVDelayList;
@@ -380,15 +315,15 @@
 	struct XGI_TimingVStruct  *TimingV;
 
 	struct XGI_StStruct          *SModeIDTable;
-	struct XGI_StandTableStruct  *StandTable;
+	struct SiS_StandTable_S  *StandTable;
 	struct XGI_ExtStruct         *EModeIDTable;
 	struct XGI_Ext2Struct        *RefIndex;
 	/* XGINew_CRT1TableStruct *CRT1Table; */
 	struct XGI_CRT1TableStruct    *XGINEWUB_CRT1Table;
-	struct XGI_VCLKDataStruct    *VCLKData;
-	struct XGI_VBVCLKDataStruct  *VBVCLKData;
-	struct XGI_StResInfoStruct   *StResInfo;
-	struct XGI_ModeResInfoStruct *ModeResInfo;
+	struct SiS_VCLKData    *VCLKData;
+	struct SiS_VBVCLKData  *VBVCLKData;
+	struct SiS_StResInfo_S   *StResInfo;
+	struct SiS_ModeResInfo_S *ModeResInfo;
 	struct XGI_XG21CRT1Struct	  *UpdateCRT1;
 
 	int ram_type;
diff --git a/drivers/staging/xgifb/vb_table.h b/drivers/staging/xgifb/vb_table.h
index e7946f1..dddf261 100644
--- a/drivers/staging/xgifb/vb_table.h
+++ b/drivers/staging/xgifb/vb_table.h
@@ -1,5 +1,5 @@
 /* yilin modify for xgi20 */
-static struct XGI_MCLKDataStruct XGI340New_MCLKData[] = {
+static struct SiS_MCLKData XGI340New_MCLKData[] = {
 	{0x16, 0x01, 0x01, 166},
 	{0x19, 0x02, 0x01, 124},
 	{0x7C, 0x08, 0x01, 200},
@@ -10,7 +10,7 @@
 	{0x5c, 0x23, 0x01, 166}
 };
 
-static struct XGI_MCLKDataStruct XGI27New_MCLKData[] = {
+static struct SiS_MCLKData XGI27New_MCLKData[] = {
 	{0x5c, 0x23, 0x01, 166},
 	{0x19, 0x02, 0x01, 124},
 	{0x7C, 0x08, 0x80, 200},
@@ -296,7 +296,7 @@
 		0x00, 0x00, 0x00, 0x00, 0x00}
 };
 
-static struct XGI_StandTableStruct XGI330_StandTable[] = {
+static struct SiS_StandTable_S XGI330_StandTable[] = {
 /* MD_0_200 */
 	{
 		0x28, 0x18, 0x08, 0x0800,
@@ -2353,109 +2353,109 @@
 
 /*add for new UNIVGABIOS*/
 static struct XGI330_LCDDataTablStruct XGI_LCDDataTable[] = {
-	{Panel1024x768, 0x0019, 0x0001, 0}, /* XGI_ExtLCD1024x768Data */
-	{Panel1024x768, 0x0019, 0x0000, 1}, /* XGI_StLCD1024x768Data */
-	{Panel1024x768, 0x0018, 0x0010, 2}, /* XGI_CetLCD1024x768Data */
-	{Panel1280x1024, 0x0019, 0x0001, 3}, /* XGI_ExtLCD1280x1024Data */
-	{Panel1280x1024, 0x0019, 0x0000, 4}, /* XGI_StLCD1280x1024Data */
-	{Panel1280x1024, 0x0018, 0x0010, 5}, /* XGI_CetLCD1280x1024Data */
-	{Panel1400x1050, 0x0019, 0x0001, 6}, /* XGI_ExtLCD1400x1050Data */
-	{Panel1400x1050, 0x0019, 0x0000, 7}, /* XGI_StLCD1400x1050Data */
-	{Panel1400x1050, 0x0018, 0x0010, 8}, /* XGI_CetLCD1400x1050Data */
-	{Panel1600x1200, 0x0019, 0x0001, 9}, /* XGI_ExtLCD1600x1200Data */
-	{Panel1600x1200, 0x0019, 0x0000, 10}, /* XGI_StLCD1600x1200Data */
+	{Panel_1024x768, 0x0019, 0x0001, 0}, /* XGI_ExtLCD1024x768Data */
+	{Panel_1024x768, 0x0019, 0x0000, 1}, /* XGI_StLCD1024x768Data */
+	{Panel_1024x768, 0x0018, 0x0010, 2}, /* XGI_CetLCD1024x768Data */
+	{Panel_1280x1024, 0x0019, 0x0001, 3}, /* XGI_ExtLCD1280x1024Data */
+	{Panel_1280x1024, 0x0019, 0x0000, 4}, /* XGI_StLCD1280x1024Data */
+	{Panel_1280x1024, 0x0018, 0x0010, 5}, /* XGI_CetLCD1280x1024Data */
+	{Panel_1400x1050, 0x0019, 0x0001, 6}, /* XGI_ExtLCD1400x1050Data */
+	{Panel_1400x1050, 0x0019, 0x0000, 7}, /* XGI_StLCD1400x1050Data */
+	{Panel_1400x1050, 0x0018, 0x0010, 8}, /* XGI_CetLCD1400x1050Data */
+	{Panel_1600x1200, 0x0019, 0x0001, 9}, /* XGI_ExtLCD1600x1200Data */
+	{Panel_1600x1200, 0x0019, 0x0000, 10}, /* XGI_StLCD1600x1200Data */
 	{PanelRef60Hz, 0x0008, 0x0008, 11}, /* XGI_NoScalingData */
-	{Panel1024x768x75, 0x0019, 0x0001, 12}, /* XGI_ExtLCD1024x768x75Data */
-	{Panel1024x768x75, 0x0019, 0x0000, 13}, /* XGI_StLCD1024x768x75Data */
-	{Panel1024x768x75, 0x0018, 0x0010, 14}, /* XGI_CetLCD1024x768x75Data */
-	{Panel1280x1024x75, 0x0019, 0x0001, 15}, /* XGI_ExtLCD1280x1024x75Data*/
-	{Panel1280x1024x75, 0x0019, 0x0000, 16}, /* XGI_StLCD1280x1024x75Data */
-	{Panel1280x1024x75, 0x0018, 0x0010, 17}, /* XGI_CetLCD1280x1024x75Data*/
+	{Panel_1024x768x75, 0x0019, 0x0001, 12}, /* XGI_ExtLCD1024x768x75Data */
+	{Panel_1024x768x75, 0x0019, 0x0000, 13}, /* XGI_StLCD1024x768x75Data */
+	{Panel_1024x768x75, 0x0018, 0x0010, 14}, /* XGI_CetLCD1024x768x75Data */
+	{Panel_1280x1024x75, 0x0019, 0x0001, 15}, /* XGI_ExtLCD1280x1024x75Data*/
+	{Panel_1280x1024x75, 0x0019, 0x0000, 16}, /* XGI_StLCD1280x1024x75Data */
+	{Panel_1280x1024x75, 0x0018, 0x0010, 17}, /* XGI_CetLCD1280x1024x75Data*/
 	{PanelRef75Hz, 0x0008, 0x0008, 18}, /* XGI_NoScalingDatax75 */
 	{0xFF, 0x0000, 0x0000, 0} /* End of table */
 };
 
 static struct XGI330_LCDDataTablStruct XGI_LCDDesDataTable[] = {
-	{Panel1024x768, 0x0019, 0x0001, 0}, /* XGI_ExtLCDDes1024x768Data */
-	{Panel1024x768, 0x0019, 0x0000, 1}, /* XGI_StLCDDes1024x768Data */
-	{Panel1024x768, 0x0018, 0x0010, 2}, /* XGI_CetLCDDes1024x768Data */
-	{Panel1280x1024, 0x0019, 0x0001, 3}, /* XGI_ExtLCDDes1280x1024Data */
-	{Panel1280x1024, 0x0019, 0x0000, 4}, /* XGI_StLCDDes1280x1024Data */
-	{Panel1280x1024, 0x0018, 0x0010, 5}, /* XGI_CetLCDDes1280x1024Data */
-	{Panel1400x1050, 0x0019, 0x0001, 6}, /* XGI_ExtLCDDes1400x1050Data */
-	{Panel1400x1050, 0x0019, 0x0000, 7}, /* XGI_StLCDDes1400x1050Data */
-	{Panel1400x1050, 0x0418, 0x0010, 8}, /* XGI_CetLCDDes1400x1050Data */
-	{Panel1400x1050, 0x0418, 0x0410, 9}, /* XGI_CetLCDDes1400x1050Data2 */
-	{Panel1600x1200, 0x0019, 0x0001, 10}, /* XGI_ExtLCDDes1600x1200Data */
-	{Panel1600x1200, 0x0019, 0x0000, 11}, /* XGI_StLCDDes1600x1200Data */
+	{Panel_1024x768, 0x0019, 0x0001, 0}, /* XGI_ExtLCDDes1024x768Data */
+	{Panel_1024x768, 0x0019, 0x0000, 1}, /* XGI_StLCDDes1024x768Data */
+	{Panel_1024x768, 0x0018, 0x0010, 2}, /* XGI_CetLCDDes1024x768Data */
+	{Panel_1280x1024, 0x0019, 0x0001, 3}, /* XGI_ExtLCDDes1280x1024Data */
+	{Panel_1280x1024, 0x0019, 0x0000, 4}, /* XGI_StLCDDes1280x1024Data */
+	{Panel_1280x1024, 0x0018, 0x0010, 5}, /* XGI_CetLCDDes1280x1024Data */
+	{Panel_1400x1050, 0x0019, 0x0001, 6}, /* XGI_ExtLCDDes1400x1050Data */
+	{Panel_1400x1050, 0x0019, 0x0000, 7}, /* XGI_StLCDDes1400x1050Data */
+	{Panel_1400x1050, 0x0418, 0x0010, 8}, /* XGI_CetLCDDes1400x1050Data */
+	{Panel_1400x1050, 0x0418, 0x0410, 9}, /* XGI_CetLCDDes1400x1050Data2 */
+	{Panel_1600x1200, 0x0019, 0x0001, 10}, /* XGI_ExtLCDDes1600x1200Data */
+	{Panel_1600x1200, 0x0019, 0x0000, 11}, /* XGI_StLCDDes1600x1200Data */
 	{PanelRef60Hz, 0x0008, 0x0008, 12}, /* XGI_NoScalingDesData */
-	{Panel1024x768x75, 0x0019, 0x0001, 13}, /*XGI_ExtLCDDes1024x768x75Data*/
-	{Panel1024x768x75, 0x0019, 0x0000, 14}, /* XGI_StLCDDes1024x768x75Data*/
-	{Panel1024x768x75, 0x0018, 0x0010, 15}, /*XGI_CetLCDDes1024x768x75Data*/
+	{Panel_1024x768x75, 0x0019, 0x0001, 13}, /*XGI_ExtLCDDes1024x768x75Data*/
+	{Panel_1024x768x75, 0x0019, 0x0000, 14}, /* XGI_StLCDDes1024x768x75Data*/
+	{Panel_1024x768x75, 0x0018, 0x0010, 15}, /*XGI_CetLCDDes1024x768x75Data*/
 	/* XGI_ExtLCDDes1280x1024x75Data */
-	{Panel1280x1024x75, 0x0019, 0x0001, 16},
+	{Panel_1280x1024x75, 0x0019, 0x0001, 16},
 	/* XGI_StLCDDes1280x1024x75Data */
-	{Panel1280x1024x75, 0x0019, 0x0000, 17},
+	{Panel_1280x1024x75, 0x0019, 0x0000, 17},
 	/* XGI_CetLCDDes1280x1024x75Data */
-	{Panel1280x1024x75, 0x0018, 0x0010, 18},
+	{Panel_1280x1024x75, 0x0018, 0x0010, 18},
 	{PanelRef75Hz, 0x0008, 0x0008, 19}, /* XGI_NoScalingDesDatax75 */
 	{0xFF, 0x0000, 0x0000, 0}
 };
 
 static struct XGI330_LCDDataTablStruct xgifb_epllcd_crt1[] = {
-	{Panel1024x768, 0x0018, 0x0000, 0}, /* XGI_LVDSCRT11024x768_1 */
-	{Panel1024x768, 0x0018, 0x0010, 1}, /* XGI_LVDSCRT11024x768_2 */
-	{Panel1280x1024, 0x0018, 0x0000, 2}, /* XGI_LVDSCRT11280x1024_1 */
-	{Panel1280x1024, 0x0018, 0x0010, 3}, /* XGI_LVDSCRT11280x1024_2 */
-	{Panel1400x1050, 0x0018, 0x0000, 4}, /* XGI_LVDSCRT11400x1050_1 */
-	{Panel1400x1050, 0x0018, 0x0010, 5}, /* XGI_LVDSCRT11400x1050_2 */
-	{Panel1600x1200, 0x0018, 0x0000, 6}, /* XGI_LVDSCRT11600x1200_1 */
-	{Panel1024x768x75, 0x0018, 0x0000, 7}, /* XGI_LVDSCRT11024x768_1x75 */
-	{Panel1024x768x75, 0x0018, 0x0010, 8}, /* XGI_LVDSCRT11024x768_2x75 */
-	{Panel1280x1024x75, 0x0018, 0x0000, 9}, /*XGI_LVDSCRT11280x1024_1x75*/
-	{Panel1280x1024x75, 0x0018, 0x0010, 10},/*XGI_LVDSCRT11280x1024_2x75*/
+	{Panel_1024x768, 0x0018, 0x0000, 0}, /* XGI_LVDSCRT11024x768_1 */
+	{Panel_1024x768, 0x0018, 0x0010, 1}, /* XGI_LVDSCRT11024x768_2 */
+	{Panel_1280x1024, 0x0018, 0x0000, 2}, /* XGI_LVDSCRT11280x1024_1 */
+	{Panel_1280x1024, 0x0018, 0x0010, 3}, /* XGI_LVDSCRT11280x1024_2 */
+	{Panel_1400x1050, 0x0018, 0x0000, 4}, /* XGI_LVDSCRT11400x1050_1 */
+	{Panel_1400x1050, 0x0018, 0x0010, 5}, /* XGI_LVDSCRT11400x1050_2 */
+	{Panel_1600x1200, 0x0018, 0x0000, 6}, /* XGI_LVDSCRT11600x1200_1 */
+	{Panel_1024x768x75, 0x0018, 0x0000, 7}, /* XGI_LVDSCRT11024x768_1x75 */
+	{Panel_1024x768x75, 0x0018, 0x0010, 8}, /* XGI_LVDSCRT11024x768_2x75 */
+	{Panel_1280x1024x75, 0x0018, 0x0000, 9}, /*XGI_LVDSCRT11280x1024_1x75*/
+	{Panel_1280x1024x75, 0x0018, 0x0010, 10},/*XGI_LVDSCRT11280x1024_2x75*/
 	{0xFF, 0x0000, 0x0000, 0}
 };
 
 static struct XGI330_LCDDataTablStruct XGI_EPLLCDDataPtr[] = {
-	{Panel1024x768, 0x0018, 0x0000, 0}, /* XGI_LVDS1024x768Data_1 */
-	{Panel1024x768, 0x0018, 0x0010, 1}, /* XGI_LVDS1024x768Data_2 */
-	{Panel1280x1024, 0x0018, 0x0000, 2}, /* XGI_LVDS1280x1024Data_1 */
-	{Panel1280x1024, 0x0018, 0x0010, 3}, /* XGI_LVDS1280x1024Data_2 */
-	{Panel1400x1050, 0x0018, 0x0000, 4}, /* XGI_LVDS1400x1050Data_1 */
-	{Panel1400x1050, 0x0018, 0x0010, 5}, /* XGI_LVDS1400x1050Data_2 */
-	{Panel1600x1200, 0x0018, 0x0000, 6}, /* XGI_LVDS1600x1200Data_1 */
+	{Panel_1024x768, 0x0018, 0x0000, 0}, /* XGI_LVDS1024x768Data_1 */
+	{Panel_1024x768, 0x0018, 0x0010, 1}, /* XGI_LVDS1024x768Data_2 */
+	{Panel_1280x1024, 0x0018, 0x0000, 2}, /* XGI_LVDS1280x1024Data_1 */
+	{Panel_1280x1024, 0x0018, 0x0010, 3}, /* XGI_LVDS1280x1024Data_2 */
+	{Panel_1400x1050, 0x0018, 0x0000, 4}, /* XGI_LVDS1400x1050Data_1 */
+	{Panel_1400x1050, 0x0018, 0x0010, 5}, /* XGI_LVDS1400x1050Data_2 */
+	{Panel_1600x1200, 0x0018, 0x0000, 6}, /* XGI_LVDS1600x1200Data_1 */
 	{PanelRef60Hz, 0x0008, 0x0008, 7}, /* XGI_LVDSNoScalingData */
-	{Panel1024x768x75, 0x0018, 0x0000, 8}, /* XGI_LVDS1024x768Data_1x75 */
-	{Panel1024x768x75, 0x0018, 0x0010, 9}, /* XGI_LVDS1024x768Data_2x75 */
-	{Panel1280x1024x75, 0x0018, 0x0000, 10}, /* XGI_LVDS1280x1024Data_1x75*/
-	{Panel1280x1024x75, 0x0018, 0x0010, 11},  /*XGI_LVDS1280x1024Data_2x75*/
+	{Panel_1024x768x75, 0x0018, 0x0000, 8}, /* XGI_LVDS1024x768Data_1x75 */
+	{Panel_1024x768x75, 0x0018, 0x0010, 9}, /* XGI_LVDS1024x768Data_2x75 */
+	{Panel_1280x1024x75, 0x0018, 0x0000, 10}, /* XGI_LVDS1280x1024Data_1x75*/
+	{Panel_1280x1024x75, 0x0018, 0x0010, 11},  /*XGI_LVDS1280x1024Data_2x75*/
 	{PanelRef75Hz, 0x0008, 0x0008, 12}, /* XGI_LVDSNoScalingDatax75 */
 	{0xFF, 0x0000, 0x0000, 0}
 };
 
 static struct XGI330_LCDDataTablStruct XGI_EPLLCDDesDataPtr[] = {
-	{Panel1024x768, 0x0018, 0x0000, 0}, /* XGI_LVDS1024x768Des_1 */
-	{Panel1024x768, 0x0618, 0x0410, 1}, /* XGI_LVDS1024x768Des_3 */
-	{Panel1024x768, 0x0018, 0x0010, 2}, /* XGI_LVDS1024x768Des_2 */
-	{Panel1280x1024, 0x0018, 0x0000, 3}, /* XGI_LVDS1280x1024Des_1 */
-	{Panel1280x1024, 0x0018, 0x0010, 4}, /* XGI_LVDS1280x1024Des_2 */
-	{Panel1400x1050, 0x0018, 0x0000, 5}, /* XGI_LVDS1400x1050Des_1 */
-	{Panel1400x1050, 0x0018, 0x0010, 6}, /* XGI_LVDS1400x1050Des_2 */
-	{Panel1600x1200, 0x0018, 0x0000, 7}, /* XGI_LVDS1600x1200Des_1 */
+	{Panel_1024x768, 0x0018, 0x0000, 0}, /* XGI_LVDS1024x768Des_1 */
+	{Panel_1024x768, 0x0618, 0x0410, 1}, /* XGI_LVDS1024x768Des_3 */
+	{Panel_1024x768, 0x0018, 0x0010, 2}, /* XGI_LVDS1024x768Des_2 */
+	{Panel_1280x1024, 0x0018, 0x0000, 3}, /* XGI_LVDS1280x1024Des_1 */
+	{Panel_1280x1024, 0x0018, 0x0010, 4}, /* XGI_LVDS1280x1024Des_2 */
+	{Panel_1400x1050, 0x0018, 0x0000, 5}, /* XGI_LVDS1400x1050Des_1 */
+	{Panel_1400x1050, 0x0018, 0x0010, 6}, /* XGI_LVDS1400x1050Des_2 */
+	{Panel_1600x1200, 0x0018, 0x0000, 7}, /* XGI_LVDS1600x1200Des_1 */
 	{PanelRef60Hz, 0x0008, 0x0008, 8},  /* XGI_LVDSNoScalingDesData */
-	{Panel1024x768x75, 0x0018, 0x0000, 9}, /* XGI_LVDS1024x768Des_1x75 */
-	{Panel1024x768x75, 0x0618, 0x0410, 10}, /* XGI_LVDS1024x768Des_3x75 */
-	{Panel1024x768x75, 0x0018, 0x0010, 11}, /* XGI_LVDS1024x768Des_2x75 */
-	{Panel1280x1024x75, 0x0018, 0x0000, 12}, /* XGI_LVDS1280x1024Des_1x75 */
-	{Panel1280x1024x75, 0x0018, 0x0010, 13}, /* XGI_LVDS1280x1024Des_2x75 */
+	{Panel_1024x768x75, 0x0018, 0x0000, 9}, /* XGI_LVDS1024x768Des_1x75 */
+	{Panel_1024x768x75, 0x0618, 0x0410, 10}, /* XGI_LVDS1024x768Des_3x75 */
+	{Panel_1024x768x75, 0x0018, 0x0010, 11}, /* XGI_LVDS1024x768Des_2x75 */
+	{Panel_1280x1024x75, 0x0018, 0x0000, 12}, /* XGI_LVDS1280x1024Des_1x75 */
+	{Panel_1280x1024x75, 0x0018, 0x0010, 13}, /* XGI_LVDS1280x1024Des_2x75 */
 	{PanelRef75Hz, 0x0008, 0x0008, 14}, /* XGI_LVDSNoScalingDesDatax75 */
 	{0xFF, 0x0000, 0x0000, 0}
 };
 
 static struct XGI330_LCDDataTablStruct XGI_EPLCHLCDRegPtr[] = {
-	{Panel1024x768, 0x0000, 0x0000, 0}, /* XGI_CH7017LV1024x768 */
-	{Panel1400x1050, 0x0000, 0x0000, 1}, /* XGI_CH7017LV1400x1050 */
+	{Panel_1024x768, 0x0000, 0x0000, 0}, /* XGI_CH7017LV1024x768 */
+	{Panel_1400x1050, 0x0000, 0x0000, 1}, /* XGI_CH7017LV1400x1050 */
 	{0xFF, 0x0000, 0x0000, 0}
 };
 
@@ -2501,225 +2501,225 @@
 /* Dual link only */
 static struct XGI330_LCDCapStruct  XGI_LCDDLCapList[] = {
 /* LCDCap1024x768 */
-	{Panel1024x768, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65,
+	{Panel_1024x768, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65_315,
 	0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
 /* LCDCap1280x1024 */
-	{Panel1280x1024, LCDDualLink+DefaultLCDCap, StLCDBToA,
-	0x012, 0x70, 0x03, VCLK108_2,
+	{Panel_1280x1024, XGI_LCDDualLink+DefaultLCDCap, StLCDBToA,
+	0x012, 0x70, 0x03, VCLK108_2_315,
 	0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
 /* LCDCap1400x1050 */
-	{Panel1400x1050, LCDDualLink+DefaultLCDCap, StLCDBToA,
-	0x012, 0x70, 0x03, VCLK108_2,
+	{Panel_1400x1050, XGI_LCDDualLink+DefaultLCDCap, StLCDBToA,
+	0x012, 0x70, 0x03, VCLK108_2_315,
 	 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
 /* LCDCap1600x1200 */
-	{Panel1600x1200, LCDDualLink+DefaultLCDCap, LCDToFull,
+	{Panel_1600x1200, XGI_LCDDualLink+DefaultLCDCap, LCDToFull,
 	0x012, 0xC0, 0x03, VCLK162,
 	 0x43, 0x22, 0x70, 0x24, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
 /* LCDCap1024x768x75 */
-	{Panel1024x768x75, DefaultLCDCap, 0, 0x012, 0x60, 0, VCLK78_75,
+	{Panel_1024x768x75, DefaultLCDCap, 0, 0x012, 0x60, 0, VCLK78_75,
 	 0x2B, 0x61, 0x2B, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
 /* LCDCap1280x1024x75 */
-	{Panel1280x1024x75, LCDDualLink+DefaultLCDCap, StLCDBToA,
+	{Panel_1280x1024x75, XGI_LCDDualLink+DefaultLCDCap, StLCDBToA,
 	0x012, 0x90, 0x03, VCLK135_5,
 	 0x54, 0x42, 0x4A, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
 /* LCDCapDefault */
-	{0xFF, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65,
+	{0xFF, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65_315,
 	0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}
 };
 
 static struct XGI330_LCDCapStruct  XGI_LCDCapList[] = {
 /* LCDCap1024x768 */
-	{Panel1024x768, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65,
+	{Panel_1024x768, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65_315,
 	0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
 /* LCDCap1280x1024 */
-	{Panel1280x1024, DefaultLCDCap, StLCDBToA,
-	0x012, 0x70, 0x03, VCLK108_2,
+	{Panel_1280x1024, DefaultLCDCap, StLCDBToA,
+	0x012, 0x70, 0x03, VCLK108_2_315,
 	0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
 /* LCDCap1400x1050 */
-	{Panel1400x1050, DefaultLCDCap, StLCDBToA,
-	0x012, 0x70, 0x03, VCLK108_2,
+	{Panel_1400x1050, DefaultLCDCap, StLCDBToA,
+	0x012, 0x70, 0x03, VCLK108_2_315,
 	 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
 /* LCDCap1600x1200 */
-	{Panel1600x1200, DefaultLCDCap, LCDToFull,
+	{Panel_1600x1200, DefaultLCDCap, LCDToFull,
 	0x012, 0xC0, 0x03, VCLK162,
 	 0x5A, 0x23, 0x5A, 0x23, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
 /* LCDCap1024x768x75 */
-	{Panel1024x768x75, DefaultLCDCap, 0, 0x012, 0x60, 0, VCLK78_75,
+	{Panel_1024x768x75, DefaultLCDCap, 0, 0x012, 0x60, 0, VCLK78_75,
 	 0x2B, 0x61, 0x2B, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
 /* LCDCap1280x1024x75 */
-	{Panel1280x1024x75, DefaultLCDCap, StLCDBToA,
+	{Panel_1280x1024x75, DefaultLCDCap, StLCDBToA,
 	0x012, 0x90, 0x03, VCLK135_5,
 	 0x54, 0x42, 0x4A, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
 /* LCDCapDefault */
-	{0xFF, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65,
+	{0xFF, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65_315,
 	0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}
 };
 
 static struct XGI_Ext2Struct XGI330_RefIndex[] = {
-	{Support32Bpp + SupportAllCRT2 + SyncPN, RES320x200, VCLK25_175,
+	{Mode32Bpp + SupportAllCRT2 + SyncPN, RES320x200, VCLK25_175,
 	0x00, 0x10, 0x59, 320, 200},/* 00 */
-	{Support32Bpp + SupportAllCRT2 + SyncPN, RES320x200, VCLK25_175,
+	{Mode32Bpp + SupportAllCRT2 + SyncPN, RES320x200, VCLK25_175,
 	0x00, 0x10, 0x00, 320, 400},/* 01 */
-	{Support32Bpp + SupportAllCRT2 + SyncNN, RES320x240, VCLK25_175,
+	{Mode32Bpp + SupportAllCRT2 + SyncNN, RES320x240, VCLK25_175,
 	0x04, 0x20, 0x50, 320, 240},/* 02 */
-	{Support32Bpp + SupportAllCRT2 + SyncPP, RES400x300, VCLK40,
+	{Mode32Bpp + SupportAllCRT2 + SyncPP, RES400x300, VCLK40,
 	0x05, 0x32, 0x51, 400, 300},/* 03 */
-	{Support32Bpp + NoSupportTV + SyncNN + SupportTV1024, RES512x384,
-	VCLK65, 0x06, 0x43, 0x52, 512, 384},/* 04 */
-	{Support32Bpp + SupportAllCRT2 + SyncPN, RES640x400, VCLK25_175,
+	{Mode32Bpp + NoSupportTV + SyncNN + SupportTV1024, RES512x384,
+	VCLK65_315, 0x06, 0x43, 0x52, 512, 384},/* 04 */
+	{Mode32Bpp + SupportAllCRT2 + SyncPN, RES640x400, VCLK25_175,
 	0x00, 0x14, 0x2f, 640, 400},/* 05 */
-	{Support32Bpp + SupportAllCRT2 + SyncNN, RES640x480x60, VCLK25_175,
+	{Mode32Bpp + SupportAllCRT2 + SyncNN, RES640x480x60, VCLK25_175,
 	0x04, 0x24, 0x2e, 640, 480},/* 06 640x480x60Hz (LCD 640x480x60z) */
-	{Support32Bpp + NoSupportHiVisionTV + SyncNN, RES640x480x72, VCLK31_5,
+	{Mode32Bpp + NoSupportHiVisionTV + SyncNN, RES640x480x72, VCLK31_5,
 	0x04, 0x24, 0x2e, 640, 480},/* 07 640x480x72Hz (LCD 640x480x70Hz) */
-	{Support32Bpp + NoSupportHiVisionTV + SyncNN, RES640x480x75, VCLK31_5,
+	{Mode32Bpp + NoSupportHiVisionTV + SyncNN, RES640x480x75, VCLK31_5,
 	0x47, 0x24, 0x2e, 640, 480},/* 08 640x480x75Hz (LCD 640x480x75Hz) */
-	{Support32Bpp + SupportRAMDAC2 + SyncNN, RES640x480x85, VCLK36,
+	{Mode32Bpp + SupportRAMDAC2 + SyncNN, RES640x480x85, VCLK36,
 	0x8A, 0x24, 0x2e, 640, 480},/* 09 640x480x85Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncPN, RES640x480x100, VCLK43_163,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPN, RES640x480x100, VCLK43_163,
 	0x00, 0x24, 0x2e, 640, 480},/* 0a 640x480x100Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncPN, RES640x480x120, VCLK52_406,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPN, RES640x480x120, VCLK52_406,
 	0x00, 0x24, 0x2e, 640, 480},/* 0b 640x480x120Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncPN, RES640x480x160, VCLK72_852,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPN, RES640x480x160, VCLK72_852,
 	0x00, 0x24, 0x2e, 640, 480},/* 0c 640x480x160Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncNN, RES640x480x200, VCLK86_6,
+	{Mode32Bpp + SupportRAMDAC2 + SyncNN, RES640x480x200, VCLK86_6,
 	0x00, 0x24, 0x2e, 640, 480},/* 0d 640x480x200Hz */
-	{Support32Bpp + NoSupportLCD + SyncPP, RES800x600x56, VCLK36,
+	{Mode32Bpp + NoSupportLCD + SyncPP, RES800x600x56, VCLK36,
 	0x05, 0x36, 0x6a, 800, 600},/* 0e 800x600x56Hz */
-	{Support32Bpp + NoSupportTV + SyncPP, RES800x600x60, VCLK40,
+	{Mode32Bpp + NoSupportTV + SyncPP, RES800x600x60, VCLK40,
 	0x05, 0x36, 0x6a, 800, 600},/* 0f 800x600x60Hz (LCD 800x600x60Hz) */
-	{Support32Bpp + NoSupportHiVisionTV + SyncPP, RES800x600x72, VCLK50,
+	{Mode32Bpp + NoSupportHiVisionTV + SyncPP, RES800x600x72, VCLK50,
 	0x48, 0x36, 0x6a, 800, 600},/* 10 800x600x72Hz (LCD 800x600x70Hz) */
-	{Support32Bpp + NoSupportHiVisionTV + SyncPP, RES800x600x75, VCLK49_5,
+	{Mode32Bpp + NoSupportHiVisionTV + SyncPP, RES800x600x75, VCLK49_5,
 	0x8B, 0x36, 0x6a, 800, 600},/* 11 800x600x75Hz (LCD 800x600x75Hz) */
-	{Support32Bpp + SupportRAMDAC2 + SyncPP, RES800x600x85, VCLK56_25,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPP, RES800x600x85, VCLK56_25,
 	0x00, 0x36, 0x6a, 800, 600},/* 12 800x600x85Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncPN, RES800x600x100, VCLK68_179,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPN, RES800x600x100, VCLK68_179,
 	0x00, 0x36, 0x6a, 800, 600},/* 13 800x600x100Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncPN, RES800x600x120, VCLK83_95,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPN, RES800x600x120, VCLK83_95,
 	0x00, 0x36, 0x6a, 800, 600},/* 14 800x600x120Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncPN, RES800x600x160, VCLK116_406,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPN, RES800x600x160, VCLK116_406,
 	0x00, 0x36, 0x6a, 800, 600},/* 15 800x600x160Hz */
-	{Support32Bpp + InterlaceMode + SyncPP, RES1024x768x43, VCLK44_9,
+	{Mode32Bpp + InterlaceMode + SyncPP, RES1024x768x43, VCLK44_9,
 	0x00, 0x47, 0x37, 1024, 768},/* 16 1024x768x43Hz */
 	/* 17 1024x768x60Hz (LCD 1024x768x60Hz) */
-	{Support32Bpp + NoSupportTV + SyncNN + SupportTV1024, RES1024x768x60,
-	VCLK65, 0x06, 0x47, 0x37, 1024, 768},
-	{Support32Bpp + NoSupportHiVisionTV + SyncNN, RES1024x768x70, VCLK75,
+	{Mode32Bpp + NoSupportTV + SyncNN + SupportTV1024, RES1024x768x60,
+	VCLK65_315, 0x06, 0x47, 0x37, 1024, 768},
+	{Mode32Bpp + NoSupportHiVisionTV + SyncNN, RES1024x768x70, VCLK75,
 	0x49, 0x47, 0x37, 1024, 768},/* 18 1024x768x70Hz (LCD 1024x768x70Hz) */
-	{Support32Bpp + NoSupportHiVisionTV + SyncPP, RES1024x768x75, VCLK78_75,
+	{Mode32Bpp + NoSupportHiVisionTV + SyncPP, RES1024x768x75, VCLK78_75,
 	0x00, 0x47, 0x37, 1024, 768},/* 19 1024x768x75Hz (LCD 1024x768x75Hz) */
-	{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1024x768x85, VCLK94_5,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPP, RES1024x768x85, VCLK94_5,
 	0x8C, 0x47, 0x37, 1024, 768},/* 1a 1024x768x85Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncPN, RES1024x768x100, VCLK113_309,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPN, RES1024x768x100, VCLK113_309,
 	0x00, 0x47, 0x37, 1024, 768},/* 1b 1024x768x100Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncPN, RES1024x768x120, VCLK139_054,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPN, RES1024x768x120, VCLK139_054,
 	0x00, 0x47, 0x37, 1024, 768},/* 1c 1024x768x120Hz */
-	{Support32Bpp + SupportLCD + SyncPP, RES1280x960x60, VCLK108_2,
+	{Mode32Bpp + SupportLCD + SyncPP, RES1280x960x60, VCLK108_2_315,
 	0x08, 0x58, 0x7b, 1280, 960},/* 1d 1280x960x60Hz */
-	{Support32Bpp + InterlaceMode + SyncPP, RES1280x1024x43, VCLK78_75,
+	{Mode32Bpp + InterlaceMode + SyncPP, RES1280x1024x43, VCLK78_75,
 	0x00, 0x58, 0x3a, 1280, 1024},/* 1e 1280x1024x43Hz */
-	{Support32Bpp + NoSupportTV + SyncPP, RES1280x1024x60, VCLK108_2,
+	{Mode32Bpp + NoSupportTV + SyncPP, RES1280x1024x60, VCLK108_2_315,
 	0x07, 0x58, 0x3a, 1280, 1024},/*1f 1280x1024x60Hz (LCD 1280x1024x60Hz)*/
-	{Support32Bpp + NoSupportTV + SyncPP, RES1280x1024x75, VCLK135_5,
+	{Mode32Bpp + NoSupportTV + SyncPP, RES1280x1024x75, VCLK135_5,
 	0x00, 0x58, 0x3a, 1280, 1024},/*20 1280x1024x75Hz (LCD 1280x1024x75Hz)*/
-	{Support32Bpp + SyncPP, RES1280x1024x85, VCLK157_5,
+	{Mode32Bpp + SyncPP, RES1280x1024x85, VCLK157_5,
 	0x00, 0x58, 0x3a, 1280, 1024},/* 21 1280x1024x85Hz */
 	/* 22 1600x1200x60Hz */
-	{Support32Bpp + SupportLCD + SyncPP + SupportCRT2in301C,
+	{Mode32Bpp + SupportLCD + SyncPP + SupportCRT2in301C,
 	RES1600x1200x60, VCLK162, 0x09, 0x7A, 0x3c, 1600, 1200},
-	{Support32Bpp + SyncPP + SupportCRT2in301C, RES1600x1200x65, VCLK175,
+	{Mode32Bpp + SyncPP + SupportCRT2in301C, RES1600x1200x65, VCLK175,
 	0x00, 0x69, 0x3c, 1600, 1200},/* 23 1600x1200x65Hz */
-	{Support32Bpp + SyncPP + SupportCRT2in301C, RES1600x1200x70, VCLK189,
+	{Mode32Bpp + SyncPP + SupportCRT2in301C, RES1600x1200x70, VCLK189,
 	0x00, 0x69, 0x3c, 1600, 1200},/* 24 1600x1200x70Hz */
-	{Support32Bpp + SyncPP + SupportCRT2in301C, RES1600x1200x75, VCLK202_5,
+	{Mode32Bpp + SyncPP + SupportCRT2in301C, RES1600x1200x75, VCLK202_5,
 	0x00, 0x69, 0x3c, 1600, 1200},/* 25 1600x1200x75Hz */
-	{Support32Bpp + SyncPP, RES1600x1200x85, VCLK229_5,
+	{Mode32Bpp + SyncPP, RES1600x1200x85, VCLK229_5,
 	0x00, 0x69, 0x3c, 1600, 1200},/* 26 1600x1200x85Hz */
-	{Support32Bpp + SyncPP, RES1600x1200x100, VCLK269_655,
+	{Mode32Bpp + SyncPP, RES1600x1200x100, VCLK269_655,
 	0x00, 0x69, 0x3c, 1600, 1200},/* 27 1600x1200x100Hz */
-	{Support32Bpp + SyncPP, RES1600x1200x120, VCLK323_586,
+	{Mode32Bpp + SyncPP, RES1600x1200x120, VCLK323_586,
 	0x00, 0x69, 0x3c, 1600, 1200},/* 28 1600x1200x120Hz */
-	{Support32Bpp + SupportLCD + SyncNP, RES1920x1440x60, VCLK234,
+	{Mode32Bpp + SupportLCD + SyncNP, RES1920x1440x60, VCLK234,
 	0x00, 0x00, 0x68, 1920, 1440},/* 29 1920x1440x60Hz */
-	{Support32Bpp + SyncPN, RES1920x1440x65, VCLK254_817,
+	{Mode32Bpp + SyncPN, RES1920x1440x65, VCLK254_817,
 	0x00, 0x00, 0x68, 1920, 1440},/* 2a 1920x1440x65Hz */
-	{Support32Bpp + SyncPN, RES1920x1440x70, VCLK277_015,
+	{Mode32Bpp + SyncPN, RES1920x1440x70, VCLK277_015,
 	0x00, 0x00, 0x68, 1920, 1440},/* 2b 1920x1440x70Hz */
-	{Support32Bpp + SyncPN, RES1920x1440x75, VCLK291_132,
+	{Mode32Bpp + SyncPN, RES1920x1440x75, VCLK291_132,
 	0x00, 0x00, 0x68, 1920, 1440},/* 2c 1920x1440x75Hz */
-	{Support32Bpp + SyncPN, RES1920x1440x85, VCLK330_615,
+	{Mode32Bpp + SyncPN, RES1920x1440x85, VCLK330_615,
 	0x00, 0x00, 0x68, 1920, 1440},/* 2d 1920x1440x85Hz */
-	{Support16Bpp + SyncPN, RES1920x1440x100, VCLK388_631,
+	{Mode16Bpp + SyncPN, RES1920x1440x100, VCLK388_631,
 	0x00, 0x00, 0x68, 1920, 1440},/* 2e 1920x1440x100Hz */
-	{Support32Bpp + SupportLCD + SyncPN, RES2048x1536x60, VCLK266_952,
+	{Mode32Bpp + SupportLCD + SyncPN, RES2048x1536x60, VCLK266_952,
 	0x00, 0x00, 0x6c, 2048, 1536},/* 2f 2048x1536x60Hz */
-	{Support32Bpp + SyncPN, RES2048x1536x65, VCLK291_766,
+	{Mode32Bpp + SyncPN, RES2048x1536x65, VCLK291_766,
 	0x00, 0x00, 0x6c, 2048, 1536},/* 30 2048x1536x65Hz */
-	{Support32Bpp + SyncPN, RES2048x1536x70, VCLK315_195,
+	{Mode32Bpp + SyncPN, RES2048x1536x70, VCLK315_195,
 	0x00, 0x00, 0x6c, 2048, 1536},/* 31 2048x1536x70Hz */
-	{Support32Bpp + SyncPN, RES2048x1536x75, VCLK340_477,
+	{Mode32Bpp + SyncPN, RES2048x1536x75, VCLK340_477,
 	0x00, 0x00, 0x6c, 2048, 1536},/* 32 2048x1536x75Hz */
-	{Support16Bpp + SyncPN, RES2048x1536x85, VCLK375_847,
+	{Mode16Bpp + SyncPN, RES2048x1536x85, VCLK375_847,
 	0x00, 0x00, 0x6c, 2048, 1536},/* 33 2048x1536x85Hz */
-	{Support32Bpp + SupportHiVisionTV + SupportRAMDAC2 +
-	 SyncPP + SupportYPbPr, RES800x480x60, VCLK39_77,
+	{Mode32Bpp + SupportHiVision + SupportRAMDAC2 +
+	 SyncPP + SupportYPbPr750p, RES800x480x60, VCLK39_77,
 	 0x08, 0x00, 0x70, 800, 480},/* 34 800x480x60Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncPP, RES800x480x75, VCLK49_5,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPP, RES800x480x75, VCLK49_5,
 	0x08, 0x00, 0x70, 800, 480},/* 35 800x480x75Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncPP, RES800x480x85, VCLK56_25,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPP, RES800x480x85, VCLK56_25,
 	0x08, 0x00, 0x70, 800, 480},/* 36 800x480x85Hz */
-	{Support32Bpp + SupportHiVisionTV + SupportRAMDAC2 +
-	 SyncPP + SupportYPbPr, RES1024x576x60, VCLK65,
+	{Mode32Bpp + SupportHiVision + SupportRAMDAC2 +
+	 SyncPP + SupportYPbPr750p, RES1024x576x60, VCLK65_315,
 	 0x09, 0x00, 0x71, 1024, 576},/* 37 1024x576x60Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1024x576x75, VCLK78_75,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPP, RES1024x576x75, VCLK78_75,
 	0x09, 0x00, 0x71, 1024, 576},/* 38 1024x576x75Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1024x576x85, VCLK94_5,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPP, RES1024x576x85, VCLK94_5,
 	0x09, 0x00, 0x71, 1024, 576},/* 39 1024x576x85Hz */
-	{Support32Bpp + SupportHiVisionTV + SupportRAMDAC2 +
-	SyncPP + SupportYPbPr, RES1280x720x60, VCLK108_2,
+	{Mode32Bpp + SupportHiVision + SupportRAMDAC2 +
+	SyncPP + SupportYPbPr750p, RES1280x720x60, VCLK108_2_315,
 	0x0A, 0x00, 0x75, 1280, 720},/* 3a 1280x720x60Hz*/
-	{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1280x720x75, VCLK135_5,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPP, RES1280x720x75, VCLK135_5,
 	0x0A, 0x00, 0x75, 1280, 720},/* 3b 1280x720x75Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1280x720x85, VCLK157_5,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPP, RES1280x720x85, VCLK157_5,
 	0x0A, 0x00, 0x75, 1280, 720},/* 3c 1280x720x85Hz */
-	{Support32Bpp + SupportTV + SyncNN, RES720x480x60, VCLK28_322,
+	{Mode32Bpp + SupportTV + SyncNN, RES720x480x60, VCLK28_322,
 	0x06, 0x00, 0x31,  720, 480},/* 3d 720x480x60Hz */
-	{Support32Bpp + SupportTV + SyncPP, RES720x576x56, VCLK36,
+	{Mode32Bpp + SupportTV + SyncPP, RES720x576x56, VCLK36,
 	0x06, 0x00, 0x32, 720, 576},/* 3e 720x576x56Hz */
-	{Support32Bpp + InterlaceMode + NoSupportLCD + SyncPP, RES856x480x79I,
+	{Mode32Bpp + InterlaceMode + NoSupportLCD + SyncPP, RES856x480x79I,
 	VCLK35_2, 0x00, 0x00, 0x00,  856, 480},/* 3f 856x480x79I */
-	{Support32Bpp + NoSupportLCD + SyncNN, RES856x480x60, VCLK35_2,
+	{Mode32Bpp + NoSupportLCD + SyncNN, RES856x480x60, VCLK35_2,
 	0x00, 0x00, 0x00,  856, 480},/* 40 856x480x60Hz */
-	{Support32Bpp + NoSupportHiVisionTV + SyncPP, RES1280x768x60,
+	{Mode32Bpp + NoSupportHiVisionTV + SyncPP, RES1280x768x60,
 	VCLK79_411, 0x08, 0x48, 0x23, 1280, 768},/* 41 1280x768x60Hz */
-	{Support32Bpp + NoSupportHiVisionTV + SyncPP, RES1400x1050x60,
+	{Mode32Bpp + NoSupportHiVisionTV + SyncPP, RES1400x1050x60,
 	VCLK122_61, 0x08, 0x69, 0x26, 1400, 1050},/* 42 1400x1050x60Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1152x864x60, VCLK80_350,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPP, RES1152x864x60, VCLK80_350,
 	0x37, 0x00, 0x20, 1152, 864},/* 43 1152x864x60Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1152x864x75, VCLK107_385,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPP, RES1152x864x75, VCLK107_385,
 	0x37, 0x00, 0x20, 1152, 864},/* 44 1152x864x75Hz */
-	{Support32Bpp + SupportLCD + SupportRAMDAC2 + SyncPP, RES1280x960x75,
+	{Mode32Bpp + SupportLCD + SupportRAMDAC2 + SyncPP, RES1280x960x75,
 	VCLK125_999, 0x3A, 0x88, 0x7b, 1280, 960},/* 45 1280x960x75Hz */
-	{Support32Bpp + SupportLCD + SupportRAMDAC2 + SyncPP, RES1280x960x85,
+	{Mode32Bpp + SupportLCD + SupportRAMDAC2 + SyncPP, RES1280x960x85,
 	VCLK148_5, 0x0A, 0x88, 0x7b, 1280, 960},/* 46 1280x960x85Hz */
-	{Support32Bpp + SupportLCD + SupportRAMDAC2 + SyncPP, RES1280x960x120,
+	{Mode32Bpp + SupportLCD + SupportRAMDAC2 + SyncPP, RES1280x960x120,
 	VCLK217_325, 0x3A, 0x88, 0x7b, 1280, 960},/* 47 1280x960x120Hz */
-	{Support32Bpp + SupportRAMDAC2 + SyncPN, RES1024x768x160, VCLK139_054,
+	{Mode32Bpp + SupportRAMDAC2 + SyncPN, RES1024x768x160, VCLK139_054,
 	0x30, 0x47, 0x37, 1024, 768},/* 48 1024x768x160Hz */
 };
 
@@ -2729,7 +2729,7 @@
 	0x57, 0x48
 };
 
-static struct XGI_StResInfoStruct XGI330_StResInfo[] = {
+static struct SiS_StResInfo_S XGI330_StResInfo[] = {
 	{640, 400},
 	{640, 350},
 	{720, 400},
@@ -2737,7 +2737,7 @@
 	{640, 480}
 };
 
-static struct XGI_ModeResInfoStruct XGI330_ModeResInfo[] = {
+static struct SiS_ModeResInfo_S XGI330_ModeResInfo[] = {
 	{ 320,  200, 8,  8},
 	{ 320,  240, 8,  8},
 	{ 320,  400, 8,  8},
diff --git a/drivers/staging/xgifb/vgatypes.h b/drivers/staging/xgifb/vgatypes.h
index 9e166bb..a7208e3 100644
--- a/drivers/staging/xgifb/vgatypes.h
+++ b/drivers/staging/xgifb/vgatypes.h
@@ -2,6 +2,9 @@
 #define _VGATYPES_
 
 #include <linux/ioctl.h>
+#include <linux/fb.h>	/* for struct fb_var_screeninfo for sis.h */
+#include "../../video/sis/vgatypes.h"
+#include "../../video/sis/sis.h"		/* for LCD_TYPE */
 
 #ifndef XGI_VB_CHIP_TYPE
 enum XGI_VB_CHIP_TYPE {
@@ -19,6 +22,12 @@
 };
 #endif
 
+
+#define XGI_LCD_TYPE
+/* Since the merge with video/sis the LCD_TYPEs are used from
+ drivers/video/sis/sis.h . Nevertheless we keep this (for the moment) for
+ future reference until the code is merged completely and we are sure
+ nothing of this should be added to the sis.h header */
 #ifndef XGI_LCD_TYPE
 enum XGI_LCD_TYPE {
 	LCD_INVALID = 0,
diff --git a/drivers/staging/zcache/Kconfig b/drivers/staging/zcache/Kconfig
index 7fabcb2..3ed2c8f 100644
--- a/drivers/staging/zcache/Kconfig
+++ b/drivers/staging/zcache/Kconfig
@@ -1,13 +1,14 @@
 config ZCACHE
-	tristate "Dynamic compression of swap pages and clean pagecache pages"
-	depends on CLEANCACHE || FRONTSWAP
-	select XVMALLOC
-	select LZO_COMPRESS
-	select LZO_DECOMPRESS
+	bool "Dynamic compression of swap pages and clean pagecache pages"
+	# X86 dependency is because zsmalloc uses non-portable pte/tlb
+	# functions
+	depends on (CLEANCACHE || FRONTSWAP) && CRYPTO && X86
+	select ZSMALLOC
+	select CRYPTO_LZO
 	default n
 	help
 	  Zcache doubles RAM efficiency while providing a significant
-	  performance boosts on many workloads.  Zcache uses lzo1x
+	  performance boosts on many workloads.  Zcache uses
 	  compression and an in-kernel implementation of transcendent
 	  memory to store clean page cache pages and swap in RAM,
 	  providing a noticeable reduction in disk I/O.
diff --git a/drivers/staging/zcache/tmem.h b/drivers/staging/zcache/tmem.h
index ed147c4..0d4aa82 100644
--- a/drivers/staging/zcache/tmem.h
+++ b/drivers/staging/zcache/tmem.h
@@ -47,7 +47,7 @@
 #define ASSERT_INVERTED_SENTINEL(_x, _y) do { } while (0)
 #endif
 
-#define ASSERT_SPINLOCK(_l)	WARN_ON(!spin_is_locked(_l))
+#define ASSERT_SPINLOCK(_l)	lockdep_assert_held(_l)
 
 /*
  * A pool is the highest-level data structure managed by tmem and
diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c
index ef7c52b..7073465 100644
--- a/drivers/staging/zcache/zcache-main.c
+++ b/drivers/staging/zcache/zcache-main.c
@@ -6,9 +6,10 @@
  *
  * Zcache provides an in-kernel "host implementation" for transcendent memory
  * and, thus indirectly, for cleancache and frontswap.  Zcache includes two
- * page-accessible memory [1] interfaces, both utilizing lzo1x compression:
+ * page-accessible memory [1] interfaces, both utilizing the crypto compression
+ * API:
  * 1) "compression buddies" ("zbud") is used for ephemeral pages
- * 2) xvmalloc is used for persistent pages.
+ * 2) zsmalloc is used for persistent pages.
  * Xvmalloc (based on the TLSF allocator) has very low fragmentation
  * so maximizes space efficiency, while zbud allows pairs (and potentially,
  * in the future, more than a pair of) compressed pages to be closely linked
@@ -23,15 +24,16 @@
 #include <linux/cpu.h>
 #include <linux/highmem.h>
 #include <linux/list.h>
-#include <linux/lzo.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/atomic.h>
 #include <linux/math64.h>
+#include <linux/crypto.h>
+#include <linux/string.h>
 #include "tmem.h"
 
-#include "../zram/xvmalloc.h" /* if built in drivers/staging */
+#include "../zsmalloc/zsmalloc.h"
 
 #if (!defined(CONFIG_CLEANCACHE) && !defined(CONFIG_FRONTSWAP))
 #error "zcache is useless without CONFIG_CLEANCACHE or CONFIG_FRONTSWAP"
@@ -60,7 +62,7 @@
 
 struct zcache_client {
 	struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT];
-	struct xv_pool *xvpool;
+	struct zs_pool *zspool;
 	bool allocated;
 	atomic_t refcount;
 };
@@ -81,6 +83,38 @@
 	return cli == &zcache_host;
 }
 
+/* crypto API for zcache  */
+#define ZCACHE_COMP_NAME_SZ CRYPTO_MAX_ALG_NAME
+static char zcache_comp_name[ZCACHE_COMP_NAME_SZ];
+static struct crypto_comp * __percpu *zcache_comp_pcpu_tfms;
+
+enum comp_op {
+	ZCACHE_COMPOP_COMPRESS,
+	ZCACHE_COMPOP_DECOMPRESS
+};
+
+static inline int zcache_comp_op(enum comp_op op,
+				const u8 *src, unsigned int slen,
+				u8 *dst, unsigned int *dlen)
+{
+	struct crypto_comp *tfm;
+	int ret;
+
+	BUG_ON(!zcache_comp_pcpu_tfms);
+	tfm = *per_cpu_ptr(zcache_comp_pcpu_tfms, get_cpu());
+	BUG_ON(!tfm);
+	switch (op) {
+	case ZCACHE_COMPOP_COMPRESS:
+		ret = crypto_comp_compress(tfm, src, slen, dst, dlen);
+		break;
+	case ZCACHE_COMPOP_DECOMPRESS:
+		ret = crypto_comp_decompress(tfm, src, slen, dst, dlen);
+		break;
+	}
+	put_cpu();
+	return ret;
+}
+
 /**********
  * Compression buddies ("zbud") provides for packing two (or, possibly
  * in the future, more) compressed ephemeral pages into a single "raw"
@@ -299,10 +333,12 @@
 	struct zbud_page *zbpg =
 		container_of(zh, struct zbud_page, buddy[budnum]);
 
+	spin_lock(&zbud_budlists_spinlock);
 	spin_lock(&zbpg->lock);
 	if (list_empty(&zbpg->bud_list)) {
 		/* ignore zombie page... see zbud_evict_pages() */
 		spin_unlock(&zbpg->lock);
+		spin_unlock(&zbud_budlists_spinlock);
 		return;
 	}
 	size = zbud_free(zh);
@@ -310,7 +346,6 @@
 	zh_other = &zbpg->buddy[(budnum == 0) ? 1 : 0];
 	if (zh_other->size == 0) { /* was unbuddied: unlist and free */
 		chunks = zbud_size_to_chunks(size) ;
-		spin_lock(&zbud_budlists_spinlock);
 		BUG_ON(list_empty(&zbud_unbuddied[chunks].list));
 		list_del_init(&zbpg->bud_list);
 		zbud_unbuddied[chunks].count--;
@@ -318,7 +353,6 @@
 		zbud_free_raw_page(zbpg);
 	} else { /* was buddied: move remaining buddy to unbuddied list */
 		chunks = zbud_size_to_chunks(zh_other->size) ;
-		spin_lock(&zbud_budlists_spinlock);
 		list_del_init(&zbpg->bud_list);
 		zcache_zbud_buddied_count--;
 		list_add_tail(&zbpg->bud_list, &zbud_unbuddied[chunks].list);
@@ -407,7 +441,7 @@
 {
 	struct zbud_page *zbpg;
 	unsigned budnum = zbud_budnum(zh);
-	size_t out_len = PAGE_SIZE;
+	unsigned int out_len = PAGE_SIZE;
 	char *to_va, *from_va;
 	unsigned size;
 	int ret = 0;
@@ -424,8 +458,9 @@
 	to_va = kmap_atomic(page, KM_USER0);
 	size = zh->size;
 	from_va = zbud_data(zh, size);
-	ret = lzo1x_decompress_safe(from_va, size, to_va, &out_len);
-	BUG_ON(ret != LZO_E_OK);
+	ret = zcache_comp_op(ZCACHE_COMPOP_DECOMPRESS, from_va, size,
+				to_va, &out_len);
+	BUG_ON(ret);
 	BUG_ON(out_len != PAGE_SIZE);
 	kunmap_atomic(to_va, KM_USER0);
 out:
@@ -622,8 +657,8 @@
 #endif
 
 /**********
- * This "zv" PAM implementation combines the TLSF-based xvMalloc
- * with lzo1x compression to maximize the amount of data that can
+ * This "zv" PAM implementation combines the slab-based zsmalloc
+ * with the crypto compression API to maximize the amount of data that can
  * be packed into a physical page.
  *
  * Zv represents a PAM page with the index and object (plus a "size" value
@@ -636,6 +671,7 @@
 	uint32_t pool_id;
 	struct tmem_oid oid;
 	uint32_t index;
+	size_t size;
 	DECL_SENTINEL
 };
 
@@ -657,72 +693,72 @@
 static atomic_t zv_curr_dist_counts[NCHUNKS];
 static atomic_t zv_cumul_dist_counts[NCHUNKS];
 
-static struct zv_hdr *zv_create(struct xv_pool *xvpool, uint32_t pool_id,
+static struct zv_hdr *zv_create(struct zs_pool *pool, uint32_t pool_id,
 				struct tmem_oid *oid, uint32_t index,
 				void *cdata, unsigned clen)
 {
-	struct page *page;
-	struct zv_hdr *zv = NULL;
-	uint32_t offset;
-	int alloc_size = clen + sizeof(struct zv_hdr);
-	int chunks = (alloc_size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT;
-	int ret;
+	struct zv_hdr *zv;
+	u32 size = clen + sizeof(struct zv_hdr);
+	int chunks = (size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT;
+	void *handle = NULL;
 
 	BUG_ON(!irqs_disabled());
 	BUG_ON(chunks >= NCHUNKS);
-	ret = xv_malloc(xvpool, alloc_size,
-			&page, &offset, ZCACHE_GFP_MASK);
-	if (unlikely(ret))
+	handle = zs_malloc(pool, size);
+	if (!handle)
 		goto out;
 	atomic_inc(&zv_curr_dist_counts[chunks]);
 	atomic_inc(&zv_cumul_dist_counts[chunks]);
-	zv = kmap_atomic(page, KM_USER0) + offset;
+	zv = zs_map_object(pool, handle);
 	zv->index = index;
 	zv->oid = *oid;
 	zv->pool_id = pool_id;
+	zv->size = clen;
 	SET_SENTINEL(zv, ZVH);
 	memcpy((char *)zv + sizeof(struct zv_hdr), cdata, clen);
-	kunmap_atomic(zv, KM_USER0);
+	zs_unmap_object(pool, handle);
 out:
-	return zv;
+	return handle;
 }
 
-static void zv_free(struct xv_pool *xvpool, struct zv_hdr *zv)
+static void zv_free(struct zs_pool *pool, void *handle)
 {
 	unsigned long flags;
-	struct page *page;
-	uint32_t offset;
-	uint16_t size = xv_get_object_size(zv);
-	int chunks = (size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT;
+	struct zv_hdr *zv;
+	uint16_t size;
+	int chunks;
 
+	zv = zs_map_object(pool, handle);
 	ASSERT_SENTINEL(zv, ZVH);
+	size = zv->size + sizeof(struct zv_hdr);
+	INVERT_SENTINEL(zv, ZVH);
+	zs_unmap_object(pool, handle);
+
+	chunks = (size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT;
 	BUG_ON(chunks >= NCHUNKS);
 	atomic_dec(&zv_curr_dist_counts[chunks]);
-	size -= sizeof(*zv);
-	BUG_ON(size == 0);
-	INVERT_SENTINEL(zv, ZVH);
-	page = virt_to_page(zv);
-	offset = (unsigned long)zv & ~PAGE_MASK;
+
 	local_irq_save(flags);
-	xv_free(xvpool, page, offset);
+	zs_free(pool, handle);
 	local_irq_restore(flags);
 }
 
-static void zv_decompress(struct page *page, struct zv_hdr *zv)
+static void zv_decompress(struct page *page, void *handle)
 {
-	size_t clen = PAGE_SIZE;
+	unsigned int clen = PAGE_SIZE;
 	char *to_va;
-	unsigned size;
 	int ret;
+	struct zv_hdr *zv;
 
+	zv = zs_map_object(zcache_host.zspool, handle);
+	BUG_ON(zv->size == 0);
 	ASSERT_SENTINEL(zv, ZVH);
-	size = xv_get_object_size(zv) - sizeof(*zv);
-	BUG_ON(size == 0);
 	to_va = kmap_atomic(page, KM_USER0);
-	ret = lzo1x_decompress_safe((char *)zv + sizeof(*zv),
-					size, to_va, &clen);
+	ret = zcache_comp_op(ZCACHE_COMPOP_DECOMPRESS, (char *)zv + sizeof(*zv),
+				zv->size, to_va, &clen);
 	kunmap_atomic(to_va, KM_USER0);
-	BUG_ON(ret != LZO_E_OK);
+	zs_unmap_object(zcache_host.zspool, handle);
+	BUG_ON(ret);
 	BUG_ON(clen != PAGE_SIZE);
 }
 
@@ -948,8 +984,8 @@
 		goto out;
 	cli->allocated = 1;
 #ifdef CONFIG_FRONTSWAP
-	cli->xvpool = xv_create_pool();
-	if (cli->xvpool == NULL)
+	cli->zspool = zs_create_pool("zcache", ZCACHE_GFP_MASK);
+	if (cli->zspool == NULL)
 		goto out;
 #endif
 	ret = 0;
@@ -1132,14 +1168,14 @@
 static unsigned long zcache_curr_pers_pampd_count_max;
 
 /* forward reference */
-static int zcache_compress(struct page *from, void **out_va, size_t *out_len);
+static int zcache_compress(struct page *from, void **out_va, unsigned *out_len);
 
 static void *zcache_pampd_create(char *data, size_t size, bool raw, int eph,
 				struct tmem_pool *pool, struct tmem_oid *oid,
 				 uint32_t index)
 {
 	void *pampd = NULL, *cdata;
-	size_t clen;
+	unsigned clen;
 	int ret;
 	unsigned long count;
 	struct page *page = (struct page *)(data);
@@ -1180,7 +1216,7 @@
 		}
 		/* reject if mean compression is too poor */
 		if ((clen > zv_max_mean_zsize) && (curr_pers_pampd_count > 0)) {
-			total_zsize = xv_get_total_size_bytes(cli->xvpool);
+			total_zsize = zs_get_total_size_bytes(cli->zspool);
 			zv_mean_zsize = div_u64(total_zsize,
 						curr_pers_pampd_count);
 			if (zv_mean_zsize > zv_max_mean_zsize) {
@@ -1188,7 +1224,7 @@
 				goto out;
 			}
 		}
-		pampd = (void *)zv_create(cli->xvpool, pool->pool_id,
+		pampd = (void *)zv_create(cli->zspool, pool->pool_id,
 						oid, index, cdata, clen);
 		if (pampd == NULL)
 			goto out;
@@ -1246,7 +1282,7 @@
 		atomic_dec(&zcache_curr_eph_pampd_count);
 		BUG_ON(atomic_read(&zcache_curr_eph_pampd_count) < 0);
 	} else {
-		zv_free(cli->xvpool, (struct zv_hdr *)pampd);
+		zv_free(cli->zspool, pampd);
 		atomic_dec(&zcache_curr_pers_pampd_count);
 		BUG_ON(atomic_read(&zcache_curr_pers_pampd_count) < 0);
 	}
@@ -1285,25 +1321,24 @@
  * zcache compression/decompression and related per-cpu stuff
  */
 
-#define LZO_WORKMEM_BYTES LZO1X_1_MEM_COMPRESS
-#define LZO_DSTMEM_PAGE_ORDER 1
-static DEFINE_PER_CPU(unsigned char *, zcache_workmem);
 static DEFINE_PER_CPU(unsigned char *, zcache_dstmem);
+#define ZCACHE_DSTMEM_ORDER 1
 
-static int zcache_compress(struct page *from, void **out_va, size_t *out_len)
+static int zcache_compress(struct page *from, void **out_va, unsigned *out_len)
 {
 	int ret = 0;
 	unsigned char *dmem = __get_cpu_var(zcache_dstmem);
-	unsigned char *wmem = __get_cpu_var(zcache_workmem);
 	char *from_va;
 
 	BUG_ON(!irqs_disabled());
-	if (unlikely(dmem == NULL || wmem == NULL))
-		goto out;  /* no buffer, so can't compress */
+	if (unlikely(dmem == NULL))
+		goto out;  /* no buffer or no compressor so can't compress */
+	*out_len = PAGE_SIZE << ZCACHE_DSTMEM_ORDER;
 	from_va = kmap_atomic(from, KM_USER0);
 	mb();
-	ret = lzo1x_1_compress(from_va, PAGE_SIZE, dmem, out_len, wmem);
-	BUG_ON(ret != LZO_E_OK);
+	ret = zcache_comp_op(ZCACHE_COMPOP_COMPRESS, from_va, PAGE_SIZE, dmem,
+				out_len);
+	BUG_ON(ret);
 	*out_va = dmem;
 	kunmap_atomic(from_va, KM_USER0);
 	ret = 1;
@@ -1311,29 +1346,48 @@
 	return ret;
 }
 
+static int zcache_comp_cpu_up(int cpu)
+{
+	struct crypto_comp *tfm;
+
+	tfm = crypto_alloc_comp(zcache_comp_name, 0, 0);
+	if (IS_ERR(tfm))
+		return NOTIFY_BAD;
+	*per_cpu_ptr(zcache_comp_pcpu_tfms, cpu) = tfm;
+	return NOTIFY_OK;
+}
+
+static void zcache_comp_cpu_down(int cpu)
+{
+	struct crypto_comp *tfm;
+
+	tfm = *per_cpu_ptr(zcache_comp_pcpu_tfms, cpu);
+	crypto_free_comp(tfm);
+	*per_cpu_ptr(zcache_comp_pcpu_tfms, cpu) = NULL;
+}
 
 static int zcache_cpu_notifier(struct notifier_block *nb,
 				unsigned long action, void *pcpu)
 {
-	int cpu = (long)pcpu;
+	int ret, cpu = (long)pcpu;
 	struct zcache_preload *kp;
 
 	switch (action) {
 	case CPU_UP_PREPARE:
+		ret = zcache_comp_cpu_up(cpu);
+		if (ret != NOTIFY_OK) {
+			pr_err("zcache: can't allocate compressor transform\n");
+			return ret;
+		}
 		per_cpu(zcache_dstmem, cpu) = (void *)__get_free_pages(
-			GFP_KERNEL | __GFP_REPEAT,
-			LZO_DSTMEM_PAGE_ORDER),
-		per_cpu(zcache_workmem, cpu) =
-			kzalloc(LZO1X_MEM_COMPRESS,
-				GFP_KERNEL | __GFP_REPEAT);
+			GFP_KERNEL | __GFP_REPEAT, ZCACHE_DSTMEM_ORDER);
 		break;
 	case CPU_DEAD:
 	case CPU_UP_CANCELED:
+		zcache_comp_cpu_down(cpu);
 		free_pages((unsigned long)per_cpu(zcache_dstmem, cpu),
-				LZO_DSTMEM_PAGE_ORDER);
+			ZCACHE_DSTMEM_ORDER);
 		per_cpu(zcache_dstmem, cpu) = NULL;
-		kfree(per_cpu(zcache_workmem, cpu));
-		per_cpu(zcache_workmem, cpu) = NULL;
 		kp = &per_cpu(zcache_preloads, cpu);
 		while (kp->nr) {
 			kmem_cache_free(zcache_objnode_cache,
@@ -1918,6 +1972,44 @@
 
 __setup("nofrontswap", no_frontswap);
 
+static int __init enable_zcache_compressor(char *s)
+{
+	strncpy(zcache_comp_name, s, ZCACHE_COMP_NAME_SZ);
+	zcache_enabled = 1;
+	return 1;
+}
+__setup("zcache=", enable_zcache_compressor);
+
+
+static int zcache_comp_init(void)
+{
+	int ret = 0;
+
+	/* check crypto algorithm */
+	if (*zcache_comp_name != '\0') {
+		ret = crypto_has_comp(zcache_comp_name, 0, 0);
+		if (!ret)
+			pr_info("zcache: %s not supported\n",
+					zcache_comp_name);
+	}
+	if (!ret)
+		strcpy(zcache_comp_name, "lzo");
+	ret = crypto_has_comp(zcache_comp_name, 0, 0);
+	if (!ret) {
+		ret = 1;
+		goto out;
+	}
+	pr_info("zcache: using %s compressor\n", zcache_comp_name);
+
+	/* alloc percpu transforms */
+	ret = 0;
+	zcache_comp_pcpu_tfms = alloc_percpu(struct crypto_comp *);
+	if (!zcache_comp_pcpu_tfms)
+		ret = 1;
+out:
+	return ret;
+}
+
 static int __init zcache_init(void)
 {
 	int ret = 0;
@@ -1940,6 +2032,11 @@
 			pr_err("zcache: can't register cpu notifier\n");
 			goto out;
 		}
+		ret = zcache_comp_init();
+		if (ret) {
+			pr_err("zcache: compressor initialization failed\n");
+			goto out;
+		}
 		for_each_online_cpu(cpu) {
 			void *pcpu = (void *)(long)cpu;
 			zcache_cpu_notifier(&zcache_cpu_notifier_block,
@@ -1975,7 +2072,7 @@
 
 		old_ops = zcache_frontswap_register_ops();
 		pr_info("zcache: frontswap enabled using kernel "
-			"transcendent memory and xvmalloc\n");
+			"transcendent memory and zsmalloc\n");
 		if (old_ops.init != NULL)
 			pr_warning("zcache: frontswap_ops overridden");
 	}
diff --git a/drivers/staging/zram/Kconfig b/drivers/staging/zram/Kconfig
index 3bec4db..9d11a4c 100644
--- a/drivers/staging/zram/Kconfig
+++ b/drivers/staging/zram/Kconfig
@@ -1,11 +1,9 @@
-config XVMALLOC
-	bool
-	default n
-
 config ZRAM
 	tristate "Compressed RAM block device support"
-	depends on BLOCK && SYSFS
-	select XVMALLOC
+	# X86 dependency is because zsmalloc uses non-portable pte/tlb
+	# functions
+	depends on BLOCK && SYSFS && X86
+	select ZSMALLOC
 	select LZO_COMPRESS
 	select LZO_DECOMPRESS
 	default n
diff --git a/drivers/staging/zram/Makefile b/drivers/staging/zram/Makefile
index 2a6d321..7f4a301 100644
--- a/drivers/staging/zram/Makefile
+++ b/drivers/staging/zram/Makefile
@@ -1,4 +1,3 @@
 zram-y	:=	zram_drv.o zram_sysfs.o
 
 obj-$(CONFIG_ZRAM)	+=	zram.o
-obj-$(CONFIG_XVMALLOC)	+=	xvmalloc.o
\ No newline at end of file
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index 2a2a92d..7f13819 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -40,7 +40,7 @@
 struct zram *zram_devices;
 
 /* Module params (documentation at end) */
-unsigned int zram_num_devices;
+static unsigned int num_devices;
 
 static void zram_stat_inc(u32 *v)
 {
@@ -135,13 +135,9 @@
 
 static void zram_free_page(struct zram *zram, size_t index)
 {
-	u32 clen;
-	void *obj;
+	void *handle = zram->table[index].handle;
 
-	struct page *page = zram->table[index].page;
-	u32 offset = zram->table[index].offset;
-
-	if (unlikely(!page)) {
+	if (unlikely(!handle)) {
 		/*
 		 * No memory is allocated for zero filled pages.
 		 * Simply clear zero page flag.
@@ -154,27 +150,24 @@
 	}
 
 	if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
-		clen = PAGE_SIZE;
-		__free_page(page);
+		__free_page(handle);
 		zram_clear_flag(zram, index, ZRAM_UNCOMPRESSED);
 		zram_stat_dec(&zram->stats.pages_expand);
 		goto out;
 	}
 
-	obj = kmap_atomic(page, KM_USER0) + offset;
-	clen = xv_get_object_size(obj) - sizeof(struct zobj_header);
-	kunmap_atomic(obj, KM_USER0);
+	zs_free(zram->mem_pool, handle);
 
-	xv_free(zram->mem_pool, page, offset);
-	if (clen <= PAGE_SIZE / 2)
+	if (zram->table[index].size <= PAGE_SIZE / 2)
 		zram_stat_dec(&zram->stats.good_compress);
 
 out:
-	zram_stat64_sub(zram, &zram->stats.compr_size, clen);
+	zram_stat64_sub(zram, &zram->stats.compr_size,
+			zram->table[index].size);
 	zram_stat_dec(&zram->stats.pages_stored);
 
-	zram->table[index].page = NULL;
-	zram->table[index].offset = 0;
+	zram->table[index].handle = NULL;
+	zram->table[index].size = 0;
 }
 
 static void handle_zero_page(struct bio_vec *bvec)
@@ -196,7 +189,7 @@
 	unsigned char *user_mem, *cmem;
 
 	user_mem = kmap_atomic(page, KM_USER0);
-	cmem = kmap_atomic(zram->table[index].page, KM_USER1);
+	cmem = kmap_atomic(zram->table[index].handle, KM_USER1);
 
 	memcpy(user_mem + bvec->bv_offset, cmem + offset, bvec->bv_len);
 	kunmap_atomic(cmem, KM_USER1);
@@ -227,7 +220,7 @@
 	}
 
 	/* Requested page is not present in compressed area */
-	if (unlikely(!zram->table[index].page)) {
+	if (unlikely(!zram->table[index].handle)) {
 		pr_debug("Read before write: sector=%lu, size=%u",
 			 (ulong)(bio->bi_sector), bio->bi_size);
 		handle_zero_page(bvec);
@@ -254,11 +247,10 @@
 		uncmem = user_mem;
 	clen = PAGE_SIZE;
 
-	cmem = kmap_atomic(zram->table[index].page, KM_USER1) +
-		zram->table[index].offset;
+	cmem = zs_map_object(zram->mem_pool, zram->table[index].handle);
 
 	ret = lzo1x_decompress_safe(cmem + sizeof(*zheader),
-				    xv_get_object_size(cmem) - sizeof(*zheader),
+				    zram->table[index].size,
 				    uncmem, &clen);
 
 	if (is_partial_io(bvec)) {
@@ -267,7 +259,7 @@
 		kfree(uncmem);
 	}
 
-	kunmap_atomic(cmem, KM_USER1);
+	zs_unmap_object(zram->mem_pool, zram->table[index].handle);
 	kunmap_atomic(user_mem, KM_USER0);
 
 	/* Should NEVER happen. Return bio error if it does. */
@@ -290,13 +282,12 @@
 	unsigned char *cmem;
 
 	if (zram_test_flag(zram, index, ZRAM_ZERO) ||
-	    !zram->table[index].page) {
+	    !zram->table[index].handle) {
 		memset(mem, 0, PAGE_SIZE);
 		return 0;
 	}
 
-	cmem = kmap_atomic(zram->table[index].page, KM_USER0) +
-		zram->table[index].offset;
+	cmem = zs_map_object(zram->mem_pool, zram->table[index].handle);
 
 	/* Page is stored uncompressed since it's incompressible */
 	if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
@@ -306,9 +297,9 @@
 	}
 
 	ret = lzo1x_decompress_safe(cmem + sizeof(*zheader),
-				    xv_get_object_size(cmem) - sizeof(*zheader),
+				    zram->table[index].size,
 				    mem, &clen);
-	kunmap_atomic(cmem, KM_USER0);
+	zs_unmap_object(zram->mem_pool, zram->table[index].handle);
 
 	/* Should NEVER happen. Return bio error if it does. */
 	if (unlikely(ret != LZO_E_OK)) {
@@ -326,6 +317,7 @@
 	int ret;
 	u32 store_offset;
 	size_t clen;
+	void *handle;
 	struct zobj_header *zheader;
 	struct page *page, *page_store;
 	unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
@@ -355,7 +347,7 @@
 	 * System overwrites unused sectors. Free memory associated
 	 * with this sector now.
 	 */
-	if (zram->table[index].page ||
+	if (zram->table[index].handle ||
 	    zram_test_flag(zram, index, ZRAM_ZERO))
 		zram_free_page(zram, index);
 
@@ -407,26 +399,22 @@
 		store_offset = 0;
 		zram_set_flag(zram, index, ZRAM_UNCOMPRESSED);
 		zram_stat_inc(&zram->stats.pages_expand);
-		zram->table[index].page = page_store;
+		handle = page_store;
 		src = kmap_atomic(page, KM_USER0);
+		cmem = kmap_atomic(page_store, KM_USER1);
 		goto memstore;
 	}
 
-	if (xv_malloc(zram->mem_pool, clen + sizeof(*zheader),
-		      &zram->table[index].page, &store_offset,
-		      GFP_NOIO | __GFP_HIGHMEM)) {
+	handle = zs_malloc(zram->mem_pool, clen + sizeof(*zheader));
+	if (!handle) {
 		pr_info("Error allocating memory for compressed "
 			"page: %u, size=%zu\n", index, clen);
 		ret = -ENOMEM;
 		goto out;
 	}
+	cmem = zs_map_object(zram->mem_pool, handle);
 
 memstore:
-	zram->table[index].offset = store_offset;
-
-	cmem = kmap_atomic(zram->table[index].page, KM_USER1) +
-		zram->table[index].offset;
-
 #if 0
 	/* Back-reference needed for memory defragmentation */
 	if (!zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)) {
@@ -438,9 +426,15 @@
 
 	memcpy(cmem, src, clen);
 
-	kunmap_atomic(cmem, KM_USER1);
-	if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)))
+	if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
+		kunmap_atomic(cmem, KM_USER1);
 		kunmap_atomic(src, KM_USER0);
+	} else {
+		zs_unmap_object(zram->mem_pool, handle);
+	}
+
+	zram->table[index].handle = handle;
+	zram->table[index].size = clen;
 
 	/* Update stats */
 	zram_stat64_add(zram, &zram->stats.compr_size, clen);
@@ -598,25 +592,20 @@
 
 	/* Free all pages that are still in this zram device */
 	for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) {
-		struct page *page;
-		u16 offset;
-
-		page = zram->table[index].page;
-		offset = zram->table[index].offset;
-
-		if (!page)
+		void *handle = zram->table[index].handle;
+		if (!handle)
 			continue;
 
 		if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)))
-			__free_page(page);
+			__free_page(handle);
 		else
-			xv_free(zram->mem_pool, page, offset);
+			zs_free(zram->mem_pool, handle);
 	}
 
 	vfree(zram->table);
 	zram->table = NULL;
 
-	xv_destroy_pool(zram->mem_pool);
+	zs_destroy_pool(zram->mem_pool);
 	zram->mem_pool = NULL;
 
 	/* Reset stats */
@@ -674,7 +663,7 @@
 	/* zram devices sort of resembles non-rotational disks */
 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue);
 
-	zram->mem_pool = xv_create_pool();
+	zram->mem_pool = zs_create_pool("zram", GFP_NOIO | __GFP_HIGHMEM);
 	if (!zram->mem_pool) {
 		pr_err("Error creating memory pool\n");
 		ret = -ENOMEM;
@@ -790,13 +779,18 @@
 		blk_cleanup_queue(zram->queue);
 }
 
+unsigned int zram_get_num_devices(void)
+{
+	return num_devices;
+}
+
 static int __init zram_init(void)
 {
 	int ret, dev_id;
 
-	if (zram_num_devices > max_num_devices) {
+	if (num_devices > max_num_devices) {
 		pr_warning("Invalid value for num_devices: %u\n",
-				zram_num_devices);
+				num_devices);
 		ret = -EINVAL;
 		goto out;
 	}
@@ -808,20 +802,20 @@
 		goto out;
 	}
 
-	if (!zram_num_devices) {
+	if (!num_devices) {
 		pr_info("num_devices not specified. Using default: 1\n");
-		zram_num_devices = 1;
+		num_devices = 1;
 	}
 
 	/* Allocate the device array and initialize each one */
-	pr_info("Creating %u devices ...\n", zram_num_devices);
-	zram_devices = kzalloc(zram_num_devices * sizeof(struct zram), GFP_KERNEL);
+	pr_info("Creating %u devices ...\n", num_devices);
+	zram_devices = kzalloc(num_devices * sizeof(struct zram), GFP_KERNEL);
 	if (!zram_devices) {
 		ret = -ENOMEM;
 		goto unregister;
 	}
 
-	for (dev_id = 0; dev_id < zram_num_devices; dev_id++) {
+	for (dev_id = 0; dev_id < num_devices; dev_id++) {
 		ret = create_device(&zram_devices[dev_id], dev_id);
 		if (ret)
 			goto free_devices;
@@ -844,7 +838,7 @@
 	int i;
 	struct zram *zram;
 
-	for (i = 0; i < zram_num_devices; i++) {
+	for (i = 0; i < num_devices; i++) {
 		zram = &zram_devices[i];
 
 		destroy_device(zram);
@@ -858,8 +852,8 @@
 	pr_debug("Cleanup done!\n");
 }
 
-module_param(zram_num_devices, uint, 0);
-MODULE_PARM_DESC(zram_num_devices, "Number of zram devices");
+module_param(num_devices, uint, 0);
+MODULE_PARM_DESC(num_devices, "Number of zram devices");
 
 module_init(zram_init);
 module_exit(zram_exit);
diff --git a/drivers/staging/zram/zram_drv.h b/drivers/staging/zram/zram_drv.h
index e5cd246..fbe8ac9 100644
--- a/drivers/staging/zram/zram_drv.h
+++ b/drivers/staging/zram/zram_drv.h
@@ -18,7 +18,7 @@
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
 
-#include "xvmalloc.h"
+#include "../zsmalloc/zsmalloc.h"
 
 /*
  * Some arbitrary value. This is just to catch
@@ -51,7 +51,7 @@
 
 /*
  * NOTE: max_zpage_size must be less than or equal to:
- *   XV_MAX_ALLOC_SIZE - sizeof(struct zobj_header)
+ *   ZS_MAX_ALLOC_SIZE - sizeof(struct zobj_header)
  * otherwise, xv_malloc() would always return failure.
  */
 
@@ -81,8 +81,8 @@
 
 /* Allocated for each disk page */
 struct table {
-	struct page *page;
-	u16 offset;
+	void *handle;
+	u16 size;	/* object size (excluding header) */
 	u8 count;	/* object ref count (not yet used) */
 	u8 flags;
 } __attribute__((aligned(4)));
@@ -102,7 +102,7 @@
 };
 
 struct zram {
-	struct xv_pool *mem_pool;
+	struct zs_pool *mem_pool;
 	void *compress_workmem;
 	void *compress_buffer;
 	struct table *table;
@@ -124,7 +124,7 @@
 };
 
 extern struct zram *zram_devices;
-extern unsigned int zram_num_devices;
+unsigned int zram_get_num_devices(void);
 #ifdef CONFIG_SYSFS
 extern struct attribute_group zram_disk_attr_group;
 #endif
diff --git a/drivers/staging/zram/zram_sysfs.c b/drivers/staging/zram/zram_sysfs.c
index d521122..a7f3771 100644
--- a/drivers/staging/zram/zram_sysfs.c
+++ b/drivers/staging/zram/zram_sysfs.c
@@ -34,7 +34,7 @@
 	int i;
 	struct zram *zram = NULL;
 
-	for (i = 0; i < zram_num_devices; i++) {
+	for (i = 0; i < zram_get_num_devices(); i++) {
 		zram = &zram_devices[i];
 		if (disk_to_dev(zram->disk) == dev)
 			break;
@@ -187,7 +187,7 @@
 	struct zram *zram = dev_to_zram(dev);
 
 	if (zram->init_done) {
-		val = xv_get_total_size_bytes(zram->mem_pool) +
+		val = zs_get_total_size_bytes(zram->mem_pool) +
 			((u64)(zram->stats.pages_expand) << PAGE_SHIFT);
 	}
 
diff --git a/drivers/staging/zsmalloc/Kconfig b/drivers/staging/zsmalloc/Kconfig
new file mode 100644
index 0000000..a5ab720
--- /dev/null
+++ b/drivers/staging/zsmalloc/Kconfig
@@ -0,0 +1,14 @@
+config ZSMALLOC
+	tristate "Memory allocator for compressed pages"
+	# X86 dependency is because of the use of __flush_tlb_one and set_pte
+	# in zsmalloc-main.c.
+	# TODO: convert these to portable functions
+	depends on X86
+	default n
+	help
+	  zsmalloc is a slab-based memory allocator designed to store
+	  compressed RAM pages.  zsmalloc uses virtual memory mapping
+	  in order to reduce fragmentation.  However, this results in a
+	  non-standard allocator interface where a handle, not a pointer, is
+	  returned by an alloc().  This handle must be mapped in order to
+	  access the allocated space.
diff --git a/drivers/staging/zsmalloc/Makefile b/drivers/staging/zsmalloc/Makefile
new file mode 100644
index 0000000..b134848
--- /dev/null
+++ b/drivers/staging/zsmalloc/Makefile
@@ -0,0 +1,3 @@
+zsmalloc-y 		:= zsmalloc-main.o
+
+obj-$(CONFIG_ZSMALLOC)	+= zsmalloc.o
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c
new file mode 100644
index 0000000..09caa4f
--- /dev/null
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -0,0 +1,745 @@
+/*
+ * zsmalloc memory allocator
+ *
+ * Copyright (C) 2011  Nitin Gupta
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the license that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ */
+
+#ifdef CONFIG_ZSMALLOC_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/highmem.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <asm/tlbflush.h>
+#include <asm/pgtable.h>
+#include <linux/cpumask.h>
+#include <linux/cpu.h>
+#include <linux/vmalloc.h>
+
+#include "zsmalloc.h"
+#include "zsmalloc_int.h"
+
+/*
+ * A zspage's class index and fullness group
+ * are encoded in its (first)page->mapping
+ */
+#define CLASS_IDX_BITS	28
+#define FULLNESS_BITS	4
+#define CLASS_IDX_MASK	((1 << CLASS_IDX_BITS) - 1)
+#define FULLNESS_MASK	((1 << FULLNESS_BITS) - 1)
+
+/* per-cpu VM mapping areas for zspage accesses that cross page boundaries */
+static DEFINE_PER_CPU(struct mapping_area, zs_map_area);
+
+static int is_first_page(struct page *page)
+{
+	return test_bit(PG_private, &page->flags);
+}
+
+static int is_last_page(struct page *page)
+{
+	return test_bit(PG_private_2, &page->flags);
+}
+
+static void get_zspage_mapping(struct page *page, unsigned int *class_idx,
+				enum fullness_group *fullness)
+{
+	unsigned long m;
+	BUG_ON(!is_first_page(page));
+
+	m = (unsigned long)page->mapping;
+	*fullness = m & FULLNESS_MASK;
+	*class_idx = (m >> FULLNESS_BITS) & CLASS_IDX_MASK;
+}
+
+static void set_zspage_mapping(struct page *page, unsigned int class_idx,
+				enum fullness_group fullness)
+{
+	unsigned long m;
+	BUG_ON(!is_first_page(page));
+
+	m = ((class_idx & CLASS_IDX_MASK) << FULLNESS_BITS) |
+			(fullness & FULLNESS_MASK);
+	page->mapping = (struct address_space *)m;
+}
+
+static int get_size_class_index(int size)
+{
+	int idx = 0;
+
+	if (likely(size > ZS_MIN_ALLOC_SIZE))
+		idx = DIV_ROUND_UP(size - ZS_MIN_ALLOC_SIZE,
+				ZS_SIZE_CLASS_DELTA);
+
+	return idx;
+}
+
+static enum fullness_group get_fullness_group(struct page *page)
+{
+	int inuse, max_objects;
+	enum fullness_group fg;
+	BUG_ON(!is_first_page(page));
+
+	inuse = page->inuse;
+	max_objects = page->objects;
+
+	if (inuse == 0)
+		fg = ZS_EMPTY;
+	else if (inuse == max_objects)
+		fg = ZS_FULL;
+	else if (inuse <= max_objects / fullness_threshold_frac)
+		fg = ZS_ALMOST_EMPTY;
+	else
+		fg = ZS_ALMOST_FULL;
+
+	return fg;
+}
+
+static void insert_zspage(struct page *page, struct size_class *class,
+				enum fullness_group fullness)
+{
+	struct page **head;
+
+	BUG_ON(!is_first_page(page));
+
+	if (fullness >= _ZS_NR_FULLNESS_GROUPS)
+		return;
+
+	head = &class->fullness_list[fullness];
+	if (*head)
+		list_add_tail(&page->lru, &(*head)->lru);
+
+	*head = page;
+}
+
+static void remove_zspage(struct page *page, struct size_class *class,
+				enum fullness_group fullness)
+{
+	struct page **head;
+
+	BUG_ON(!is_first_page(page));
+
+	if (fullness >= _ZS_NR_FULLNESS_GROUPS)
+		return;
+
+	head = &class->fullness_list[fullness];
+	BUG_ON(!*head);
+	if (list_empty(&(*head)->lru))
+		*head = NULL;
+	else if (*head == page)
+		*head = (struct page *)list_entry((*head)->lru.next,
+					struct page, lru);
+
+	list_del_init(&page->lru);
+}
+
+static enum fullness_group fix_fullness_group(struct zs_pool *pool,
+						struct page *page)
+{
+	int class_idx;
+	struct size_class *class;
+	enum fullness_group currfg, newfg;
+
+	BUG_ON(!is_first_page(page));
+
+	get_zspage_mapping(page, &class_idx, &currfg);
+	newfg = get_fullness_group(page);
+	if (newfg == currfg)
+		goto out;
+
+	class = &pool->size_class[class_idx];
+	remove_zspage(page, class, currfg);
+	insert_zspage(page, class, newfg);
+	set_zspage_mapping(page, class_idx, newfg);
+
+out:
+	return newfg;
+}
+
+/*
+ * We have to decide on how many pages to link together
+ * to form a zspage for each size class. This is important
+ * to reduce wastage due to unusable space left at end of
+ * each zspage which is given as:
+ *	wastage = Zp - Zp % size_class
+ * where Zp = zspage size = k * PAGE_SIZE where k = 1, 2, ...
+ *
+ * For example, for size class of 3/8 * PAGE_SIZE, we should
+ * link together 3 PAGE_SIZE sized pages to form a zspage
+ * since then we can perfectly fit in 8 such objects.
+ */
+static int get_zspage_order(int class_size)
+{
+	int i, max_usedpc = 0;
+	/* zspage order which gives maximum used size per KB */
+	int max_usedpc_order = 1;
+
+	for (i = 1; i <= ZS_MAX_PAGES_PER_ZSPAGE; i++) {
+		int zspage_size;
+		int waste, usedpc;
+
+		zspage_size = i * PAGE_SIZE;
+		waste = zspage_size % class_size;
+		usedpc = (zspage_size - waste) * 100 / zspage_size;
+
+		if (usedpc > max_usedpc) {
+			max_usedpc = usedpc;
+			max_usedpc_order = i;
+		}
+	}
+
+	return max_usedpc_order;
+}
+
+/*
+ * A single 'zspage' is composed of many system pages which are
+ * linked together using fields in struct page. This function finds
+ * the first/head page, given any component page of a zspage.
+ */
+static struct page *get_first_page(struct page *page)
+{
+	if (is_first_page(page))
+		return page;
+	else
+		return page->first_page;
+}
+
+static struct page *get_next_page(struct page *page)
+{
+	struct page *next;
+
+	if (is_last_page(page))
+		next = NULL;
+	else if (is_first_page(page))
+		next = (struct page *)page->private;
+	else
+		next = list_entry(page->lru.next, struct page, lru);
+
+	return next;
+}
+
+/* Encode <page, obj_idx> as a single handle value */
+static void *obj_location_to_handle(struct page *page, unsigned long obj_idx)
+{
+	unsigned long handle;
+
+	if (!page) {
+		BUG_ON(obj_idx);
+		return NULL;
+	}
+
+	handle = page_to_pfn(page) << OBJ_INDEX_BITS;
+	handle |= (obj_idx & OBJ_INDEX_MASK);
+
+	return (void *)handle;
+}
+
+/* Decode <page, obj_idx> pair from the given object handle */
+static void obj_handle_to_location(void *handle, struct page **page,
+				unsigned long *obj_idx)
+{
+	unsigned long hval = (unsigned long)handle;
+
+	*page = pfn_to_page(hval >> OBJ_INDEX_BITS);
+	*obj_idx = hval & OBJ_INDEX_MASK;
+}
+
+static unsigned long obj_idx_to_offset(struct page *page,
+				unsigned long obj_idx, int class_size)
+{
+	unsigned long off = 0;
+
+	if (!is_first_page(page))
+		off = page->index;
+
+	return off + obj_idx * class_size;
+}
+
+static void free_zspage(struct page *first_page)
+{
+	struct page *nextp, *tmp;
+
+	BUG_ON(!is_first_page(first_page));
+	BUG_ON(first_page->inuse);
+
+	nextp = (struct page *)page_private(first_page);
+
+	clear_bit(PG_private, &first_page->flags);
+	clear_bit(PG_private_2, &first_page->flags);
+	set_page_private(first_page, 0);
+	first_page->mapping = NULL;
+	first_page->freelist = NULL;
+	reset_page_mapcount(first_page);
+	__free_page(first_page);
+
+	/* zspage with only 1 system page */
+	if (!nextp)
+		return;
+
+	list_for_each_entry_safe(nextp, tmp, &nextp->lru, lru) {
+		list_del(&nextp->lru);
+		clear_bit(PG_private_2, &nextp->flags);
+		nextp->index = 0;
+		__free_page(nextp);
+	}
+}
+
+/* Initialize a newly allocated zspage */
+static void init_zspage(struct page *first_page, struct size_class *class)
+{
+	unsigned long off = 0;
+	struct page *page = first_page;
+
+	BUG_ON(!is_first_page(first_page));
+	while (page) {
+		struct page *next_page;
+		struct link_free *link;
+		unsigned int i, objs_on_page;
+
+		/*
+		 * page->index stores offset of first object starting
+		 * in the page. For the first page, this is always 0,
+		 * so we use first_page->index (aka ->freelist) to store
+		 * head of corresponding zspage's freelist.
+		 */
+		if (page != first_page)
+			page->index = off;
+
+		link = (struct link_free *)kmap_atomic(page) +
+						off / sizeof(*link);
+		objs_on_page = (PAGE_SIZE - off) / class->size;
+
+		for (i = 1; i <= objs_on_page; i++) {
+			off += class->size;
+			if (off < PAGE_SIZE) {
+				link->next = obj_location_to_handle(page, i);
+				link += class->size / sizeof(*link);
+			}
+		}
+
+		/*
+		 * We now come to the last (full or partial) object on this
+		 * page, which must point to the first object on the next
+		 * page (if present)
+		 */
+		next_page = get_next_page(page);
+		link->next = obj_location_to_handle(next_page, 0);
+		kunmap_atomic(link);
+		page = next_page;
+		off = (off + class->size) % PAGE_SIZE;
+	}
+}
+
+/*
+ * Allocate a zspage for the given size class
+ */
+static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
+{
+	int i, error;
+	struct page *first_page = NULL;
+
+	/*
+	 * Allocate individual pages and link them together as:
+	 * 1. first page->private = first sub-page
+	 * 2. all sub-pages are linked together using page->lru
+	 * 3. each sub-page is linked to the first page using page->first_page
+	 *
+	 * For each size class, First/Head pages are linked together using
+	 * page->lru. Also, we set PG_private to identify the first page
+	 * (i.e. no other sub-page has this flag set) and PG_private_2 to
+	 * identify the last page.
+	 */
+	error = -ENOMEM;
+	for (i = 0; i < class->zspage_order; i++) {
+		struct page *page, *prev_page;
+
+		page = alloc_page(flags);
+		if (!page)
+			goto cleanup;
+
+		INIT_LIST_HEAD(&page->lru);
+		if (i == 0) {	/* first page */
+			set_bit(PG_private, &page->flags);
+			set_page_private(page, 0);
+			first_page = page;
+			first_page->inuse = 0;
+		}
+		if (i == 1)
+			first_page->private = (unsigned long)page;
+		if (i >= 1)
+			page->first_page = first_page;
+		if (i >= 2)
+			list_add(&page->lru, &prev_page->lru);
+		if (i == class->zspage_order - 1)	/* last page */
+			set_bit(PG_private_2, &page->flags);
+
+		prev_page = page;
+	}
+
+	init_zspage(first_page, class);
+
+	first_page->freelist = obj_location_to_handle(first_page, 0);
+	/* Maximum number of objects we can store in this zspage */
+	first_page->objects = class->zspage_order * PAGE_SIZE / class->size;
+
+	error = 0; /* Success */
+
+cleanup:
+	if (unlikely(error) && first_page) {
+		free_zspage(first_page);
+		first_page = NULL;
+	}
+
+	return first_page;
+}
+
+static struct page *find_get_zspage(struct size_class *class)
+{
+	int i;
+	struct page *page;
+
+	for (i = 0; i < _ZS_NR_FULLNESS_GROUPS; i++) {
+		page = class->fullness_list[i];
+		if (page)
+			break;
+	}
+
+	return page;
+}
+
+
+/*
+ * If this becomes a separate module, register zs_init() with
+ * module_init(), zs_exit with module_exit(), and remove zs_initialized
+*/
+static int zs_initialized;
+
+static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action,
+				void *pcpu)
+{
+	int cpu = (long)pcpu;
+	struct mapping_area *area;
+
+	switch (action) {
+	case CPU_UP_PREPARE:
+		area = &per_cpu(zs_map_area, cpu);
+		if (area->vm)
+			break;
+		area->vm = alloc_vm_area(2 * PAGE_SIZE, area->vm_ptes);
+		if (!area->vm)
+			return notifier_from_errno(-ENOMEM);
+		break;
+	case CPU_DEAD:
+	case CPU_UP_CANCELED:
+		area = &per_cpu(zs_map_area, cpu);
+		if (area->vm)
+			free_vm_area(area->vm);
+		area->vm = NULL;
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block zs_cpu_nb = {
+	.notifier_call = zs_cpu_notifier
+};
+
+static void zs_exit(void)
+{
+	int cpu;
+
+	for_each_online_cpu(cpu)
+		zs_cpu_notifier(NULL, CPU_DEAD, (void *)(long)cpu);
+	unregister_cpu_notifier(&zs_cpu_nb);
+}
+
+static int zs_init(void)
+{
+	int cpu, ret;
+
+	register_cpu_notifier(&zs_cpu_nb);
+	for_each_online_cpu(cpu) {
+		ret = zs_cpu_notifier(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
+		if (notifier_to_errno(ret))
+			goto fail;
+	}
+	return 0;
+fail:
+	zs_exit();
+	return notifier_to_errno(ret);
+}
+
+struct zs_pool *zs_create_pool(const char *name, gfp_t flags)
+{
+	int i, error, ovhd_size;
+	struct zs_pool *pool;
+
+	if (!name)
+		return NULL;
+
+	ovhd_size = roundup(sizeof(*pool), PAGE_SIZE);
+	pool = kzalloc(ovhd_size, GFP_KERNEL);
+	if (!pool)
+		return NULL;
+
+	for (i = 0; i < ZS_SIZE_CLASSES; i++) {
+		int size;
+		struct size_class *class;
+
+		size = ZS_MIN_ALLOC_SIZE + i * ZS_SIZE_CLASS_DELTA;
+		if (size > ZS_MAX_ALLOC_SIZE)
+			size = ZS_MAX_ALLOC_SIZE;
+
+		class = &pool->size_class[i];
+		class->size = size;
+		class->index = i;
+		spin_lock_init(&class->lock);
+		class->zspage_order = get_zspage_order(size);
+
+	}
+
+	/*
+	 * If this becomes a separate module, register zs_init with
+	 * module_init, and remove this block
+	*/
+	if (!zs_initialized) {
+		error = zs_init();
+		if (error)
+			goto cleanup;
+		zs_initialized = 1;
+	}
+
+	pool->flags = flags;
+	pool->name = name;
+
+	error = 0; /* Success */
+
+cleanup:
+	if (error) {
+		zs_destroy_pool(pool);
+		pool = NULL;
+	}
+
+	return pool;
+}
+EXPORT_SYMBOL_GPL(zs_create_pool);
+
+void zs_destroy_pool(struct zs_pool *pool)
+{
+	int i;
+
+	for (i = 0; i < ZS_SIZE_CLASSES; i++) {
+		int fg;
+		struct size_class *class = &pool->size_class[i];
+
+		for (fg = 0; fg < _ZS_NR_FULLNESS_GROUPS; fg++) {
+			if (class->fullness_list[fg]) {
+				pr_info("Freeing non-empty class with size "
+					"%db, fullness group %d\n",
+					class->size, fg);
+			}
+		}
+	}
+	kfree(pool);
+}
+EXPORT_SYMBOL_GPL(zs_destroy_pool);
+
+/**
+ * zs_malloc - Allocate block of given size from pool.
+ * @pool: pool to allocate from
+ * @size: size of block to allocate
+ * @page: page no. that holds the object
+ * @offset: location of object within page
+ *
+ * On success, <page, offset> identifies block allocated
+ * and 0 is returned. On failure, <page, offset> is set to
+ * 0 and -ENOMEM is returned.
+ *
+ * Allocation requests with size > ZS_MAX_ALLOC_SIZE will fail.
+ */
+void *zs_malloc(struct zs_pool *pool, size_t size)
+{
+	void *obj;
+	struct link_free *link;
+	int class_idx;
+	struct size_class *class;
+
+	struct page *first_page, *m_page;
+	unsigned long m_objidx, m_offset;
+
+	if (unlikely(!size || size > ZS_MAX_ALLOC_SIZE))
+		return NULL;
+
+	class_idx = get_size_class_index(size);
+	class = &pool->size_class[class_idx];
+	BUG_ON(class_idx != class->index);
+
+	spin_lock(&class->lock);
+	first_page = find_get_zspage(class);
+
+	if (!first_page) {
+		spin_unlock(&class->lock);
+		first_page = alloc_zspage(class, pool->flags);
+		if (unlikely(!first_page))
+			return NULL;
+
+		set_zspage_mapping(first_page, class->index, ZS_EMPTY);
+		spin_lock(&class->lock);
+		class->pages_allocated += class->zspage_order;
+	}
+
+	obj = first_page->freelist;
+	obj_handle_to_location(obj, &m_page, &m_objidx);
+	m_offset = obj_idx_to_offset(m_page, m_objidx, class->size);
+
+	link = (struct link_free *)kmap_atomic(m_page) +
+					m_offset / sizeof(*link);
+	first_page->freelist = link->next;
+	memset(link, POISON_INUSE, sizeof(*link));
+	kunmap_atomic(link);
+
+	first_page->inuse++;
+	/* Now move the zspage to another fullness group, if required */
+	fix_fullness_group(pool, first_page);
+	spin_unlock(&class->lock);
+
+	return obj;
+}
+EXPORT_SYMBOL_GPL(zs_malloc);
+
+void zs_free(struct zs_pool *pool, void *obj)
+{
+	struct link_free *link;
+	struct page *first_page, *f_page;
+	unsigned long f_objidx, f_offset;
+
+	int class_idx;
+	struct size_class *class;
+	enum fullness_group fullness;
+
+	if (unlikely(!obj))
+		return;
+
+	obj_handle_to_location(obj, &f_page, &f_objidx);
+	first_page = get_first_page(f_page);
+
+	get_zspage_mapping(first_page, &class_idx, &fullness);
+	class = &pool->size_class[class_idx];
+	f_offset = obj_idx_to_offset(f_page, f_objidx, class->size);
+
+	spin_lock(&class->lock);
+
+	/* Insert this object in containing zspage's freelist */
+	link = (struct link_free *)((unsigned char *)kmap_atomic(f_page)
+							+ f_offset);
+	link->next = first_page->freelist;
+	kunmap_atomic(link);
+	first_page->freelist = obj;
+
+	first_page->inuse--;
+	fullness = fix_fullness_group(pool, first_page);
+
+	if (fullness == ZS_EMPTY)
+		class->pages_allocated -= class->zspage_order;
+
+	spin_unlock(&class->lock);
+
+	if (fullness == ZS_EMPTY)
+		free_zspage(first_page);
+}
+EXPORT_SYMBOL_GPL(zs_free);
+
+void *zs_map_object(struct zs_pool *pool, void *handle)
+{
+	struct page *page;
+	unsigned long obj_idx, off;
+
+	unsigned int class_idx;
+	enum fullness_group fg;
+	struct size_class *class;
+	struct mapping_area *area;
+
+	BUG_ON(!handle);
+
+	obj_handle_to_location(handle, &page, &obj_idx);
+	get_zspage_mapping(get_first_page(page), &class_idx, &fg);
+	class = &pool->size_class[class_idx];
+	off = obj_idx_to_offset(page, obj_idx, class->size);
+
+	area = &get_cpu_var(zs_map_area);
+	if (off + class->size <= PAGE_SIZE) {
+		/* this object is contained entirely within a page */
+		area->vm_addr = kmap_atomic(page);
+	} else {
+		/* this object spans two pages */
+		struct page *nextp;
+
+		nextp = get_next_page(page);
+		BUG_ON(!nextp);
+
+
+		set_pte(area->vm_ptes[0], mk_pte(page, PAGE_KERNEL));
+		set_pte(area->vm_ptes[1], mk_pte(nextp, PAGE_KERNEL));
+
+		/* We pre-allocated VM area so mapping can never fail */
+		area->vm_addr = area->vm->addr;
+	}
+
+	return area->vm_addr + off;
+}
+EXPORT_SYMBOL_GPL(zs_map_object);
+
+void zs_unmap_object(struct zs_pool *pool, void *handle)
+{
+	struct page *page;
+	unsigned long obj_idx, off;
+
+	unsigned int class_idx;
+	enum fullness_group fg;
+	struct size_class *class;
+	struct mapping_area *area;
+
+	BUG_ON(!handle);
+
+	obj_handle_to_location(handle, &page, &obj_idx);
+	get_zspage_mapping(get_first_page(page), &class_idx, &fg);
+	class = &pool->size_class[class_idx];
+	off = obj_idx_to_offset(page, obj_idx, class->size);
+
+	area = &__get_cpu_var(zs_map_area);
+	if (off + class->size <= PAGE_SIZE) {
+		kunmap_atomic(area->vm_addr);
+	} else {
+		set_pte(area->vm_ptes[0], __pte(0));
+		set_pte(area->vm_ptes[1], __pte(0));
+		__flush_tlb_one((unsigned long)area->vm_addr);
+		__flush_tlb_one((unsigned long)area->vm_addr + PAGE_SIZE);
+	}
+	put_cpu_var(zs_map_area);
+}
+EXPORT_SYMBOL_GPL(zs_unmap_object);
+
+u64 zs_get_total_size_bytes(struct zs_pool *pool)
+{
+	int i;
+	u64 npages = 0;
+
+	for (i = 0; i < ZS_SIZE_CLASSES; i++)
+		npages += pool->size_class[i].pages_allocated;
+
+	return npages << PAGE_SHIFT;
+}
+EXPORT_SYMBOL_GPL(zs_get_total_size_bytes);
diff --git a/drivers/staging/zsmalloc/zsmalloc.h b/drivers/staging/zsmalloc/zsmalloc.h
new file mode 100644
index 0000000..949384e
--- /dev/null
+++ b/drivers/staging/zsmalloc/zsmalloc.h
@@ -0,0 +1,31 @@
+/*
+ * zsmalloc memory allocator
+ *
+ * Copyright (C) 2011  Nitin Gupta
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the license that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ */
+
+#ifndef _ZS_MALLOC_H_
+#define _ZS_MALLOC_H_
+
+#include <linux/types.h>
+
+struct zs_pool;
+
+struct zs_pool *zs_create_pool(const char *name, gfp_t flags);
+void zs_destroy_pool(struct zs_pool *pool);
+
+void *zs_malloc(struct zs_pool *pool, size_t size);
+void zs_free(struct zs_pool *pool, void *obj);
+
+void *zs_map_object(struct zs_pool *pool, void *handle);
+void zs_unmap_object(struct zs_pool *pool, void *handle);
+
+u64 zs_get_total_size_bytes(struct zs_pool *pool);
+
+#endif
diff --git a/drivers/staging/zsmalloc/zsmalloc_int.h b/drivers/staging/zsmalloc/zsmalloc_int.h
new file mode 100644
index 0000000..92eefc6
--- /dev/null
+++ b/drivers/staging/zsmalloc/zsmalloc_int.h
@@ -0,0 +1,155 @@
+/*
+ * zsmalloc memory allocator
+ *
+ * Copyright (C) 2011  Nitin Gupta
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the license that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ */
+
+#ifndef _ZS_MALLOC_INT_H_
+#define _ZS_MALLOC_INT_H_
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+/*
+ * This must be power of 2 and greater than of equal to sizeof(link_free).
+ * These two conditions ensure that any 'struct link_free' itself doesn't
+ * span more than 1 page which avoids complex case of mapping 2 pages simply
+ * to restore link_free pointer values.
+ */
+#define ZS_ALIGN		8
+
+/*
+ * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single)
+ * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N.
+ */
+#define ZS_MAX_ZSPAGE_ORDER 2
+#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER)
+
+/*
+ * Object location (<PFN>, <obj_idx>) is encoded as
+ * as single (void *) handle value.
+ *
+ * Note that object index <obj_idx> is relative to system
+ * page <PFN> it is stored in, so for each sub-page belonging
+ * to a zspage, obj_idx starts with 0.
+ *
+ * This is made more complicated by various memory models and PAE.
+ */
+
+#ifndef MAX_PHYSMEM_BITS
+#ifdef CONFIG_HIGHMEM64G
+#define MAX_PHYSMEM_BITS 36
+#else /* !CONFIG_HIGHMEM64G */
+/*
+ * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
+ * be PAGE_SHIFT
+ */
+#define MAX_PHYSMEM_BITS BITS_PER_LONG
+#endif
+#endif
+#define _PFN_BITS		(MAX_PHYSMEM_BITS - PAGE_SHIFT)
+#define OBJ_INDEX_BITS	(BITS_PER_LONG - _PFN_BITS)
+#define OBJ_INDEX_MASK	((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
+
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */
+#define ZS_MIN_ALLOC_SIZE \
+	MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
+#define ZS_MAX_ALLOC_SIZE	PAGE_SIZE
+
+/*
+ * On systems with 4K page size, this gives 254 size classes! There is a
+ * trader-off here:
+ *  - Large number of size classes is potentially wasteful as free page are
+ *    spread across these classes
+ *  - Small number of size classes causes large internal fragmentation
+ *  - Probably its better to use specific size classes (empirically
+ *    determined). NOTE: all those class sizes must be set as multiple of
+ *    ZS_ALIGN to make sure link_free itself never has to span 2 pages.
+ *
+ *  ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN
+ *  (reason above)
+ */
+#define ZS_SIZE_CLASS_DELTA	16
+#define ZS_SIZE_CLASSES		((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \
+					ZS_SIZE_CLASS_DELTA + 1)
+
+/*
+ * We do not maintain any list for completely empty or full pages
+ */
+enum fullness_group {
+	ZS_ALMOST_FULL,
+	ZS_ALMOST_EMPTY,
+	_ZS_NR_FULLNESS_GROUPS,
+
+	ZS_EMPTY,
+	ZS_FULL
+};
+
+/*
+ * We assign a page to ZS_ALMOST_EMPTY fullness group when:
+ *	n <= N / f, where
+ * n = number of allocated objects
+ * N = total number of objects zspage can store
+ * f = 1/fullness_threshold_frac
+ *
+ * Similarly, we assign zspage to:
+ *	ZS_ALMOST_FULL	when n > N / f
+ *	ZS_EMPTY	when n == 0
+ *	ZS_FULL		when n == N
+ *
+ * (see: fix_fullness_group())
+ */
+static const int fullness_threshold_frac = 4;
+
+struct mapping_area {
+	struct vm_struct *vm;
+	pte_t *vm_ptes[2];
+	char *vm_addr;
+};
+
+struct size_class {
+	/*
+	 * Size of objects stored in this class. Must be multiple
+	 * of ZS_ALIGN.
+	 */
+	int size;
+	unsigned int index;
+
+	/* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
+	int zspage_order;
+
+	spinlock_t lock;
+
+	/* stats */
+	u64 pages_allocated;
+
+	struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS];
+};
+
+/*
+ * Placed within free objects to form a singly linked list.
+ * For every zspage, first_page->freelist gives head of this list.
+ *
+ * This must be power of 2 and less than or equal to ZS_ALIGN
+ */
+struct link_free {
+	/* Handle of next free chunk (encodes <PFN, obj_idx>) */
+	void *next;
+};
+
+struct zs_pool {
+	struct size_class size_class[ZS_SIZE_CLASSES];
+
+	gfp_t flags;	/* allocation flags used when growing pool */
+	const char *name;
+};
+
+#endif
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 4426290..501b27c 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -1028,7 +1028,7 @@
 		return iscsit_add_reject_from_cmd(
 				ISCSI_REASON_BOOKMARK_NO_RESOURCES,
 				1, 1, buf, cmd);
-	} else if (transport_ret == -EINVAL) {
+	} else if (transport_ret < 0) {
 		/*
 		 * Unsupported SAM Opcode.  CHECK_CONDITION will be sent
 		 * in iscsit_execute_cmd() during the CmdSN OOO Execution
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index b7c7793..63e703b 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -117,7 +117,7 @@
 					struct se_node_acl *, struct se_session *);
 static void core_scsi3_put_pr_reg(struct t10_pr_registration *);
 
-static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd, int *ret)
+static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd)
 {
 	struct se_session *se_sess = cmd->se_sess;
 	struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
@@ -127,7 +127,7 @@
 	int conflict = 0;
 
 	if (!crh)
-		return false;
+		return -EINVAL;
 
 	pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl,
 			se_sess);
@@ -155,16 +155,14 @@
 		 */
 		if (pr_reg->pr_res_holder) {
 			core_scsi3_put_pr_reg(pr_reg);
-			*ret = 0;
-			return false;
+			return 1;
 		}
 		if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) ||
 		    (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) ||
 		    (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
 		    (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
 			core_scsi3_put_pr_reg(pr_reg);
-			*ret = 0;
-			return true;
+			return 1;
 		}
 		core_scsi3_put_pr_reg(pr_reg);
 		conflict = 1;
@@ -189,10 +187,10 @@
 			" while active SPC-3 registrations exist,"
 			" returning RESERVATION_CONFLICT\n");
 		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT;
-		return true;
+		return -EBUSY;
 	}
 
-	return false;
+	return 0;
 }
 
 int target_scsi2_reservation_release(struct se_task *task)
@@ -201,12 +199,18 @@
 	struct se_device *dev = cmd->se_dev;
 	struct se_session *sess = cmd->se_sess;
 	struct se_portal_group *tpg = sess->se_tpg;
-	int ret = 0;
+	int ret = 0, rc;
 
 	if (!sess || !tpg)
 		goto out;
-	if (target_check_scsi2_reservation_conflict(cmd, &ret))
+	rc = target_check_scsi2_reservation_conflict(cmd);
+	if (rc == 1)
 		goto out;
+	else if (rc < 0) {
+		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT;
+		ret = -EINVAL;
+		goto out;
+	}
 
 	ret = 0;
 	spin_lock(&dev->dev_reservation_lock);
@@ -243,7 +247,7 @@
 	struct se_device *dev = cmd->se_dev;
 	struct se_session *sess = cmd->se_sess;
 	struct se_portal_group *tpg = sess->se_tpg;
-	int ret = 0;
+	int ret = 0, rc;
 
 	if ((cmd->t_task_cdb[1] & 0x01) &&
 	    (cmd->t_task_cdb[1] & 0x02)) {
@@ -259,8 +263,14 @@
 	 */
 	if (!sess || !tpg)
 		goto out;
-	if (target_check_scsi2_reservation_conflict(cmd, &ret))
+	rc = target_check_scsi2_reservation_conflict(cmd);
+	if (rc == 1)
 		goto out;
+	else if (rc < 0) {
+		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT;
+		ret = -EINVAL;
+		goto out;
+	}
 
 	ret = 0;
 	spin_lock(&dev->dev_reservation_lock);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 58cea07..cd5cd95 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -2539,6 +2539,7 @@
 					cmd, cdb, pr_reg_type) != 0) {
 			cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
 			cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT;
+			cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
 			cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT;
 			return -EBUSY;
 		}
diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c
index 4c0507c..eff512b 100644
--- a/drivers/target/tcm_fc/tfc_sess.c
+++ b/drivers/target/tcm_fc/tfc_sess.c
@@ -86,16 +86,6 @@
 }
 
 /*
- * Free tport via RCU.
- */
-static void ft_tport_rcu_free(struct rcu_head *rcu)
-{
-	struct ft_tport *tport = container_of(rcu, struct ft_tport, rcu);
-
-	kfree(tport);
-}
-
-/*
  * Delete a target local port.
  * Caller holds ft_lport_lock.
  */
@@ -114,7 +104,7 @@
 		tpg->tport = NULL;
 		tport->tpg = NULL;
 	}
-	call_rcu(&tport->rcu, ft_tport_rcu_free);
+	kfree_rcu(tport, rcu);
 }
 
 /*
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index b84c834..afadcd43 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -45,7 +45,7 @@
 
 #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
 #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
- tty->name, (info->flags), serial_driver->refcount,info->count,tty->count,s)
+ tty->name, (info->tport.flags), serial_driver->refcount,info->count,tty->count,s)
 #else
 #define DBG_CNT(s)
 #endif
@@ -58,7 +58,6 @@
 
 #include <linux/types.h>
 #include <linux/serial.h>
-#include <linux/serialP.h>
 #include <linux/serial_reg.h>
 static char *serial_version = "4.30";
 
@@ -70,6 +69,7 @@
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
+#include <linux/circ_buf.h>
 #include <linux/console.h>
 #include <linux/major.h>
 #include <linux/string.h>
@@ -92,6 +92,24 @@
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 
+struct serial_state {
+	struct tty_port		tport;
+	struct circ_buf		xmit;
+	struct async_icount	icount;
+
+	unsigned long		port;
+	int			baud_base;
+	int			xmit_fifo_size;
+	int			custom_divisor;
+	int			read_status_mask;
+	int			ignore_status_mask;
+	int			timeout;
+	int			quot;
+	int			IER; 	/* Interrupt Enable Register */
+	int			MCR; 	/* Modem control register */
+	int			x_char;	/* xon/xoff character */
+};
+
 #define custom amiga_custom
 static char *serial_name = "Amiga-builtin serial driver";
 
@@ -100,11 +118,10 @@
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
 
-static struct async_struct *IRQ_ports;
-
 static unsigned char current_ctl_bits;
 
-static void change_speed(struct async_struct *info, struct ktermios *old);
+static void change_speed(struct tty_struct *tty, struct serial_state *info,
+		struct ktermios *old);
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
 
 
@@ -117,7 +134,7 @@
 #define serial_isroot()	(capable(CAP_SYS_ADMIN))
 
 
-static inline int serial_paranoia_check(struct async_struct *info,
+static inline int serial_paranoia_check(struct serial_state *info,
 					char *name, const char *routine)
 {
 #ifdef SERIAL_PARANOIA_CHECK
@@ -170,7 +187,7 @@
  */
 static void rs_stop(struct tty_struct *tty)
 {
-	struct async_struct *info = tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	unsigned long flags;
 
 	if (serial_paranoia_check(info, tty->name, "rs_stop"))
@@ -190,7 +207,7 @@
 
 static void rs_start(struct tty_struct *tty)
 {
-	struct async_struct *info = tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	unsigned long flags;
 
 	if (serial_paranoia_check(info, tty->name, "rs_start"))
@@ -231,27 +248,16 @@
  * -----------------------------------------------------------------------
  */
 
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static void rs_sched_event(struct async_struct *info,
-			   int event)
-{
-	info->event |= 1 << event;
-	tasklet_schedule(&info->tlet);
-}
-
-static void receive_chars(struct async_struct *info)
+static void receive_chars(struct serial_state *info)
 {
         int status;
 	int serdatr;
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->tport.tty;
 	unsigned char ch, flag;
 	struct	async_icount *icount;
 	int oe = 0;
 
-	icount = &info->state->icount;
+	icount = &info->icount;
 
 	status = UART_LSR_DR; /* We obviously have a character! */
 	serdatr = custom.serdatr;
@@ -308,7 +314,7 @@
 	    printk("handling break....");
 #endif
 	    flag = TTY_BREAK;
-	    if (info->flags & ASYNC_SAK)
+	    if (info->tport.flags & ASYNC_SAK)
 	      do_SAK(tty);
 	  } else if (status & UART_LSR_PE)
 	    flag = TTY_PARITY;
@@ -331,20 +337,20 @@
 	return;
 }
 
-static void transmit_chars(struct async_struct *info)
+static void transmit_chars(struct serial_state *info)
 {
 	custom.intreq = IF_TBE;
 	mb();
 	if (info->x_char) {
 	        custom.serdat = info->x_char | 0x100;
 		mb();
-		info->state->icount.tx++;
+		info->icount.tx++;
 		info->x_char = 0;
 		return;
 	}
 	if (info->xmit.head == info->xmit.tail
-	    || info->tty->stopped
-	    || info->tty->hw_stopped) {
+	    || info->tport.tty->stopped
+	    || info->tport.tty->hw_stopped) {
 		info->IER &= ~UART_IER_THRI;
 	        custom.intena = IF_TBE;
 		mb();
@@ -354,12 +360,12 @@
 	custom.serdat = info->xmit.buf[info->xmit.tail++] | 0x100;
 	mb();
 	info->xmit.tail = info->xmit.tail & (SERIAL_XMIT_SIZE-1);
-	info->state->icount.tx++;
+	info->icount.tx++;
 
 	if (CIRC_CNT(info->xmit.head,
 		     info->xmit.tail,
 		     SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
-		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+		tty_wakeup(info->tport.tty);
 
 #ifdef SERIAL_DEBUG_INTR
 	printk("THRE...");
@@ -371,8 +377,9 @@
 	}
 }
 
-static void check_modem_status(struct async_struct *info)
+static void check_modem_status(struct serial_state *info)
 {
+	struct tty_port *port = &info->tport;
 	unsigned char status = ciab.pra & (SER_DCD | SER_CTS | SER_DSR);
 	unsigned char dstatus;
 	struct	async_icount *icount;
@@ -382,52 +389,52 @@
 	current_ctl_bits = status;
 
 	if (dstatus) {
-		icount = &info->state->icount;
+		icount = &info->icount;
 		/* update input line counters */
 		if (dstatus & SER_DSR)
 			icount->dsr++;
 		if (dstatus & SER_DCD) {
 			icount->dcd++;
 #ifdef CONFIG_HARD_PPS
-			if ((info->flags & ASYNC_HARDPPS_CD) &&
+			if ((port->flags & ASYNC_HARDPPS_CD) &&
 			    !(status & SER_DCD))
 				hardpps();
 #endif
 		}
 		if (dstatus & SER_CTS)
 			icount->cts++;
-		wake_up_interruptible(&info->delta_msr_wait);
+		wake_up_interruptible(&port->delta_msr_wait);
 	}
 
-	if ((info->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) {
+	if ((port->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) {
 #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
 		printk("ttyS%d CD now %s...", info->line,
 		       (!(status & SER_DCD)) ? "on" : "off");
 #endif
 		if (!(status & SER_DCD))
-			wake_up_interruptible(&info->open_wait);
+			wake_up_interruptible(&port->open_wait);
 		else {
 #ifdef SERIAL_DEBUG_OPEN
 			printk("doing serial hangup...");
 #endif
-			if (info->tty)
-				tty_hangup(info->tty);
+			if (port->tty)
+				tty_hangup(port->tty);
 		}
 	}
-	if (info->flags & ASYNC_CTS_FLOW) {
-		if (info->tty->hw_stopped) {
+	if (port->flags & ASYNC_CTS_FLOW) {
+		if (port->tty->hw_stopped) {
 			if (!(status & SER_CTS)) {
 #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
 				printk("CTS tx start...");
 #endif
-				info->tty->hw_stopped = 0;
+				port->tty->hw_stopped = 0;
 				info->IER |= UART_IER_THRI;
 				custom.intena = IF_SETCLR | IF_TBE;
 				mb();
 				/* set a pending Tx Interrupt, transmitter should restart now */
 				custom.intreq = IF_SETCLR | IF_TBE;
 				mb();
-				rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+				tty_wakeup(port->tty);
 				return;
 			}
 		} else {
@@ -435,7 +442,7 @@
 #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
 				printk("CTS tx stop...");
 #endif
-				info->tty->hw_stopped = 1;
+				port->tty->hw_stopped = 1;
 				info->IER &= ~UART_IER_THRI;
 				/* disable Tx interrupt and remove any pending interrupts */
 				custom.intena = IF_TBE;
@@ -450,7 +457,7 @@
 static irqreturn_t ser_vbl_int( int irq, void *data)
 {
         /* vbl is just a periodic interrupt we tie into to update modem status */
-	struct async_struct * info = IRQ_ports;
+	struct serial_state *info = data;
 	/*
 	 * TBD - is it better to unregister from this interrupt or to
 	 * ignore it if MSI is clear ?
@@ -462,18 +469,16 @@
 
 static irqreturn_t ser_rx_int(int irq, void *dev_id)
 {
-	struct async_struct * info;
+	struct serial_state *info = dev_id;
 
 #ifdef SERIAL_DEBUG_INTR
 	printk("ser_rx_int...");
 #endif
 
-	info = IRQ_ports;
-	if (!info || !info->tty)
+	if (!info->tport.tty)
 		return IRQ_NONE;
 
 	receive_chars(info);
-	info->last_active = jiffies;
 #ifdef SERIAL_DEBUG_INTR
 	printk("end.\n");
 #endif
@@ -482,19 +487,17 @@
 
 static irqreturn_t ser_tx_int(int irq, void *dev_id)
 {
-	struct async_struct * info;
+	struct serial_state *info = dev_id;
 
 	if (custom.serdatr & SDR_TBE) {
 #ifdef SERIAL_DEBUG_INTR
 	  printk("ser_tx_int...");
 #endif
 
-	  info = IRQ_ports;
-	  if (!info || !info->tty)
+	  if (!info->tport.tty)
 		return IRQ_NONE;
 
 	  transmit_chars(info);
-	  info->last_active = jiffies;
 #ifdef SERIAL_DEBUG_INTR
 	  printk("end.\n");
 #endif
@@ -509,29 +512,6 @@
  */
 
 /*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using rs_sched_event(), and they get done here.
- */
-
-static void do_softint(unsigned long private_)
-{
-	struct async_struct	*info = (struct async_struct *) private_;
-	struct tty_struct	*tty;
-
-	tty = info->tty;
-	if (!tty)
-		return;
-
-	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
-		tty_wakeup(tty);
-}
-
-/*
  * ---------------------------------------------------------------
  * Low level utility subroutines for the serial driver:  routines to
  * figure out the appropriate timeout for an interrupt chain, routines
@@ -540,8 +520,9 @@
  * ---------------------------------------------------------------
  */
 
-static int startup(struct async_struct * info)
+static int startup(struct tty_struct *tty, struct serial_state *info)
 {
+	struct tty_port *port = &info->tport;
 	unsigned long flags;
 	int	retval=0;
 	unsigned long page;
@@ -552,7 +533,7 @@
 
 	local_irq_save(flags);
 
-	if (info->flags & ASYNC_INITIALIZED) {
+	if (port->flags & ASYNC_INITIALIZED) {
 		free_page(page);
 		goto errout;
 	}
@@ -574,9 +555,7 @@
 	retval = request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0, "serial status", info);
 	if (retval) {
 	  if (serial_isroot()) {
-	    if (info->tty)
-	      set_bit(TTY_IO_ERROR,
-		      &info->tty->flags);
+	      set_bit(TTY_IO_ERROR, &tty->flags);
 	    retval = 0;
 	  }
 	  goto errout;
@@ -590,37 +569,32 @@
 	/* remember current state of the DCD and CTS bits */
 	current_ctl_bits = ciab.pra & (SER_DCD | SER_CTS | SER_DSR);
 
-	IRQ_ports = info;
-
 	info->MCR = 0;
-	if (info->tty->termios->c_cflag & CBAUD)
+	if (C_BAUD(tty))
 	  info->MCR = SER_DTR | SER_RTS;
 	rtsdtr_ctrl(info->MCR);
 
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	clear_bit(TTY_IO_ERROR, &tty->flags);
 	info->xmit.head = info->xmit.tail = 0;
 
 	/*
 	 * Set up the tty->alt_speed kludge
 	 */
-	if (info->tty) {
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-			info->tty->alt_speed = 57600;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-			info->tty->alt_speed = 115200;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-			info->tty->alt_speed = 230400;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-			info->tty->alt_speed = 460800;
-	}
+	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+		tty->alt_speed = 57600;
+	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+		tty->alt_speed = 115200;
+	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+		tty->alt_speed = 230400;
+	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+		tty->alt_speed = 460800;
 
 	/*
 	 * and set the speed of the serial port
 	 */
-	change_speed(info, NULL);
+	change_speed(tty, info, NULL);
 
-	info->flags |= ASYNC_INITIALIZED;
+	port->flags |= ASYNC_INITIALIZED;
 	local_irq_restore(flags);
 	return 0;
 
@@ -633,15 +607,15 @@
  * This routine will shutdown a serial port; interrupts are disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
  */
-static void shutdown(struct async_struct * info)
+static void shutdown(struct tty_struct *tty, struct serial_state *info)
 {
 	unsigned long	flags;
 	struct serial_state *state;
 
-	if (!(info->flags & ASYNC_INITIALIZED))
+	if (!(info->tport.flags & ASYNC_INITIALIZED))
 		return;
 
-	state = info->state;
+	state = info;
 
 #ifdef SERIAL_DEBUG_OPEN
 	printk("Shutting down serial port %d ....\n", info->line);
@@ -653,9 +627,7 @@
 	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
 	 * here so the queue might never be waken up
 	 */
-	wake_up_interruptible(&info->delta_msr_wait);
-
-	IRQ_ports = NULL;
+	wake_up_interruptible(&info->tport.delta_msr_wait);
 
 	/*
 	 * Free the IRQ, if necessary
@@ -675,14 +647,13 @@
 	custom.adkcon = AC_UARTBRK;
 	mb();
 
-	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+	if (tty->termios->c_cflag & HUPCL)
 		info->MCR &= ~(SER_DTR|SER_RTS);
 	rtsdtr_ctrl(info->MCR);
 
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	set_bit(TTY_IO_ERROR, &tty->flags);
 
-	info->flags &= ~ASYNC_INITIALIZED;
+	info->tport.flags &= ~ASYNC_INITIALIZED;
 	local_irq_restore(flags);
 }
 
@@ -691,17 +662,16 @@
  * This routine is called to set the UART divisor registers to match
  * the specified baud rate for a serial port.
  */
-static void change_speed(struct async_struct *info,
+static void change_speed(struct tty_struct *tty, struct serial_state *info,
 			 struct ktermios *old_termios)
 {
+	struct tty_port *port = &info->tport;
 	int	quot = 0, baud_base, baud;
 	unsigned cflag, cval = 0;
 	int	bits;
 	unsigned long	flags;
 
-	if (!info->tty || !info->tty->termios)
-		return;
-	cflag = info->tty->termios->c_cflag;
+	cflag = tty->termios->c_cflag;
 
 	/* Byte size is always 8 bits plus parity bit if requested */
 
@@ -722,13 +692,12 @@
 #endif
 
 	/* Determine divisor based on baud rate */
-	baud = tty_get_baud_rate(info->tty);
+	baud = tty_get_baud_rate(tty);
 	if (!baud)
 		baud = 9600;	/* B0 transition handled in rs_set_termios */
-	baud_base = info->state->baud_base;
-	if (baud == 38400 &&
-	    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
-		quot = info->state->custom_divisor;
+	baud_base = info->baud_base;
+	if (baud == 38400 && (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
+		quot = info->custom_divisor;
 	else {
 		if (baud == 134)
 			/* Special case since 134 is really 134.5 */
@@ -739,14 +708,14 @@
 	/* If the quotient is zero refuse the change */
 	if (!quot && old_termios) {
 		/* FIXME: Will need updating for new tty in the end */
-		info->tty->termios->c_cflag &= ~CBAUD;
-		info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
-		baud = tty_get_baud_rate(info->tty);
+		tty->termios->c_cflag &= ~CBAUD;
+		tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+		baud = tty_get_baud_rate(tty);
 		if (!baud)
 			baud = 9600;
 		if (baud == 38400 &&
-		    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
-			quot = info->state->custom_divisor;
+		    (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
+			quot = info->custom_divisor;
 		else {
 			if (baud == 134)
 				/* Special case since 134 is really 134.5 */
@@ -764,17 +733,17 @@
 
 	/* CTS flow control flag and modem status interrupts */
 	info->IER &= ~UART_IER_MSI;
-	if (info->flags & ASYNC_HARDPPS_CD)
+	if (port->flags & ASYNC_HARDPPS_CD)
 		info->IER |= UART_IER_MSI;
 	if (cflag & CRTSCTS) {
-		info->flags |= ASYNC_CTS_FLOW;
+		port->flags |= ASYNC_CTS_FLOW;
 		info->IER |= UART_IER_MSI;
 	} else
-		info->flags &= ~ASYNC_CTS_FLOW;
+		port->flags &= ~ASYNC_CTS_FLOW;
 	if (cflag & CLOCAL)
-		info->flags &= ~ASYNC_CHECK_CD;
+		port->flags &= ~ASYNC_CHECK_CD;
 	else {
-		info->flags |= ASYNC_CHECK_CD;
+		port->flags |= ASYNC_CHECK_CD;
 		info->IER |= UART_IER_MSI;
 	}
 	/* TBD:
@@ -786,24 +755,24 @@
 	 */
 
 	info->read_status_mask = UART_LSR_OE | UART_LSR_DR;
-	if (I_INPCK(info->tty))
+	if (I_INPCK(tty))
 		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+	if (I_BRKINT(tty) || I_PARMRK(tty))
 		info->read_status_mask |= UART_LSR_BI;
 
 	/*
 	 * Characters to ignore
 	 */
 	info->ignore_status_mask = 0;
-	if (I_IGNPAR(info->tty))
+	if (I_IGNPAR(tty))
 		info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-	if (I_IGNBRK(info->tty)) {
+	if (I_IGNBRK(tty)) {
 		info->ignore_status_mask |= UART_LSR_BI;
 		/*
 		 * If we're ignore parity and break indicators, ignore 
 		 * overruns too.  (For real raw support).
 		 */
-		if (I_IGNPAR(info->tty))
+		if (I_IGNPAR(tty))
 			info->ignore_status_mask |= UART_LSR_OE;
 	}
 	/*
@@ -828,13 +797,12 @@
 	mb();
 	}
 
-	info->LCR = cval;				/* Save LCR */
 	local_irq_restore(flags);
 }
 
 static int rs_put_char(struct tty_struct *tty, unsigned char ch)
 {
-	struct async_struct *info;
+	struct serial_state *info;
 	unsigned long flags;
 
 	info = tty->driver_data;
@@ -861,7 +829,7 @@
 
 static void rs_flush_chars(struct tty_struct *tty)
 {
-	struct async_struct *info = tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	unsigned long flags;
 
 	if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
@@ -886,11 +854,9 @@
 static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count)
 {
 	int	c, ret = 0;
-	struct async_struct *info;
+	struct serial_state *info = tty->driver_data;
 	unsigned long flags;
 
-	info = tty->driver_data;
-
 	if (serial_paranoia_check(info, tty->name, "rs_write"))
 		return 0;
 
@@ -934,7 +900,7 @@
 
 static int rs_write_room(struct tty_struct *tty)
 {
-	struct async_struct *info = tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 
 	if (serial_paranoia_check(info, tty->name, "rs_write_room"))
 		return 0;
@@ -943,7 +909,7 @@
 
 static int rs_chars_in_buffer(struct tty_struct *tty)
 {
-	struct async_struct *info = tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 
 	if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
 		return 0;
@@ -952,7 +918,7 @@
 
 static void rs_flush_buffer(struct tty_struct *tty)
 {
-	struct async_struct *info = tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	unsigned long flags;
 
 	if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
@@ -969,7 +935,7 @@
  */
 static void rs_send_xchar(struct tty_struct *tty, char ch)
 {
-	struct async_struct *info = tty->driver_data;
+	struct serial_state *info = tty->driver_data;
         unsigned long flags;
 
 	if (serial_paranoia_check(info, tty->name, "rs_send_char"))
@@ -1004,7 +970,7 @@
  */
 static void rs_throttle(struct tty_struct * tty)
 {
-	struct async_struct *info = tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
@@ -1029,7 +995,7 @@
 
 static void rs_unthrottle(struct tty_struct * tty)
 {
-	struct async_struct *info = tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
@@ -1060,25 +1026,22 @@
  * ------------------------------------------------------------
  */
 
-static int get_serial_info(struct async_struct * info,
+static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
 			   struct serial_struct __user * retinfo)
 {
 	struct serial_struct tmp;
-	struct serial_state *state = info->state;
    
 	if (!retinfo)
 		return -EFAULT;
 	memset(&tmp, 0, sizeof(tmp));
 	tty_lock();
-	tmp.type = state->type;
-	tmp.line = state->line;
+	tmp.line = tty->index;
 	tmp.port = state->port;
-	tmp.irq = state->irq;
-	tmp.flags = state->flags;
+	tmp.flags = state->tport.flags;
 	tmp.xmit_fifo_size = state->xmit_fifo_size;
 	tmp.baud_base = state->baud_base;
-	tmp.close_delay = state->close_delay;
-	tmp.closing_wait = state->closing_wait;
+	tmp.close_delay = state->tport.close_delay;
+	tmp.closing_wait = state->tport.closing_wait;
 	tmp.custom_divisor = state->custom_divisor;
 	tty_unlock();
 	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
@@ -1086,38 +1049,34 @@
 	return 0;
 }
 
-static int set_serial_info(struct async_struct * info,
+static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
 			   struct serial_struct __user * new_info)
 {
+	struct tty_port *port = &state->tport;
 	struct serial_struct new_serial;
- 	struct serial_state old_state, *state;
-	unsigned int		change_irq,change_port;
+	bool change_spd;
 	int 			retval = 0;
 
 	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
 		return -EFAULT;
 
 	tty_lock();
-	state = info->state;
-	old_state = *state;
-  
-	change_irq = new_serial.irq != state->irq;
-	change_port = (new_serial.port != state->port);
-	if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size)) {
-	  tty_unlock();
-	  return -EINVAL;
+	change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
+		new_serial.custom_divisor != state->custom_divisor;
+	if (new_serial.irq || new_serial.port != state->port ||
+			new_serial.xmit_fifo_size != state->xmit_fifo_size) {
+		tty_unlock();
+		return -EINVAL;
 	}
   
 	if (!serial_isroot()) {
 		if ((new_serial.baud_base != state->baud_base) ||
-		    (new_serial.close_delay != state->close_delay) ||
+		    (new_serial.close_delay != port->close_delay) ||
 		    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
 		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
-		     (state->flags & ~ASYNC_USR_MASK)))
+		     (port->flags & ~ASYNC_USR_MASK)))
 			return -EPERM;
-		state->flags = ((state->flags & ~ASYNC_USR_MASK) |
-			       (new_serial.flags & ASYNC_USR_MASK));
-		info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+		port->flags = ((port->flags & ~ASYNC_USR_MASK) |
 			       (new_serial.flags & ASYNC_USR_MASK));
 		state->custom_divisor = new_serial.custom_divisor;
 		goto check_and_exit;
@@ -1134,32 +1093,28 @@
 	 */
 
 	state->baud_base = new_serial.baud_base;
-	state->flags = ((state->flags & ~ASYNC_FLAGS) |
+	port->flags = ((port->flags & ~ASYNC_FLAGS) |
 			(new_serial.flags & ASYNC_FLAGS));
-	info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
-		       (info->flags & ASYNC_INTERNAL_FLAGS));
 	state->custom_divisor = new_serial.custom_divisor;
-	state->close_delay = new_serial.close_delay * HZ/100;
-	state->closing_wait = new_serial.closing_wait * HZ/100;
-	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+	port->close_delay = new_serial.close_delay * HZ/100;
+	port->closing_wait = new_serial.closing_wait * HZ/100;
+	tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 check_and_exit:
-	if (info->flags & ASYNC_INITIALIZED) {
-		if (((old_state.flags & ASYNC_SPD_MASK) !=
-		     (state->flags & ASYNC_SPD_MASK)) ||
-		    (old_state.custom_divisor != state->custom_divisor)) {
-			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-				info->tty->alt_speed = 57600;
-			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-				info->tty->alt_speed = 115200;
-			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-				info->tty->alt_speed = 230400;
-			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-				info->tty->alt_speed = 460800;
-			change_speed(info, NULL);
+	if (port->flags & ASYNC_INITIALIZED) {
+		if (change_spd) {
+			if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+				tty->alt_speed = 57600;
+			if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+				tty->alt_speed = 115200;
+			if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+				tty->alt_speed = 230400;
+			if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+				tty->alt_speed = 460800;
+			change_speed(tty, state, NULL);
 		}
 	} else
-		retval = startup(info);
+		retval = startup(tty, state);
 	tty_unlock();
 	return retval;
 }
@@ -1175,7 +1130,7 @@
  * 	    transmit holding register is empty.  This functionality
  * 	    allows an RS485 driver to be written in user space. 
  */
-static int get_lsr_info(struct async_struct * info, unsigned int __user *value)
+static int get_lsr_info(struct serial_state *info, unsigned int __user *value)
 {
 	unsigned char status;
 	unsigned int result;
@@ -1194,7 +1149,7 @@
 
 static int rs_tiocmget(struct tty_struct *tty)
 {
-	struct async_struct * info = tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	unsigned char control, status;
 	unsigned long flags;
 
@@ -1217,7 +1172,7 @@
 static int rs_tiocmset(struct tty_struct *tty, unsigned int set,
 						unsigned int clear)
 {
-	struct async_struct * info = tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	unsigned long flags;
 
 	if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
@@ -1244,7 +1199,7 @@
  */
 static int rs_break(struct tty_struct *tty, int break_state)
 {
-	struct async_struct * info = tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	unsigned long flags;
 
 	if (serial_paranoia_check(info, tty->name, "rs_break"))
@@ -1269,12 +1224,12 @@
 static int rs_get_icount(struct tty_struct *tty,
 				struct serial_icounter_struct *icount)
 {
-	struct async_struct *info = tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	struct async_icount cnow;
 	unsigned long flags;
 
 	local_irq_save(flags);
-	cnow = info->state->icount;
+	cnow = info->icount;
 	local_irq_restore(flags);
 	icount->cts = cnow.cts;
 	icount->dsr = cnow.dsr;
@@ -1294,7 +1249,7 @@
 static int rs_ioctl(struct tty_struct *tty,
 		    unsigned int cmd, unsigned long arg)
 {
-	struct async_struct * info = tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	struct async_icount cprev, cnow;	/* kernel counter temps */
 	void __user *argp = (void __user *)arg;
 	unsigned long flags;
@@ -1311,9 +1266,9 @@
 
 	switch (cmd) {
 		case TIOCGSERIAL:
-			return get_serial_info(info, argp);
+			return get_serial_info(tty, info, argp);
 		case TIOCSSERIAL:
-			return set_serial_info(info, argp);
+			return set_serial_info(tty, info, argp);
 		case TIOCSERCONFIG:
 			return 0;
 
@@ -1322,7 +1277,7 @@
 
 		case TIOCSERGSTRUCT:
 			if (copy_to_user(argp,
-					 info, sizeof(struct async_struct)))
+					 info, sizeof(struct serial_state)))
 				return -EFAULT;
 			return 0;
 
@@ -1335,15 +1290,15 @@
 		case TIOCMIWAIT:
 			local_irq_save(flags);
 			/* note the counters on entry */
-			cprev = info->state->icount;
+			cprev = info->icount;
 			local_irq_restore(flags);
 			while (1) {
-				interruptible_sleep_on(&info->delta_msr_wait);
+				interruptible_sleep_on(&info->tport.delta_msr_wait);
 				/* see if a signal did it */
 				if (signal_pending(current))
 					return -ERESTARTSYS;
 				local_irq_save(flags);
-				cnow = info->state->icount; /* atomic copy */
+				cnow = info->icount; /* atomic copy */
 				local_irq_restore(flags);
 				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
 				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
@@ -1372,11 +1327,11 @@
 
 static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
-	struct async_struct *info = tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	unsigned long flags;
 	unsigned int cflag = tty->termios->c_cflag;
 
-	change_speed(info, old_termios);
+	change_speed(tty, info, old_termios);
 
 	/* Handle transition to B0 status */
 	if ((old_termios->c_cflag & CBAUD) &&
@@ -1432,64 +1387,23 @@
  */
 static void rs_close(struct tty_struct *tty, struct file * filp)
 {
-	struct async_struct * info = tty->driver_data;
-	struct serial_state *state;
-	unsigned long flags;
+	struct serial_state *state = tty->driver_data;
+	struct tty_port *port = &state->tport;
 
-	if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
+	if (serial_paranoia_check(state, tty->name, "rs_close"))
 		return;
 
-	state = info->state;
-
-	local_irq_save(flags);
-
-	if (tty_hung_up_p(filp)) {
-		DBG_CNT("before DEC-hung");
-		local_irq_restore(flags);
+	if (tty_port_close_start(port, tty, filp) == 0)
 		return;
-	}
 
-#ifdef SERIAL_DEBUG_OPEN
-	printk("rs_close ttys%d, count = %d\n", info->line, state->count);
-#endif
-	if ((tty->count == 1) && (state->count != 1)) {
-		/*
-		 * Uh, oh.  tty->count is 1, which means that the tty
-		 * structure will be freed.  state->count should always
-		 * be one in these conditions.  If it's greater than
-		 * one, we've got real problems, since it means the
-		 * serial port won't be shutdown.
-		 */
-		printk("rs_close: bad serial port count; tty->count is 1, "
-		       "state->count is %d\n", state->count);
-		state->count = 1;
-	}
-	if (--state->count < 0) {
-		printk("rs_close: bad serial port count for ttys%d: %d\n",
-		       info->line, state->count);
-		state->count = 0;
-	}
-	if (state->count) {
-		DBG_CNT("before DEC-2");
-		local_irq_restore(flags);
-		return;
-	}
-	info->flags |= ASYNC_CLOSING;
-	/*
-	 * Now we wait for the transmit buffer to clear; and we notify 
-	 * the line discipline to only process XON/XOFF characters.
-	 */
-	tty->closing = 1;
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
 	 * interrupt driver to stop checking the data ready bit in the
 	 * line status register.
 	 */
-	info->read_status_mask &= ~UART_LSR_DR;
-	if (info->flags & ASYNC_INITIALIZED) {
+	state->read_status_mask &= ~UART_LSR_DR;
+	if (port->flags & ASYNC_INITIALIZED) {
 	        /* disable receive interrupts */
 	        custom.intena = IF_RBF;
 		mb();
@@ -1502,24 +1416,15 @@
 		 * has completely drained; this is especially
 		 * important if there is a transmit FIFO!
 		 */
-		rs_wait_until_sent(tty, info->timeout);
+		rs_wait_until_sent(tty, state->timeout);
 	}
-	shutdown(info);
+	shutdown(tty, state);
 	rs_flush_buffer(tty);
 		
 	tty_ldisc_flush(tty);
-	tty->closing = 0;
-	info->event = 0;
-	info->tty = NULL;
-	if (info->blocked_open) {
-		if (info->close_delay) {
-			msleep_interruptible(jiffies_to_msecs(info->close_delay));
-		}
-		wake_up_interruptible(&info->open_wait);
-	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-	wake_up_interruptible(&info->close_wait);
-	local_irq_restore(flags);
+	port->tty = NULL;
+
+	tty_port_close_end(port, tty);
 }
 
 /*
@@ -1527,7 +1432,7 @@
  */
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
 {
-	struct async_struct * info = tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	unsigned long orig_jiffies, char_time;
 	int lsr;
 
@@ -1590,173 +1495,17 @@
  */
 static void rs_hangup(struct tty_struct *tty)
 {
-	struct async_struct * info = tty->driver_data;
-	struct serial_state *state = info->state;
+	struct serial_state *info = tty->driver_data;
 
 	if (serial_paranoia_check(info, tty->name, "rs_hangup"))
 		return;
 
-	state = info->state;
-
 	rs_flush_buffer(tty);
-	shutdown(info);
-	info->event = 0;
-	state->count = 0;
-	info->flags &= ~ASYNC_NORMAL_ACTIVE;
-	info->tty = NULL;
-	wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
-			   struct async_struct *info)
-{
-#ifdef DECLARE_WAITQUEUE
-	DECLARE_WAITQUEUE(wait, current);
-#else
-	struct wait_queue wait = { current, NULL };
-#endif
-	struct serial_state *state = info->state;
-	int		retval;
-	int		do_clocal = 0, extra_count = 0;
-	unsigned long	flags;
-
-	/*
-	 * If the device is in the middle of being closed, then block
-	 * until it's done, and then try again.
-	 */
-	if (tty_hung_up_p(filp) ||
-	    (info->flags & ASYNC_CLOSING)) {
-		if (info->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-		return ((info->flags & ASYNC_HUP_NOTIFY) ?
-			-EAGAIN : -ERESTARTSYS);
-#else
-		return -EAGAIN;
-#endif
-	}
-
-	/*
-	 * If non-blocking mode is set, or the port is not enabled,
-	 * then make the check up front and then exit.
-	 */
-	if ((filp->f_flags & O_NONBLOCK) ||
-	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		info->flags |= ASYNC_NORMAL_ACTIVE;
-		return 0;
-	}
-
-	if (tty->termios->c_cflag & CLOCAL)
-		do_clocal = 1;
-
-	/*
-	 * Block waiting for the carrier detect and the line to become
-	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, state->count is dropped by one, so that
-	 * rs_close() knows when to free things.  We restore it upon
-	 * exit, either normal or abnormal.
-	 */
-	retval = 0;
-	add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready before block: ttys%d, count = %d\n",
-	       state->line, state->count);
-#endif
-	local_irq_save(flags);
-	if (!tty_hung_up_p(filp)) {
-		extra_count = 1;
-		state->count--;
-	}
-	local_irq_restore(flags);
-	info->blocked_open++;
-	while (1) {
-		local_irq_save(flags);
-		if (tty->termios->c_cflag & CBAUD)
-		        rtsdtr_ctrl(SER_DTR|SER_RTS);
-		local_irq_restore(flags);
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (tty_hung_up_p(filp) ||
-		    !(info->flags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-			if (info->flags & ASYNC_HUP_NOTIFY)
-				retval = -EAGAIN;
-			else
-				retval = -ERESTARTSYS;
-#else
-			retval = -EAGAIN;
-#endif
-			break;
-		}
-		if (!(info->flags & ASYNC_CLOSING) &&
-		    (do_clocal || (!(ciab.pra & SER_DCD)) ))
-			break;
-		if (signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			break;
-		}
-#ifdef SERIAL_DEBUG_OPEN
-		printk("block_til_ready blocking: ttys%d, count = %d\n",
-		       info->line, state->count);
-#endif
-		tty_unlock();
-		schedule();
-		tty_lock();
-	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&info->open_wait, &wait);
-	if (extra_count)
-		state->count++;
-	info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready after blocking: ttys%d, count = %d\n",
-	       info->line, state->count);
-#endif
-	if (retval)
-		return retval;
-	info->flags |= ASYNC_NORMAL_ACTIVE;
-	return 0;
-}
-
-static int get_async_struct(int line, struct async_struct **ret_info)
-{
-	struct async_struct *info;
-	struct serial_state *sstate;
-
-	sstate = rs_table + line;
-	sstate->count++;
-	if (sstate->info) {
-		*ret_info = sstate->info;
-		return 0;
-	}
-	info = kzalloc(sizeof(struct async_struct), GFP_KERNEL);
-	if (!info) {
-		sstate->count--;
-		return -ENOMEM;
-	}
-#ifdef DECLARE_WAITQUEUE
-	init_waitqueue_head(&info->open_wait);
-	init_waitqueue_head(&info->close_wait);
-	init_waitqueue_head(&info->delta_msr_wait);
-#endif
-	info->magic = SERIAL_MAGIC;
-	info->port = sstate->port;
-	info->flags = sstate->flags;
-	info->xmit_fifo_size = sstate->xmit_fifo_size;
-	info->line = line;
-	tasklet_init(&info->tlet, do_softint, (unsigned long)info);
-	info->state = sstate;
-	if (sstate->info) {
-		kfree(info);
-		*ret_info = sstate->info;
-		return 0;
-	}
-	*ret_info = sstate->info = info;
-	return 0;
+	shutdown(tty, info);
+	info->tport.count = 0;
+	info->tport.flags &= ~ASYNC_NORMAL_ACTIVE;
+	info->tport.tty = NULL;
+	wake_up_interruptible(&info->tport.open_wait);
 }
 
 /*
@@ -1767,91 +1516,42 @@
  */
 static int rs_open(struct tty_struct *tty, struct file * filp)
 {
-	struct async_struct	*info;
-	int 			retval, line;
+	struct serial_state *info = rs_table + tty->index;
+	struct tty_port *port = &info->tport;
+	int retval;
 
-	line = tty->index;
-	if ((line < 0) || (line >= NR_PORTS)) {
-		return -ENODEV;
-	}
-	retval = get_async_struct(line, &info);
-	if (retval) {
-		return retval;
-	}
+	port->count++;
+	port->tty = tty;
 	tty->driver_data = info;
-	info->tty = tty;
+	tty->port = port;
 	if (serial_paranoia_check(info, tty->name, "rs_open"))
 		return -ENODEV;
 
-#ifdef SERIAL_DEBUG_OPEN
-	printk("rs_open %s, count = %d\n", tty->name, info->state->count);
-#endif
-	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+	tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
-	/*
-	 * If the port is the middle of closing, bail out now
-	 */
-	if (tty_hung_up_p(filp) ||
-	    (info->flags & ASYNC_CLOSING)) {
-		if (info->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-		return ((info->flags & ASYNC_HUP_NOTIFY) ?
-			-EAGAIN : -ERESTARTSYS);
-#else
-		return -EAGAIN;
-#endif
-	}
-
-	/*
-	 * Start up serial port
-	 */
-	retval = startup(info);
+	retval = startup(tty, info);
 	if (retval) {
 		return retval;
 	}
 
-	retval = block_til_ready(tty, filp, info);
-	if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-		printk("rs_open returning after block_til_ready with %d\n",
-		       retval);
-#endif
-		return retval;
-	}
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("rs_open %s successful...", tty->name);
-#endif
-	return 0;
+	return tty_port_block_til_ready(port, tty, filp);
 }
 
 /*
  * /proc fs routines....
  */
 
-static inline void line_info(struct seq_file *m, struct serial_state *state)
+static inline void line_info(struct seq_file *m, int line,
+		struct serial_state *state)
 {
-	struct async_struct *info = state->info, scr_info;
 	char	stat_buf[30], control, status;
 	unsigned long flags;
 
-	seq_printf(m, "%d: uart:amiga_builtin",state->line);
+	seq_printf(m, "%d: uart:amiga_builtin", line);
 
-	/*
-	 * Figure out the current RS-232 lines
-	 */
-	if (!info) {
-		info = &scr_info;	/* This is just for serial_{in,out} */
-
-		info->magic = SERIAL_MAGIC;
-		info->flags = state->flags;
-		info->quot = 0;
-		info->tty = NULL;
-	}
 	local_irq_save(flags);
 	status = ciab.pra;
-	control = info ? info->MCR : status;
+	control = (state->tport.flags & ASYNC_INITIALIZED) ? state->MCR : status;
 	local_irq_restore(flags);
 
 	stat_buf[0] = 0;
@@ -1867,9 +1567,8 @@
 	if(!(status & SER_DCD))
 		strcat(stat_buf, "|CD");
 
-	if (info->quot) {
-		seq_printf(m, " baud:%d", state->baud_base / info->quot);
-	}
+	if (state->quot)
+		seq_printf(m, " baud:%d", state->baud_base / state->quot);
 
 	seq_printf(m, " tx:%d rx:%d", state->icount.tx, state->icount.rx);
 
@@ -1894,7 +1593,7 @@
 static int rs_proc_show(struct seq_file *m, void *v)
 {
 	seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version);
-	line_info(m, &rs_table[0]);
+	line_info(m, 0, &rs_table[0]);
 	return 0;
 }
 
@@ -1955,6 +1654,32 @@
 	.proc_fops = &rs_proc_fops,
 };
 
+static int amiga_carrier_raised(struct tty_port *port)
+{
+	return !(ciab.pra & SER_DCD);
+}
+
+static void amiga_dtr_rts(struct tty_port *port, int raise)
+{
+	struct serial_state *info = container_of(port, struct serial_state,
+			tport);
+	unsigned long flags;
+
+	if (raise)
+		info->MCR |= SER_DTR|SER_RTS;
+	else
+		info->MCR &= ~(SER_DTR|SER_RTS);
+
+	local_irq_save(flags);
+	rtsdtr_ctrl(info->MCR);
+	local_irq_restore(flags);
+}
+
+static const struct tty_port_operations amiga_port_ops = {
+	.carrier_raised = amiga_carrier_raised,
+	.dtr_rts = amiga_dtr_rts,
+};
+
 /*
  * The serial driver boot-time initialization code!
  */
@@ -1964,17 +1689,14 @@
 	struct serial_state * state;
 	int error;
 
-	serial_driver = alloc_tty_driver(1);
+	serial_driver = alloc_tty_driver(NR_PORTS);
 	if (!serial_driver)
 		return -ENOMEM;
 
-	IRQ_ports = NULL;
-
 	show_serial_version();
 
 	/* Initialize the tty_driver structure */
 
-	serial_driver->owner = THIS_MODULE;
 	serial_driver->driver_name = "amiserial";
 	serial_driver->name = "ttyS";
 	serial_driver->major = TTY_MAJOR;
@@ -1992,20 +1714,17 @@
 		goto fail_put_tty_driver;
 
 	state = rs_table;
-	state->magic = SSTATE_MAGIC;
 	state->port = (int)&custom.serdatr; /* Just to give it a value */
-	state->line = 0;
 	state->custom_divisor = 0;
-	state->close_delay = 5*HZ/10;
-	state->closing_wait = 30*HZ;
 	state->icount.cts = state->icount.dsr = 
 	  state->icount.rng = state->icount.dcd = 0;
 	state->icount.rx = state->icount.tx = 0;
 	state->icount.frame = state->icount.parity = 0;
 	state->icount.overrun = state->icount.brk = 0;
+	tty_port_init(&state->tport);
+	state->tport.ops = &amiga_port_ops;
 
-	printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n",
-		       state->line);
+	printk(KERN_INFO "ttyS0 is the amiga builtin serial port\n");
 
 	/* Hardware set up */
 
@@ -2058,20 +1777,15 @@
 {
 	int error;
 	struct serial_state *state = platform_get_drvdata(pdev);
-	struct async_struct *info = state->info;
 
 	/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
-	tasklet_kill(&info->tlet);
 	if ((error = tty_unregister_driver(serial_driver)))
 		printk("SERIAL: failed to unregister serial driver (%d)\n",
 		       error);
 	put_tty_driver(serial_driver);
 
-	rs_table[0].info = NULL;
-	kfree(info);
-
-	free_irq(IRQ_AMIGA_TBE, rs_table);
-	free_irq(IRQ_AMIGA_RBF, rs_table);
+	free_irq(IRQ_AMIGA_TBE, state);
+	free_irq(IRQ_AMIGA_RBF, state);
 
 	platform_set_drvdata(pdev, NULL);
 
diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c
index 3a99776..946f799 100644
--- a/drivers/tty/bfin_jtag_comm.c
+++ b/drivers/tty/bfin_jtag_comm.c
@@ -257,7 +257,6 @@
 	if (!bfin_jc_driver)
 		goto err_driver;
 
-	bfin_jc_driver->owner        = THIS_MODULE;
 	bfin_jc_driver->driver_name  = DRV_NAME;
 	bfin_jc_driver->name         = DEV_NAME;
 	bfin_jc_driver->type         = TTY_DRIVER_TYPE_SERIAL;
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index c9bf779..e61cabd 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -1515,13 +1515,9 @@
 static int cy_open(struct tty_struct *tty, struct file *filp)
 {
 	struct cyclades_port *info;
-	unsigned int i, line;
+	unsigned int i, line = tty->index;
 	int retval;
 
-	line = tty->index;
-	if (tty->index < 0 || NR_PORTS <= line)
-		return -ENODEV;
-
 	for (i = 0; i < NR_CARDS; i++)
 		if (line < cy_card[i].first_line + cy_card[i].nports &&
 				line >= cy_card[i].first_line)
@@ -2413,7 +2409,7 @@
 		/* Not supported yet */
 		return -EINVAL;
 	}
-	return put_user(result, (unsigned long __user *)value);
+	return put_user(result, value);
 }
 
 static int cy_tiocmget(struct tty_struct *tty)
@@ -4090,7 +4086,6 @@
 
 	/* Initialize the tty_driver structure */
 
-	cy_serial_driver->owner = THIS_MODULE;
 	cy_serial_driver->driver_name = "cyclades";
 	cy_serial_driver->name = "ttyC";
 	cy_serial_driver->major = CYCLADES_MAJOR;
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 1595dba..4813684 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -825,7 +825,6 @@
 		goto error;
 	}
 
-	ehv_bc_driver->owner = THIS_MODULE;
 	ehv_bc_driver->driver_name = "ehv-bc";
 	ehv_bc_driver->name = ehv_bc_console.name;
 	ehv_bc_driver->type = TTY_DRIVER_TYPE_CONSOLE;
diff --git a/drivers/tty/hvc/hvc_beat.c b/drivers/tty/hvc/hvc_beat.c
index 5fe4631..1560d23 100644
--- a/drivers/tty/hvc/hvc_beat.c
+++ b/drivers/tty/hvc/hvc_beat.c
@@ -113,7 +113,7 @@
 	if (!firmware_has_feature(FW_FEATURE_BEAT))
 		return -ENODEV;
 
-	hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16);
+	hp = hvc_alloc(0, 0, &hvc_beat_get_put_ops, 16);
 	if (IS_ERR(hp))
 		return PTR_ERR(hp);
 	hvc_beat_dev = hp;
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index b6b2d18..8880adf 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -917,7 +917,6 @@
 		goto out;
 	}
 
-	drv->owner = THIS_MODULE;
 	drv->driver_name = "hvc";
 	drv->name = "hvc";
 	drv->major = HVC_MAJOR;
diff --git a/drivers/tty/hvc/hvc_rtas.c b/drivers/tty/hvc/hvc_rtas.c
index 61c4a61..0069bb8 100644
--- a/drivers/tty/hvc/hvc_rtas.c
+++ b/drivers/tty/hvc/hvc_rtas.c
@@ -94,7 +94,7 @@
 
 	/* Allocate an hvc_struct for the console device we instantiated
 	 * earlier.  Save off hp so that we can return it on exit */
-	hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16);
+	hp = hvc_alloc(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops, 16);
 	if (IS_ERR(hp))
 		return PTR_ERR(hp);
 
diff --git a/drivers/tty/hvc/hvc_udbg.c b/drivers/tty/hvc/hvc_udbg.c
index b0957e6..4c9b13e 100644
--- a/drivers/tty/hvc/hvc_udbg.c
+++ b/drivers/tty/hvc/hvc_udbg.c
@@ -69,7 +69,7 @@
 
 	BUG_ON(hvc_udbg_dev);
 
-	hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16);
+	hp = hvc_alloc(0, 0, &hvc_udbg_ops, 16);
 	if (IS_ERR(hp))
 		return PTR_ERR(hp);
 
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index 52fdf60..a1b0a75 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -176,7 +176,7 @@
 		xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
 	}
 	if (xencons_irq < 0)
-		xencons_irq = 0; /* NO_IRQ */
+		xencons_irq = 0;
 	else
 		irq_set_noprobe(xencons_irq);
 
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index b9040be..d237591 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -1090,27 +1090,23 @@
  */
 static struct hvcs_struct *hvcs_get_by_index(int index)
 {
-	struct hvcs_struct *hvcsd = NULL;
+	struct hvcs_struct *hvcsd;
 	unsigned long flags;
 
 	spin_lock(&hvcs_structs_lock);
-	/* We can immediately discard OOB requests */
-	if (index >= 0 && index < HVCS_MAX_SERVER_ADAPTERS) {
-		list_for_each_entry(hvcsd, &hvcs_structs, next) {
-			spin_lock_irqsave(&hvcsd->lock, flags);
-			if (hvcsd->index == index) {
-				kref_get(&hvcsd->kref);
-				spin_unlock_irqrestore(&hvcsd->lock, flags);
-				spin_unlock(&hvcs_structs_lock);
-				return hvcsd;
-			}
+	list_for_each_entry(hvcsd, &hvcs_structs, next) {
+		spin_lock_irqsave(&hvcsd->lock, flags);
+		if (hvcsd->index == index) {
+			kref_get(&hvcsd->kref);
 			spin_unlock_irqrestore(&hvcsd->lock, flags);
+			spin_unlock(&hvcs_structs_lock);
+			return hvcsd;
 		}
-		hvcsd = NULL;
+		spin_unlock_irqrestore(&hvcsd->lock, flags);
 	}
-
 	spin_unlock(&hvcs_structs_lock);
-	return hvcsd;
+
+	return NULL;
 }
 
 /*
@@ -1203,7 +1199,7 @@
 {
 	struct hvcs_struct *hvcsd;
 	unsigned long flags;
-	int irq = NO_IRQ;
+	int irq;
 
 	/*
 	 * Is someone trying to close the file associated with this device after
@@ -1264,7 +1260,7 @@
 	struct hvcs_struct *hvcsd = tty->driver_data;
 	unsigned long flags;
 	int temp_open_count;
-	int irq = NO_IRQ;
+	int irq;
 
 	spin_lock_irqsave(&hvcsd->lock, flags);
 	/* Preserve this so that we know how many kref refs to put */
@@ -1499,8 +1495,6 @@
 		goto index_fail;
 	}
 
-	hvcs_tty_driver->owner = THIS_MODULE;
-
 	hvcs_tty_driver->driver_name = hvcs_driver_name;
 	hvcs_tty_driver->name = hvcs_device_node;
 
diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c
index cdfa3e0..a7488b7 100644
--- a/drivers/tty/hvc/hvsi.c
+++ b/drivers/tty/hvc/hvsi.c
@@ -737,14 +737,11 @@
 {
 	struct hvsi_struct *hp;
 	unsigned long flags;
-	int line = tty->index;
 	int ret;
 
 	pr_debug("%s\n", __func__);
 
-	if (line < 0 || line >= hvsi_count)
-		return -ENODEV;
-	hp = &hvsi_ports[line];
+	hp = &hvsi_ports[tty->index];
 
 	tty->driver_data = hp;
 
@@ -1088,7 +1085,6 @@
 	if (!hvsi_driver)
 		return -ENOMEM;
 
-	hvsi_driver->owner = THIS_MODULE;
 	hvsi_driver->driver_name = "hvsi";
 	hvsi_driver->name = "hvsi";
 	hvsi_driver->major = HVSI_MAJOR;
@@ -1237,7 +1233,7 @@
 		hp->state = HVSI_CLOSED;
 		hp->vtermno = *vtermno;
 		hp->virq = irq_create_mapping(NULL, irq[0]);
-		if (hp->virq == NO_IRQ) {
+		if (hp->virq == 0) {
 			printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
 				__func__, irq[0]);
 			continue;
diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c
index ef92869..77ceaa9 100644
--- a/drivers/tty/ipwireless/tty.c
+++ b/drivers/tty/ipwireless/tty.c
@@ -90,33 +90,23 @@
 	       tty->index);
 }
 
-static struct ipw_tty *get_tty(int minor)
+static struct ipw_tty *get_tty(int index)
 {
-	if (minor < ipw_tty_driver->minor_start
-			|| minor >= ipw_tty_driver->minor_start +
-			IPWIRELESS_PCMCIA_MINORS)
+	/*
+	 * The 'ras_raw' channel is only available when 'loopback' mode
+	 * is enabled.
+	 * Number of minor starts with 16 (_RANGE * _RAS_RAW).
+	 */
+	if (!ipwireless_loopback && index >=
+			 IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW)
 		return NULL;
-	else {
-		int minor_offset = minor - ipw_tty_driver->minor_start;
 
-		/*
-		 * The 'ras_raw' channel is only available when 'loopback' mode
-		 * is enabled.
-		 * Number of minor starts with 16 (_RANGE * _RAS_RAW).
-		 */
-		if (!ipwireless_loopback &&
-				minor_offset >=
-				 IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW)
-			return NULL;
-
-		return ttys[minor_offset];
-	}
+	return ttys[index];
 }
 
 static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
 {
-	int minor = linux_tty->index;
-	struct ipw_tty *tty = get_tty(minor);
+	struct ipw_tty *tty = get_tty(linux_tty->index);
 
 	if (!tty)
 		return -ENODEV;
@@ -510,7 +500,7 @@
 		ipwireless_associate_network_tty(network,
 						 secondary_channel_idx,
 						 ttys[j]);
-	if (get_tty(j + ipw_tty_driver->minor_start) == ttys[j])
+	if (get_tty(j) == ttys[j])
 		report_registering(ttys[j]);
 	return 0;
 }
@@ -570,7 +560,7 @@
 
 		if (ttyj) {
 			mutex_lock(&ttyj->ipw_tty_mutex);
-			if (get_tty(j + ipw_tty_driver->minor_start) == ttyj)
+			if (get_tty(j) == ttyj)
 				report_deregistering(ttyj);
 			ttyj->closing = 1;
 			if (ttyj->linux_tty != NULL) {
@@ -614,7 +604,6 @@
 	if (!ipw_tty_driver)
 		return -ENOMEM;
 
-	ipw_tty_driver->owner = THIS_MODULE;
 	ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME;
 	ipw_tty_driver->name = "ttyIPWp";
 	ipw_tty_driver->major = 0;
diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c
index e5c295a..03c1497 100644
--- a/drivers/tty/isicom.c
+++ b/drivers/tty/isicom.c
@@ -849,8 +849,6 @@
 	unsigned int board;
 	int line = tty->index;
 
-	if (line < 0 || line > PORT_COUNT-1)
-		return NULL;
 	board = BOARD(line);
 	card = &isi_card[board];
 
@@ -1678,7 +1676,6 @@
 		goto error;
 	}
 
-	isicom_normal->owner			= THIS_MODULE;
 	isicom_normal->name 			= "ttyM";
 	isicom_normal->major			= ISICOM_NMAJOR;
 	isicom_normal->minor_start		= 0;
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index d15a071..8a8d044 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -1036,7 +1036,6 @@
 	if (!moxaDriver)
 		return -ENOMEM;
 
-	moxaDriver->owner = THIS_MODULE;
 	moxaDriver->name = "ttyMX";
 	moxaDriver->major = ttymajor;
 	moxaDriver->minor_start = 0;
@@ -1331,7 +1330,7 @@
 	if (ch == NULL)
 		return;
 
-	if (!(ch->statusflags & TXSTOPPED))
+	if (!test_bit(TXSTOPPED, &ch->statusflags))
 		return;
 
 	MoxaPortTxEnable(ch);
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 8998d52..17ff377 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -1010,8 +1010,6 @@
 	line = tty->index;
 	if (line == MXSER_PORTS)
 		return 0;
-	if (line < 0 || line > MXSER_PORTS)
-		return -ENODEV;
 	info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD];
 	if (!info->ioaddr)
 		return -ENODEV;
@@ -2658,12 +2656,9 @@
 		MXSER_VERSION);
 
 	/* Initialize the tty_driver structure */
-	mxvar_sdriver->owner = THIS_MODULE;
-	mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
 	mxvar_sdriver->name = "ttyMI";
 	mxvar_sdriver->major = ttymajor;
 	mxvar_sdriver->minor_start = 0;
-	mxvar_sdriver->num = MXSER_PORTS + 1;
 	mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
 	mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
 	mxvar_sdriver->init_termios = tty_std_termios;
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index fc7bbba..c43b683 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -3120,7 +3120,6 @@
 		pr_err("gsm_init: tty allocation failed.\n");
 		return -EINVAL;
 	}
-	gsm_tty_driver->owner	= THIS_MODULE;
 	gsm_tty_driver->driver_name	= "gsmtty";
 	gsm_tty_driver->name		= "gsmtty";
 	gsm_tty_driver->major		= 0;	/* Dynamic */
diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c
index fd347ff..e7592f9 100644
--- a/drivers/tty/nozomi.c
+++ b/drivers/tty/nozomi.c
@@ -1602,13 +1602,9 @@
 	int ret;
 	if (!port || !dc || dc->state != NOZOMI_STATE_READY)
 		return -ENODEV;
-	ret = tty_init_termios(tty);
-	if (ret == 0) {
-		tty_driver_kref_get(driver);
-		tty->count++;
+	ret = tty_standard_install(driver, tty);
+	if (ret == 0)
 		tty->driver_data = port;
-		driver->ttys[tty->index] = tty;
-	}
 	return ret;
 }
 
@@ -1920,7 +1916,6 @@
 	if (!ntty_driver)
 		return -ENOMEM;
 
-	ntty_driver->owner = THIS_MODULE;
 	ntty_driver->driver_name = NOZOMI_NAME_TTY;
 	ntty_driver->name = "noz";
 	ntty_driver->major = 0;
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index d8653ab..f96ecae 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -21,7 +21,6 @@
 #include <linux/major.h>
 #include <linux/mm.h>
 #include <linux/init.h>
-#include <linux/sysctl.h>
 #include <linux/device.h>
 #include <linux/uaccess.h>
 #include <linux/bitops.h>
@@ -394,7 +393,6 @@
 	if (!pty_slave_driver)
 		panic("Couldn't allocate pty slave driver");
 
-	pty_driver->owner = THIS_MODULE;
 	pty_driver->driver_name = "pty_master";
 	pty_driver->name = "pty";
 	pty_driver->major = PTY_MASTER_MAJOR;
@@ -412,7 +410,6 @@
 	pty_driver->other = pty_slave_driver;
 	tty_set_operations(pty_driver, &master_pty_ops_bsd);
 
-	pty_slave_driver->owner = THIS_MODULE;
 	pty_slave_driver->driver_name = "pty_slave";
 	pty_slave_driver->name = "ttyp";
 	pty_slave_driver->major = PTY_SLAVE_MAJOR;
@@ -439,55 +436,9 @@
 
 /* Unix98 devices */
 #ifdef CONFIG_UNIX98_PTYS
-/*
- * sysctl support for setting limits on the number of Unix98 ptys allocated.
- * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
- */
-int pty_limit = NR_UNIX98_PTY_DEFAULT;
-static int pty_limit_min;
-static int pty_limit_max = NR_UNIX98_PTY_MAX;
-static int pty_count;
 
 static struct cdev ptmx_cdev;
 
-static struct ctl_table pty_table[] = {
-	{
-		.procname	= "max",
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.data		= &pty_limit,
-		.proc_handler	= proc_dointvec_minmax,
-		.extra1		= &pty_limit_min,
-		.extra2		= &pty_limit_max,
-	}, {
-		.procname	= "nr",
-		.maxlen		= sizeof(int),
-		.mode		= 0444,
-		.data		= &pty_count,
-		.proc_handler	= proc_dointvec,
-	}, 
-	{}
-};
-
-static struct ctl_table pty_kern_table[] = {
-	{
-		.procname	= "pty",
-		.mode		= 0555,
-		.child		= pty_table,
-	},
-	{}
-};
-
-static struct ctl_table pty_root_table[] = {
-	{
-		.procname	= "kernel",
-		.mode		= 0555,
-		.child		= pty_kern_table,
-	},
-	{}
-};
-
-
 static int pty_unix98_ioctl(struct tty_struct *tty,
 			    unsigned int cmd, unsigned long arg)
 {
@@ -515,10 +466,8 @@
 static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
 		struct inode *ptm_inode, int idx)
 {
-	struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
-	if (tty)
-		tty = tty->link;
-	return tty;
+	/* Master must be open via /dev/ptmx */
+	return ERR_PTR(-EIO);
 }
 
 /**
@@ -589,7 +538,6 @@
 	 */
 	tty_driver_kref_get(driver);
 	tty->count++;
-	pty_count++;
 	return 0;
 err_free_mem:
 	deinitialize_tty_struct(o_tty);
@@ -603,7 +551,6 @@
 
 static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
 {
-	pty_count--;
 }
 
 static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
@@ -677,7 +624,7 @@
 
 	mutex_lock(&tty_mutex);
 	tty_lock();
-	tty = tty_init_dev(ptm_driver, index, 1);
+	tty = tty_init_dev(ptm_driver, index);
 	mutex_unlock(&tty_mutex);
 
 	if (IS_ERR(tty)) {
@@ -722,7 +669,6 @@
 	if (!pts_driver)
 		panic("Couldn't allocate Unix98 pts driver");
 
-	ptm_driver->owner = THIS_MODULE;
 	ptm_driver->driver_name = "pty_master";
 	ptm_driver->name = "ptm";
 	ptm_driver->major = UNIX98_PTY_MASTER_MAJOR;
@@ -741,7 +687,6 @@
 	ptm_driver->other = pts_driver;
 	tty_set_operations(ptm_driver, &ptm_unix98_ops);
 
-	pts_driver->owner = THIS_MODULE;
 	pts_driver->driver_name = "pty_slave";
 	pts_driver->name = "pts";
 	pts_driver->major = UNIX98_PTY_SLAVE_MAJOR;
@@ -762,8 +707,6 @@
 	if (tty_register_driver(pts_driver))
 		panic("Couldn't register Unix98 pts driver");
 
-	register_sysctl_table(pty_root_table);
-
 	/* Now create the /dev/ptmx special device */
 	tty_default_fops(&ptmx_fops);
 	ptmx_fops.open = ptmx_open;
diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c
index de88aa5..777d5f9 100644
--- a/drivers/tty/rocket.c
+++ b/drivers/tty/rocket.c
@@ -892,12 +892,12 @@
 {
 	struct r_port *info;
 	struct tty_port *port;
-	int line = 0, retval;
+	int retval;
 	CHANNEL_t *cp;
 	unsigned long page;
 
-	line = tty->index;
-	if (line < 0 || line >= MAX_RP_PORTS || ((info = rp_table[line]) == NULL))
+	info = rp_table[tty->index];
+	if (info == NULL)
 		return -ENXIO;
 	port = &info->port;
 	
@@ -2277,7 +2277,6 @@
 	 * driver with the tty layer.
 	 */
 
-	rocket_driver->owner = THIS_MODULE;
 	rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV;
 	rocket_driver->name = "ttyR";
 	rocket_driver->driver_name = "Comtrol RocketPort";
diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c
index 1b37626..f899996 100644
--- a/drivers/tty/serial/21285.c
+++ b/drivers/tty/serial/21285.c
@@ -331,7 +331,7 @@
 	int ret = 0;
 	if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285)
 		ret = -EINVAL;
-	if (ser->irq != NO_IRQ)
+	if (ser->irq <= 0)
 		ret = -EINVAL;
 	if (ser->baud_base != port->uartclk / 16)
 		ret = -EINVAL;
@@ -360,7 +360,7 @@
 static struct uart_port serial21285_port = {
 	.mapbase	= 0x42000160,
 	.iotype		= UPIO_MEM,
-	.irq		= NO_IRQ,
+	.irq		= 0,
 	.fifosize	= 16,
 	.ops		= &serial21285_ops,
 	.flags		= UPF_BOOT_AUTOCONF,
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
index a88ef97..7398390 100644
--- a/drivers/tty/serial/68328serial.c
+++ b/drivers/tty/serial/68328serial.c
@@ -1190,14 +1190,9 @@
 int rs_open(struct tty_struct *tty, struct file * filp)
 {
 	struct m68k_serial	*info;
-	int 			retval, line;
+	int retval;
 
-	line = tty->index;
-	
-	if (line >= NR_PORTS || line < 0) /* we have exactly one */
-		return -ENODEV;
-
-	info = &m68k_soft[line];
+	info = &m68k_soft[tty->index];
 
 	if (serial_paranoia_check(info, tty->name, "rs_open"))
 		return -ENODEV;
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
index 9b7336f..5b149b4 100644
--- a/drivers/tty/serial/8250/8250.c
+++ b/drivers/tty/serial/8250/8250.c
@@ -38,16 +38,15 @@
 #include <linux/nmi.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
+#ifdef CONFIG_SPARC
+#include <linux/sunserialcore.h>
+#endif
 
 #include <asm/io.h>
 #include <asm/irq.h>
 
 #include "8250.h"
 
-#ifdef CONFIG_SPARC
-#include "../suncore.h"
-#endif
-
 /*
  * Configuration:
  *   share_irqs - whether we pass IRQF_SHARED to request_irq().  This option
@@ -86,13 +85,6 @@
 #define BOTH_EMPTY 	(UART_LSR_TEMT | UART_LSR_THRE)
 
 
-/*
- * We default to IRQ0 for the "no irq" hack.   Some
- * machine types want others as well - they're free
- * to redefine this in their header file.
- */
-#define is_real_interrupt(irq)	((irq) != 0)
-
 #ifdef CONFIG_SERIAL_8250_DETECT_IRQ
 #define CONFIG_SERIAL_DETECT_IRQ 1
 #endif
@@ -475,9 +467,8 @@
 }
 
 static void
-serial_out_sync(struct uart_8250_port *up, int offset, int value)
+serial_port_out_sync(struct uart_port *p, int offset, int value)
 {
-	struct uart_port *p = &up->port;
 	switch (p->iotype) {
 	case UPIO_MEM:
 	case UPIO_MEM32:
@@ -490,30 +481,17 @@
 	}
 }
 
-#define serial_in(up, offset)		\
-	(up->port.serial_in(&(up)->port, (offset)))
-#define serial_out(up, offset, value)	\
-	(up->port.serial_out(&(up)->port, (offset), (value)))
-/*
- * We used to support using pause I/O for certain machines.  We
- * haven't supported this for a while, but just in case it's badly
- * needed for certain old 386 machines, I've left these #define's
- * in....
- */
-#define serial_inp(up, offset)		serial_in(up, offset)
-#define serial_outp(up, offset, value)	serial_out(up, offset, value)
-
 /* Uart divisor latch read */
 static inline int _serial_dl_read(struct uart_8250_port *up)
 {
-	return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8;
+	return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;
 }
 
 /* Uart divisor latch write */
 static inline void _serial_dl_write(struct uart_8250_port *up, int value)
 {
-	serial_outp(up, UART_DLL, value & 0xff);
-	serial_outp(up, UART_DLM, value >> 8 & 0xff);
+	serial_out(up, UART_DLL, value & 0xff);
+	serial_out(up, UART_DLM, value >> 8 & 0xff);
 }
 
 #if defined(CONFIG_MIPS_ALCHEMY)
@@ -583,10 +561,10 @@
 static void serial8250_clear_fifos(struct uart_8250_port *p)
 {
 	if (p->capabilities & UART_CAP_FIFO) {
-		serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO);
-		serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO |
+		serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO);
+		serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO |
 			       UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-		serial_outp(p, UART_FCR, 0);
+		serial_out(p, UART_FCR, 0);
 	}
 }
 
@@ -599,15 +577,15 @@
 {
 	if (p->capabilities & UART_CAP_SLEEP) {
 		if (p->capabilities & UART_CAP_EFR) {
-			serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B);
-			serial_outp(p, UART_EFR, UART_EFR_ECB);
-			serial_outp(p, UART_LCR, 0);
+			serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B);
+			serial_out(p, UART_EFR, UART_EFR_ECB);
+			serial_out(p, UART_LCR, 0);
 		}
-		serial_outp(p, UART_IER, sleep ? UART_IERX_SLEEP : 0);
+		serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0);
 		if (p->capabilities & UART_CAP_EFR) {
-			serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B);
-			serial_outp(p, UART_EFR, 0);
-			serial_outp(p, UART_LCR, 0);
+			serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B);
+			serial_out(p, UART_EFR, 0);
+			serial_out(p, UART_LCR, 0);
 		}
 	}
 }
@@ -622,12 +600,12 @@
 	unsigned char mode;
 	int result;
 
-	mode = serial_inp(up, UART_RSA_MSR);
+	mode = serial_in(up, UART_RSA_MSR);
 	result = mode & UART_RSA_MSR_FIFO;
 
 	if (!result) {
-		serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
-		mode = serial_inp(up, UART_RSA_MSR);
+		serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
+		mode = serial_in(up, UART_RSA_MSR);
 		result = mode & UART_RSA_MSR_FIFO;
 	}
 
@@ -646,7 +624,7 @@
 			spin_unlock_irq(&up->port.lock);
 		}
 		if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
-			serial_outp(up, UART_RSA_FRR, 0);
+			serial_out(up, UART_RSA_FRR, 0);
 	}
 }
 
@@ -665,12 +643,12 @@
 	    up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
 		spin_lock_irq(&up->port.lock);
 
-		mode = serial_inp(up, UART_RSA_MSR);
+		mode = serial_in(up, UART_RSA_MSR);
 		result = !(mode & UART_RSA_MSR_FIFO);
 
 		if (!result) {
-			serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
-			mode = serial_inp(up, UART_RSA_MSR);
+			serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
+			mode = serial_in(up, UART_RSA_MSR);
 			result = !(mode & UART_RSA_MSR_FIFO);
 		}
 
@@ -691,28 +669,28 @@
 	unsigned short old_dl;
 	int count;
 
-	old_lcr = serial_inp(up, UART_LCR);
-	serial_outp(up, UART_LCR, 0);
-	old_fcr = serial_inp(up, UART_FCR);
-	old_mcr = serial_inp(up, UART_MCR);
-	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+	old_lcr = serial_in(up, UART_LCR);
+	serial_out(up, UART_LCR, 0);
+	old_fcr = serial_in(up, UART_FCR);
+	old_mcr = serial_in(up, UART_MCR);
+	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
 		    UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-	serial_outp(up, UART_MCR, UART_MCR_LOOP);
-	serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
+	serial_out(up, UART_MCR, UART_MCR_LOOP);
+	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
 	old_dl = serial_dl_read(up);
 	serial_dl_write(up, 0x0001);
-	serial_outp(up, UART_LCR, 0x03);
+	serial_out(up, UART_LCR, 0x03);
 	for (count = 0; count < 256; count++)
-		serial_outp(up, UART_TX, count);
+		serial_out(up, UART_TX, count);
 	mdelay(20);/* FIXME - schedule_timeout */
-	for (count = 0; (serial_inp(up, UART_LSR) & UART_LSR_DR) &&
+	for (count = 0; (serial_in(up, UART_LSR) & UART_LSR_DR) &&
 	     (count < 256); count++)
-		serial_inp(up, UART_RX);
-	serial_outp(up, UART_FCR, old_fcr);
-	serial_outp(up, UART_MCR, old_mcr);
-	serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
+		serial_in(up, UART_RX);
+	serial_out(up, UART_FCR, old_fcr);
+	serial_out(up, UART_MCR, old_mcr);
+	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
 	serial_dl_write(up, old_dl);
-	serial_outp(up, UART_LCR, old_lcr);
+	serial_out(up, UART_LCR, old_lcr);
 
 	return count;
 }
@@ -727,20 +705,20 @@
 	unsigned char old_dll, old_dlm, old_lcr;
 	unsigned int id;
 
-	old_lcr = serial_inp(p, UART_LCR);
-	serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_A);
+	old_lcr = serial_in(p, UART_LCR);
+	serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A);
 
-	old_dll = serial_inp(p, UART_DLL);
-	old_dlm = serial_inp(p, UART_DLM);
+	old_dll = serial_in(p, UART_DLL);
+	old_dlm = serial_in(p, UART_DLM);
 
-	serial_outp(p, UART_DLL, 0);
-	serial_outp(p, UART_DLM, 0);
+	serial_out(p, UART_DLL, 0);
+	serial_out(p, UART_DLM, 0);
 
-	id = serial_inp(p, UART_DLL) | serial_inp(p, UART_DLM) << 8;
+	id = serial_in(p, UART_DLL) | serial_in(p, UART_DLM) << 8;
 
-	serial_outp(p, UART_DLL, old_dll);
-	serial_outp(p, UART_DLM, old_dlm);
-	serial_outp(p, UART_LCR, old_lcr);
+	serial_out(p, UART_DLL, old_dll);
+	serial_out(p, UART_DLM, old_dlm);
+	serial_out(p, UART_LCR, old_lcr);
 
 	return id;
 }
@@ -850,11 +828,11 @@
 	up->port.type = PORT_8250;
 
 	scratch = serial_in(up, UART_SCR);
-	serial_outp(up, UART_SCR, 0xa5);
+	serial_out(up, UART_SCR, 0xa5);
 	status1 = serial_in(up, UART_SCR);
-	serial_outp(up, UART_SCR, 0x5a);
+	serial_out(up, UART_SCR, 0x5a);
 	status2 = serial_in(up, UART_SCR);
-	serial_outp(up, UART_SCR, scratch);
+	serial_out(up, UART_SCR, scratch);
 
 	if (status1 == 0xa5 && status2 == 0x5a)
 		up->port.type = PORT_16450;
@@ -885,7 +863,7 @@
 	} else {
 		status &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
 		status |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
-		serial_outp(up, 0x04, status);
+		serial_out(up, 0x04, status);
 	}
 	return 1;
 }
@@ -908,9 +886,9 @@
 	 * Check for presence of the EFR when DLAB is set.
 	 * Only ST16C650V1 UARTs pass this test.
 	 */
-	serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
+	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
 	if (serial_in(up, UART_EFR) == 0) {
-		serial_outp(up, UART_EFR, 0xA8);
+		serial_out(up, UART_EFR, 0xA8);
 		if (serial_in(up, UART_EFR) != 0) {
 			DEBUG_AUTOCONF("EFRv1 ");
 			up->port.type = PORT_16650;
@@ -918,7 +896,7 @@
 		} else {
 			DEBUG_AUTOCONF("Motorola 8xxx DUART ");
 		}
-		serial_outp(up, UART_EFR, 0);
+		serial_out(up, UART_EFR, 0);
 		return;
 	}
 
@@ -926,7 +904,7 @@
 	 * Maybe it requires 0xbf to be written to the LCR.
 	 * (other ST16C650V2 UARTs, TI16C752A, etc)
 	 */
-	serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
 	if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) {
 		DEBUG_AUTOCONF("EFRv2 ");
 		autoconfig_has_efr(up);
@@ -940,23 +918,23 @@
 	 * switch back to bank 2, read it from EXCR1 again and check
 	 * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2
 	 */
-	serial_outp(up, UART_LCR, 0);
+	serial_out(up, UART_LCR, 0);
 	status1 = serial_in(up, UART_MCR);
-	serial_outp(up, UART_LCR, 0xE0);
+	serial_out(up, UART_LCR, 0xE0);
 	status2 = serial_in(up, 0x02); /* EXCR1 */
 
 	if (!((status2 ^ status1) & UART_MCR_LOOP)) {
-		serial_outp(up, UART_LCR, 0);
-		serial_outp(up, UART_MCR, status1 ^ UART_MCR_LOOP);
-		serial_outp(up, UART_LCR, 0xE0);
+		serial_out(up, UART_LCR, 0);
+		serial_out(up, UART_MCR, status1 ^ UART_MCR_LOOP);
+		serial_out(up, UART_LCR, 0xE0);
 		status2 = serial_in(up, 0x02); /* EXCR1 */
-		serial_outp(up, UART_LCR, 0);
-		serial_outp(up, UART_MCR, status1);
+		serial_out(up, UART_LCR, 0);
+		serial_out(up, UART_MCR, status1);
 
 		if ((status2 ^ status1) & UART_MCR_LOOP) {
 			unsigned short quot;
 
-			serial_outp(up, UART_LCR, 0xE0);
+			serial_out(up, UART_LCR, 0xE0);
 
 			quot = serial_dl_read(up);
 			quot <<= 3;
@@ -964,7 +942,7 @@
 			if (ns16550a_goto_highspeed(up))
 				serial_dl_write(up, quot);
 
-			serial_outp(up, UART_LCR, 0);
+			serial_out(up, UART_LCR, 0);
 
 			up->port.uartclk = 921600*16;
 			up->port.type = PORT_NS16550A;
@@ -979,15 +957,15 @@
 	 * Try setting it with and without DLAB set.  Cheap clones
 	 * set bit 5 without DLAB set.
 	 */
-	serial_outp(up, UART_LCR, 0);
-	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+	serial_out(up, UART_LCR, 0);
+	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
 	status1 = serial_in(up, UART_IIR) >> 5;
-	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-	serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
-	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
 	status2 = serial_in(up, UART_IIR) >> 5;
-	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-	serial_outp(up, UART_LCR, 0);
+	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+	serial_out(up, UART_LCR, 0);
 
 	DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2);
 
@@ -1006,13 +984,13 @@
 	 * already a 1 and maybe locked there before we even start start.
 	 */
 	iersave = serial_in(up, UART_IER);
-	serial_outp(up, UART_IER, iersave & ~UART_IER_UUE);
+	serial_out(up, UART_IER, iersave & ~UART_IER_UUE);
 	if (!(serial_in(up, UART_IER) & UART_IER_UUE)) {
 		/*
 		 * OK it's in a known zero state, try writing and reading
 		 * without disturbing the current state of the other bits.
 		 */
-		serial_outp(up, UART_IER, iersave | UART_IER_UUE);
+		serial_out(up, UART_IER, iersave | UART_IER_UUE);
 		if (serial_in(up, UART_IER) & UART_IER_UUE) {
 			/*
 			 * It's an Xscale.
@@ -1030,7 +1008,7 @@
 		 */
 		DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 ");
 	}
-	serial_outp(up, UART_IER, iersave);
+	serial_out(up, UART_IER, iersave);
 
 	/*
 	 * Exar uarts have EFR in a weird location
@@ -1061,24 +1039,25 @@
 {
 	unsigned char status1, scratch, scratch2, scratch3;
 	unsigned char save_lcr, save_mcr;
+	struct uart_port *port = &up->port;
 	unsigned long flags;
 
-	if (!up->port.iobase && !up->port.mapbase && !up->port.membase)
+	if (!port->iobase && !port->mapbase && !port->membase)
 		return;
 
 	DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ",
-		       serial_index(&up->port), up->port.iobase, up->port.membase);
+		       serial_index(port), port->iobase, port->membase);
 
 	/*
 	 * We really do need global IRQs disabled here - we're going to
 	 * be frobbing the chips IRQ enable register to see if it exists.
 	 */
-	spin_lock_irqsave(&up->port.lock, flags);
+	spin_lock_irqsave(&port->lock, flags);
 
 	up->capabilities = 0;
 	up->bugs = 0;
 
-	if (!(up->port.flags & UPF_BUGGY_UART)) {
+	if (!(port->flags & UPF_BUGGY_UART)) {
 		/*
 		 * Do a simple existence test first; if we fail this,
 		 * there's no point trying anything else.
@@ -1092,8 +1071,8 @@
 		 * Note: this is safe as long as MCR bit 4 is clear
 		 * and the device is in "PC" mode.
 		 */
-		scratch = serial_inp(up, UART_IER);
-		serial_outp(up, UART_IER, 0);
+		scratch = serial_in(up, UART_IER);
+		serial_out(up, UART_IER, 0);
 #ifdef __i386__
 		outb(0xff, 0x080);
 #endif
@@ -1101,13 +1080,13 @@
 		 * Mask out IER[7:4] bits for test as some UARTs (e.g. TL
 		 * 16C754B) allow only to modify them if an EFR bit is set.
 		 */
-		scratch2 = serial_inp(up, UART_IER) & 0x0f;
-		serial_outp(up, UART_IER, 0x0F);
+		scratch2 = serial_in(up, UART_IER) & 0x0f;
+		serial_out(up, UART_IER, 0x0F);
 #ifdef __i386__
 		outb(0, 0x080);
 #endif
-		scratch3 = serial_inp(up, UART_IER) & 0x0f;
-		serial_outp(up, UART_IER, scratch);
+		scratch3 = serial_in(up, UART_IER) & 0x0f;
+		serial_out(up, UART_IER, scratch);
 		if (scratch2 != 0 || scratch3 != 0x0F) {
 			/*
 			 * We failed; there's nothing here
@@ -1130,10 +1109,10 @@
 	 * manufacturer would be stupid enough to design a board
 	 * that conflicts with COM 1-4 --- we hope!
 	 */
-	if (!(up->port.flags & UPF_SKIP_TEST)) {
-		serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A);
-		status1 = serial_inp(up, UART_MSR) & 0xF0;
-		serial_outp(up, UART_MCR, save_mcr);
+	if (!(port->flags & UPF_SKIP_TEST)) {
+		serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A);
+		status1 = serial_in(up, UART_MSR) & 0xF0;
+		serial_out(up, UART_MCR, save_mcr);
 		if (status1 != 0x90) {
 			DEBUG_AUTOCONF("LOOP test failed (%02x) ",
 				       status1);
@@ -1150,11 +1129,11 @@
 	 * We also initialise the EFR (if any) to zero for later.  The
 	 * EFR occupies the same register location as the FCR and IIR.
 	 */
-	serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
-	serial_outp(up, UART_EFR, 0);
-	serial_outp(up, UART_LCR, 0);
+	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+	serial_out(up, UART_EFR, 0);
+	serial_out(up, UART_LCR, 0);
 
-	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
 	scratch = serial_in(up, UART_IIR) >> 6;
 
 	DEBUG_AUTOCONF("iir=%d ", scratch);
@@ -1164,10 +1143,10 @@
 		autoconfig_8250(up);
 		break;
 	case 1:
-		up->port.type = PORT_UNKNOWN;
+		port->type = PORT_UNKNOWN;
 		break;
 	case 2:
-		up->port.type = PORT_16550;
+		port->type = PORT_16550;
 		break;
 	case 3:
 		autoconfig_16550a(up);
@@ -1178,102 +1157,102 @@
 	/*
 	 * Only probe for RSA ports if we got the region.
 	 */
-	if (up->port.type == PORT_16550A && probeflags & PROBE_RSA) {
+	if (port->type == PORT_16550A && probeflags & PROBE_RSA) {
 		int i;
 
 		for (i = 0 ; i < probe_rsa_count; ++i) {
-			if (probe_rsa[i] == up->port.iobase &&
-			    __enable_rsa(up)) {
-				up->port.type = PORT_RSA;
+			if (probe_rsa[i] == port->iobase && __enable_rsa(up)) {
+				port->type = PORT_RSA;
 				break;
 			}
 		}
 	}
 #endif
 
-	serial_outp(up, UART_LCR, save_lcr);
+	serial_out(up, UART_LCR, save_lcr);
 
-	if (up->capabilities != uart_config[up->port.type].flags) {
+	if (up->capabilities != uart_config[port->type].flags) {
 		printk(KERN_WARNING
 		       "ttyS%d: detected caps %08x should be %08x\n",
-		       serial_index(&up->port), up->capabilities,
-		       uart_config[up->port.type].flags);
+		       serial_index(port), up->capabilities,
+		       uart_config[port->type].flags);
 	}
 
-	up->port.fifosize = uart_config[up->port.type].fifo_size;
-	up->capabilities = uart_config[up->port.type].flags;
-	up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
+	port->fifosize = uart_config[up->port.type].fifo_size;
+	up->capabilities = uart_config[port->type].flags;
+	up->tx_loadsz = uart_config[port->type].tx_loadsz;
 
-	if (up->port.type == PORT_UNKNOWN)
+	if (port->type == PORT_UNKNOWN)
 		goto out;
 
 	/*
 	 * Reset the UART.
 	 */
 #ifdef CONFIG_SERIAL_8250_RSA
-	if (up->port.type == PORT_RSA)
-		serial_outp(up, UART_RSA_FRR, 0);
+	if (port->type == PORT_RSA)
+		serial_out(up, UART_RSA_FRR, 0);
 #endif
-	serial_outp(up, UART_MCR, save_mcr);
+	serial_out(up, UART_MCR, save_mcr);
 	serial8250_clear_fifos(up);
 	serial_in(up, UART_RX);
 	if (up->capabilities & UART_CAP_UUE)
-		serial_outp(up, UART_IER, UART_IER_UUE);
+		serial_out(up, UART_IER, UART_IER_UUE);
 	else
-		serial_outp(up, UART_IER, 0);
+		serial_out(up, UART_IER, 0);
 
  out:
-	spin_unlock_irqrestore(&up->port.lock, flags);
-	DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);
+	spin_unlock_irqrestore(&port->lock, flags);
+	DEBUG_AUTOCONF("type=%s\n", uart_config[port->type].name);
 }
 
 static void autoconfig_irq(struct uart_8250_port *up)
 {
+	struct uart_port *port = &up->port;
 	unsigned char save_mcr, save_ier;
 	unsigned char save_ICP = 0;
 	unsigned int ICP = 0;
 	unsigned long irqs;
 	int irq;
 
-	if (up->port.flags & UPF_FOURPORT) {
-		ICP = (up->port.iobase & 0xfe0) | 0x1f;
+	if (port->flags & UPF_FOURPORT) {
+		ICP = (port->iobase & 0xfe0) | 0x1f;
 		save_ICP = inb_p(ICP);
 		outb_p(0x80, ICP);
-		(void) inb_p(ICP);
+		inb_p(ICP);
 	}
 
 	/* forget possible initially masked and pending IRQ */
 	probe_irq_off(probe_irq_on());
-	save_mcr = serial_inp(up, UART_MCR);
-	save_ier = serial_inp(up, UART_IER);
-	serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
+	save_mcr = serial_in(up, UART_MCR);
+	save_ier = serial_in(up, UART_IER);
+	serial_out(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
 
 	irqs = probe_irq_on();
-	serial_outp(up, UART_MCR, 0);
+	serial_out(up, UART_MCR, 0);
 	udelay(10);
-	if (up->port.flags & UPF_FOURPORT) {
-		serial_outp(up, UART_MCR,
+	if (port->flags & UPF_FOURPORT) {
+		serial_out(up, UART_MCR,
 			    UART_MCR_DTR | UART_MCR_RTS);
 	} else {
-		serial_outp(up, UART_MCR,
+		serial_out(up, UART_MCR,
 			    UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
 	}
-	serial_outp(up, UART_IER, 0x0f);	/* enable all intrs */
-	(void)serial_inp(up, UART_LSR);
-	(void)serial_inp(up, UART_RX);
-	(void)serial_inp(up, UART_IIR);
-	(void)serial_inp(up, UART_MSR);
-	serial_outp(up, UART_TX, 0xFF);
+	serial_out(up, UART_IER, 0x0f);	/* enable all intrs */
+	serial_in(up, UART_LSR);
+	serial_in(up, UART_RX);
+	serial_in(up, UART_IIR);
+	serial_in(up, UART_MSR);
+	serial_out(up, UART_TX, 0xFF);
 	udelay(20);
 	irq = probe_irq_off(irqs);
 
-	serial_outp(up, UART_MCR, save_mcr);
-	serial_outp(up, UART_IER, save_ier);
+	serial_out(up, UART_MCR, save_mcr);
+	serial_out(up, UART_IER, save_ier);
 
-	if (up->port.flags & UPF_FOURPORT)
+	if (port->flags & UPF_FOURPORT)
 		outb_p(save_ICP, ICP);
 
-	up->port.irq = (irq > 0) ? irq : 0;
+	port->irq = (irq > 0) ? irq : 0;
 }
 
 static inline void __stop_tx(struct uart_8250_port *p)
@@ -1294,7 +1273,7 @@
 	/*
 	 * We really want to stop the transmitter from sending.
 	 */
-	if (up->port.type == PORT_16C950) {
+	if (port->type == PORT_16C950) {
 		up->acr |= UART_ACR_TXDIS;
 		serial_icr_write(up, UART_ACR, up->acr);
 	}
@@ -1307,13 +1286,13 @@
 
 	if (!(up->ier & UART_IER_THRI)) {
 		up->ier |= UART_IER_THRI;
-		serial_out(up, UART_IER, up->ier);
+		serial_port_out(port, UART_IER, up->ier);
 
 		if (up->bugs & UART_BUG_TXEN) {
 			unsigned char lsr;
 			lsr = serial_in(up, UART_LSR);
 			up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
-			if ((up->port.type == PORT_RM9000) ?
+			if ((port->type == PORT_RM9000) ?
 				(lsr & UART_LSR_THRE) :
 				(lsr & UART_LSR_TEMT))
 				serial8250_tx_chars(up);
@@ -1323,7 +1302,7 @@
 	/*
 	 * Re-enable the transmitter if we disabled it.
 	 */
-	if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) {
+	if (port->type == PORT_16C950 && up->acr & UART_ACR_TXDIS) {
 		up->acr &= ~UART_ACR_TXDIS;
 		serial_icr_write(up, UART_ACR, up->acr);
 	}
@@ -1336,7 +1315,7 @@
 
 	up->ier &= ~UART_IER_RLSI;
 	up->port.read_status_mask &= ~UART_LSR_DR;
-	serial_out(up, UART_IER, up->ier);
+	serial_port_out(port, UART_IER, up->ier);
 }
 
 static void serial8250_enable_ms(struct uart_port *port)
@@ -1349,7 +1328,7 @@
 		return;
 
 	up->ier |= UART_IER_MSI;
-	serial_out(up, UART_IER, up->ier);
+	serial_port_out(port, UART_IER, up->ier);
 }
 
 /*
@@ -1381,14 +1360,15 @@
 unsigned char
 serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
 {
-	struct tty_struct *tty = up->port.state->port.tty;
+	struct uart_port *port = &up->port;
+	struct tty_struct *tty = port->state->port.tty;
 	unsigned char ch;
 	int max_count = 256;
 	char flag;
 
 	do {
 		if (likely(lsr & UART_LSR_DR))
-			ch = serial_inp(up, UART_RX);
+			ch = serial_in(up, UART_RX);
 		else
 			/*
 			 * Intel 82571 has a Serial Over Lan device that will
@@ -1400,7 +1380,7 @@
 			ch = 0;
 
 		flag = TTY_NORMAL;
-		up->port.icount.rx++;
+		port->icount.rx++;
 
 		lsr |= up->lsr_saved_flags;
 		up->lsr_saved_flags = 0;
@@ -1411,12 +1391,12 @@
 			 */
 			if (lsr & UART_LSR_BI) {
 				lsr &= ~(UART_LSR_FE | UART_LSR_PE);
-				up->port.icount.brk++;
+				port->icount.brk++;
 				/*
 				 * If tegra port then clear the rx fifo to
 				 * accept another break/character.
 				 */
-				if (up->port.type == PORT_TEGRA)
+				if (port->type == PORT_TEGRA)
 					clear_rx_fifo(up);
 
 				/*
@@ -1425,19 +1405,19 @@
 				 * may get masked by ignore_status_mask
 				 * or read_status_mask.
 				 */
-				if (uart_handle_break(&up->port))
+				if (uart_handle_break(port))
 					goto ignore_char;
 			} else if (lsr & UART_LSR_PE)
-				up->port.icount.parity++;
+				port->icount.parity++;
 			else if (lsr & UART_LSR_FE)
-				up->port.icount.frame++;
+				port->icount.frame++;
 			if (lsr & UART_LSR_OE)
-				up->port.icount.overrun++;
+				port->icount.overrun++;
 
 			/*
 			 * Mask off conditions which should be ignored.
 			 */
-			lsr &= up->port.read_status_mask;
+			lsr &= port->read_status_mask;
 
 			if (lsr & UART_LSR_BI) {
 				DEBUG_INTR("handling break....");
@@ -1447,34 +1427,35 @@
 			else if (lsr & UART_LSR_FE)
 				flag = TTY_FRAME;
 		}
-		if (uart_handle_sysrq_char(&up->port, ch))
+		if (uart_handle_sysrq_char(port, ch))
 			goto ignore_char;
 
-		uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
+		uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
 
 ignore_char:
-		lsr = serial_inp(up, UART_LSR);
+		lsr = serial_in(up, UART_LSR);
 	} while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
-	spin_unlock(&up->port.lock);
+	spin_unlock(&port->lock);
 	tty_flip_buffer_push(tty);
-	spin_lock(&up->port.lock);
+	spin_lock(&port->lock);
 	return lsr;
 }
 EXPORT_SYMBOL_GPL(serial8250_rx_chars);
 
 void serial8250_tx_chars(struct uart_8250_port *up)
 {
-	struct circ_buf *xmit = &up->port.state->xmit;
+	struct uart_port *port = &up->port;
+	struct circ_buf *xmit = &port->state->xmit;
 	int count;
 
-	if (up->port.x_char) {
-		serial_outp(up, UART_TX, up->port.x_char);
-		up->port.icount.tx++;
-		up->port.x_char = 0;
+	if (port->x_char) {
+		serial_out(up, UART_TX, port->x_char);
+		port->icount.tx++;
+		port->x_char = 0;
 		return;
 	}
-	if (uart_tx_stopped(&up->port)) {
-		serial8250_stop_tx(&up->port);
+	if (uart_tx_stopped(port)) {
+		serial8250_stop_tx(port);
 		return;
 	}
 	if (uart_circ_empty(xmit)) {
@@ -1486,13 +1467,13 @@
 	do {
 		serial_out(up, UART_TX, xmit->buf[xmit->tail]);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-		up->port.icount.tx++;
+		port->icount.tx++;
 		if (uart_circ_empty(xmit))
 			break;
 	} while (--count > 0);
 
 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-		uart_write_wakeup(&up->port);
+		uart_write_wakeup(port);
 
 	DEBUG_INTR("THRE...");
 
@@ -1503,22 +1484,23 @@
 
 unsigned int serial8250_modem_status(struct uart_8250_port *up)
 {
+	struct uart_port *port = &up->port;
 	unsigned int status = serial_in(up, UART_MSR);
 
 	status |= up->msr_saved_flags;
 	up->msr_saved_flags = 0;
 	if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
-	    up->port.state != NULL) {
+	    port->state != NULL) {
 		if (status & UART_MSR_TERI)
-			up->port.icount.rng++;
+			port->icount.rng++;
 		if (status & UART_MSR_DDSR)
-			up->port.icount.dsr++;
+			port->icount.dsr++;
 		if (status & UART_MSR_DDCD)
-			uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+			uart_handle_dcd_change(port, status & UART_MSR_DCD);
 		if (status & UART_MSR_DCTS)
-			uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
+			uart_handle_cts_change(port, status & UART_MSR_CTS);
 
-		wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+		wake_up_interruptible(&port->state->port.delta_msr_wait);
 	}
 
 	return status;
@@ -1538,9 +1520,9 @@
 	if (iir & UART_IIR_NO_INT)
 		return 0;
 
-	spin_lock_irqsave(&up->port.lock, flags);
+	spin_lock_irqsave(&port->lock, flags);
 
-	status = serial_inp(up, UART_LSR);
+	status = serial_port_in(port, UART_LSR);
 
 	DEBUG_INTR("status = %x...", status);
 
@@ -1550,16 +1532,14 @@
 	if (status & UART_LSR_THRE)
 		serial8250_tx_chars(up);
 
-	spin_unlock_irqrestore(&up->port.lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
 	return 1;
 }
 EXPORT_SYMBOL_GPL(serial8250_handle_irq);
 
 static int serial8250_default_handle_irq(struct uart_port *port)
 {
-	struct uart_8250_port *up =
-		container_of(port, struct uart_8250_port, port);
-	unsigned int iir = serial_in(up, UART_IIR);
+	unsigned int iir = serial_port_in(port, UART_IIR);
 
 	return serial8250_handle_irq(port, iir);
 }
@@ -1750,7 +1730,7 @@
 	 * Must disable interrupts or else we risk racing with the interrupt
 	 * based handler.
 	 */
-	if (is_real_interrupt(up->port.irq)) {
+	if (up->port.irq) {
 		ier = serial_in(up, UART_IER);
 		serial_out(up, UART_IER, 0);
 	}
@@ -1775,7 +1755,7 @@
 	if (!(iir & UART_IIR_NO_INT))
 		serial8250_tx_chars(up);
 
-	if (is_real_interrupt(up->port.irq))
+	if (up->port.irq)
 		serial_out(up, UART_IER, ier);
 
 	spin_unlock_irqrestore(&up->port.lock, flags);
@@ -1792,10 +1772,10 @@
 	unsigned long flags;
 	unsigned int lsr;
 
-	spin_lock_irqsave(&up->port.lock, flags);
-	lsr = serial_in(up, UART_LSR);
+	spin_lock_irqsave(&port->lock, flags);
+	lsr = serial_port_in(port, UART_LSR);
 	up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
-	spin_unlock_irqrestore(&up->port.lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
 
 	return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;
 }
@@ -1840,7 +1820,7 @@
 
 	mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
 
-	serial_out(up, UART_MCR, mcr);
+	serial_port_out(port, UART_MCR, mcr);
 }
 
 static void serial8250_break_ctl(struct uart_port *port, int break_state)
@@ -1849,13 +1829,13 @@
 		container_of(port, struct uart_8250_port, port);
 	unsigned long flags;
 
-	spin_lock_irqsave(&up->port.lock, flags);
+	spin_lock_irqsave(&port->lock, flags);
 	if (break_state == -1)
 		up->lcr |= UART_LCR_SBC;
 	else
 		up->lcr &= ~UART_LCR_SBC;
-	serial_out(up, UART_LCR, up->lcr);
-	spin_unlock_irqrestore(&up->port.lock, flags);
+	serial_port_out(port, UART_LCR, up->lcr);
+	spin_unlock_irqrestore(&port->lock, flags);
 }
 
 /*
@@ -1900,14 +1880,12 @@
 
 static int serial8250_get_poll_char(struct uart_port *port)
 {
-	struct uart_8250_port *up =
-		container_of(port, struct uart_8250_port, port);
-	unsigned char lsr = serial_inp(up, UART_LSR);
+	unsigned char lsr = serial_port_in(port, UART_LSR);
 
 	if (!(lsr & UART_LSR_DR))
 		return NO_POLL_CHAR;
 
-	return serial_inp(up, UART_RX);
+	return serial_port_in(port, UART_RX);
 }
 
 
@@ -1921,21 +1899,21 @@
 	/*
 	 *	First save the IER then disable the interrupts
 	 */
-	ier = serial_in(up, UART_IER);
+	ier = serial_port_in(port, UART_IER);
 	if (up->capabilities & UART_CAP_UUE)
-		serial_out(up, UART_IER, UART_IER_UUE);
+		serial_port_out(port, UART_IER, UART_IER_UUE);
 	else
-		serial_out(up, UART_IER, 0);
+		serial_port_out(port, UART_IER, 0);
 
 	wait_for_xmitr(up, BOTH_EMPTY);
 	/*
 	 *	Send the character out.
 	 *	If a LF, also do CR...
 	 */
-	serial_out(up, UART_TX, c);
+	serial_port_out(port, UART_TX, c);
 	if (c == 10) {
 		wait_for_xmitr(up, BOTH_EMPTY);
-		serial_out(up, UART_TX, 13);
+		serial_port_out(port, UART_TX, 13);
 	}
 
 	/*
@@ -1943,7 +1921,7 @@
 	 *	and restore the IER
 	 */
 	wait_for_xmitr(up, BOTH_EMPTY);
-	serial_out(up, UART_IER, ier);
+	serial_port_out(port, UART_IER, ier);
 }
 
 #endif /* CONFIG_CONSOLE_POLL */
@@ -1956,25 +1934,25 @@
 	unsigned char lsr, iir;
 	int retval;
 
-	up->port.fifosize = uart_config[up->port.type].fifo_size;
+	port->fifosize = uart_config[up->port.type].fifo_size;
 	up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
 	up->capabilities = uart_config[up->port.type].flags;
 	up->mcr = 0;
 
-	if (up->port.iotype != up->cur_iotype)
+	if (port->iotype != up->cur_iotype)
 		set_io_from_upio(port);
 
-	if (up->port.type == PORT_16C950) {
+	if (port->type == PORT_16C950) {
 		/* Wake up and initialize UART */
 		up->acr = 0;
-		serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
-		serial_outp(up, UART_EFR, UART_EFR_ECB);
-		serial_outp(up, UART_IER, 0);
-		serial_outp(up, UART_LCR, 0);
+		serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B);
+		serial_port_out(port, UART_EFR, UART_EFR_ECB);
+		serial_port_out(port, UART_IER, 0);
+		serial_port_out(port, UART_LCR, 0);
 		serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
-		serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
-		serial_outp(up, UART_EFR, UART_EFR_ECB);
-		serial_outp(up, UART_LCR, 0);
+		serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B);
+		serial_port_out(port, UART_EFR, UART_EFR_ECB);
+		serial_port_out(port, UART_LCR, 0);
 	}
 
 #ifdef CONFIG_SERIAL_8250_RSA
@@ -1994,41 +1972,43 @@
 	/*
 	 * Clear the interrupt registers.
 	 */
-	(void) serial_inp(up, UART_LSR);
-	(void) serial_inp(up, UART_RX);
-	(void) serial_inp(up, UART_IIR);
-	(void) serial_inp(up, UART_MSR);
+	serial_port_in(port, UART_LSR);
+	serial_port_in(port, UART_RX);
+	serial_port_in(port, UART_IIR);
+	serial_port_in(port, UART_MSR);
 
 	/*
 	 * At this point, there's no way the LSR could still be 0xff;
 	 * if it is, then bail out, because there's likely no UART
 	 * here.
 	 */
-	if (!(up->port.flags & UPF_BUGGY_UART) &&
-	    (serial_inp(up, UART_LSR) == 0xff)) {
+	if (!(port->flags & UPF_BUGGY_UART) &&
+	    (serial_port_in(port, UART_LSR) == 0xff)) {
 		printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
-				   serial_index(&up->port));
+				   serial_index(port));
 		return -ENODEV;
 	}
 
 	/*
 	 * For a XR16C850, we need to set the trigger levels
 	 */
-	if (up->port.type == PORT_16850) {
+	if (port->type == PORT_16850) {
 		unsigned char fctr;
 
-		serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+		serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
 
-		fctr = serial_inp(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX);
-		serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX);
-		serial_outp(up, UART_TRG, UART_TRG_96);
-		serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX);
-		serial_outp(up, UART_TRG, UART_TRG_96);
+		fctr = serial_in(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX);
+		serial_port_out(port, UART_FCTR,
+				fctr | UART_FCTR_TRGD | UART_FCTR_RX);
+		serial_port_out(port, UART_TRG, UART_TRG_96);
+		serial_port_out(port, UART_FCTR,
+				fctr | UART_FCTR_TRGD | UART_FCTR_TX);
+		serial_port_out(port, UART_TRG, UART_TRG_96);
 
-		serial_outp(up, UART_LCR, 0);
+		serial_port_out(port, UART_LCR, 0);
 	}
 
-	if (is_real_interrupt(up->port.irq)) {
+	if (port->irq) {
 		unsigned char iir1;
 		/*
 		 * Test for UARTs that do not reassert THRE when the
@@ -2038,23 +2018,23 @@
 		 * the interrupt is enabled.  Delays are necessary to
 		 * allow register changes to become visible.
 		 */
-		spin_lock_irqsave(&up->port.lock, flags);
+		spin_lock_irqsave(&port->lock, flags);
 		if (up->port.irqflags & IRQF_SHARED)
-			disable_irq_nosync(up->port.irq);
+			disable_irq_nosync(port->irq);
 
 		wait_for_xmitr(up, UART_LSR_THRE);
-		serial_out_sync(up, UART_IER, UART_IER_THRI);
+		serial_port_out_sync(port, UART_IER, UART_IER_THRI);
 		udelay(1); /* allow THRE to set */
-		iir1 = serial_in(up, UART_IIR);
-		serial_out(up, UART_IER, 0);
-		serial_out_sync(up, UART_IER, UART_IER_THRI);
+		iir1 = serial_port_in(port, UART_IIR);
+		serial_port_out(port, UART_IER, 0);
+		serial_port_out_sync(port, UART_IER, UART_IER_THRI);
 		udelay(1); /* allow a working UART time to re-assert THRE */
-		iir = serial_in(up, UART_IIR);
-		serial_out(up, UART_IER, 0);
+		iir = serial_port_in(port, UART_IIR);
+		serial_port_out(port, UART_IER, 0);
 
-		if (up->port.irqflags & IRQF_SHARED)
-			enable_irq(up->port.irq);
-		spin_unlock_irqrestore(&up->port.lock, flags);
+		if (port->irqflags & IRQF_SHARED)
+			enable_irq(port->irq);
+		spin_unlock_irqrestore(&port->lock, flags);
 
 		/*
 		 * If the interrupt is not reasserted, setup a timer to
@@ -2083,7 +2063,7 @@
 	 * hardware interrupt, we use a timer-based system.  The original
 	 * driver used to do this with IRQ0.
 	 */
-	if (!is_real_interrupt(up->port.irq)) {
+	if (!port->irq) {
 		up->timer.data = (unsigned long)up;
 		mod_timer(&up->timer, jiffies + uart_poll_timeout(port));
 	} else {
@@ -2095,20 +2075,20 @@
 	/*
 	 * Now, initialize the UART
 	 */
-	serial_outp(up, UART_LCR, UART_LCR_WLEN8);
+	serial_port_out(port, UART_LCR, UART_LCR_WLEN8);
 
-	spin_lock_irqsave(&up->port.lock, flags);
+	spin_lock_irqsave(&port->lock, flags);
 	if (up->port.flags & UPF_FOURPORT) {
-		if (!is_real_interrupt(up->port.irq))
+		if (!up->port.irq)
 			up->port.mctrl |= TIOCM_OUT1;
 	} else
 		/*
 		 * Most PC uarts need OUT2 raised to enable interrupts.
 		 */
-		if (is_real_interrupt(up->port.irq))
+		if (port->irq)
 			up->port.mctrl |= TIOCM_OUT2;
 
-	serial8250_set_mctrl(&up->port, up->port.mctrl);
+	serial8250_set_mctrl(port, port->mctrl);
 
 	/* Serial over Lan (SoL) hack:
 	   Intel 8257x Gigabit ethernet chips have a
@@ -2128,10 +2108,10 @@
 	 * Do a quick test to see if we receive an
 	 * interrupt when we enable the TX irq.
 	 */
-	serial_outp(up, UART_IER, UART_IER_THRI);
-	lsr = serial_in(up, UART_LSR);
-	iir = serial_in(up, UART_IIR);
-	serial_outp(up, UART_IER, 0);
+	serial_port_out(port, UART_IER, UART_IER_THRI);
+	lsr = serial_port_in(port, UART_LSR);
+	iir = serial_port_in(port, UART_IIR);
+	serial_port_out(port, UART_IER, 0);
 
 	if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
 		if (!(up->bugs & UART_BUG_TXEN)) {
@@ -2144,17 +2124,17 @@
 	}
 
 dont_test_tx_en:
-	spin_unlock_irqrestore(&up->port.lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
 
 	/*
 	 * Clear the interrupt registers again for luck, and clear the
 	 * saved flags to avoid getting false values from polling
 	 * routines or the previous session.
 	 */
-	serial_inp(up, UART_LSR);
-	serial_inp(up, UART_RX);
-	serial_inp(up, UART_IIR);
-	serial_inp(up, UART_MSR);
+	serial_port_in(port, UART_LSR);
+	serial_port_in(port, UART_RX);
+	serial_port_in(port, UART_IIR);
+	serial_port_in(port, UART_MSR);
 	up->lsr_saved_flags = 0;
 	up->msr_saved_flags = 0;
 
@@ -2164,16 +2144,16 @@
 	 * anyway, so we don't enable them here.
 	 */
 	up->ier = UART_IER_RLSI | UART_IER_RDI;
-	serial_outp(up, UART_IER, up->ier);
+	serial_port_out(port, UART_IER, up->ier);
 
-	if (up->port.flags & UPF_FOURPORT) {
+	if (port->flags & UPF_FOURPORT) {
 		unsigned int icp;
 		/*
 		 * Enable interrupts on the AST Fourport board
 		 */
-		icp = (up->port.iobase & 0xfe0) | 0x01f;
+		icp = (port->iobase & 0xfe0) | 0x01f;
 		outb_p(0x80, icp);
-		(void) inb_p(icp);
+		inb_p(icp);
 	}
 
 	return 0;
@@ -2189,23 +2169,24 @@
 	 * Disable interrupts from this port
 	 */
 	up->ier = 0;
-	serial_outp(up, UART_IER, 0);
+	serial_port_out(port, UART_IER, 0);
 
-	spin_lock_irqsave(&up->port.lock, flags);
-	if (up->port.flags & UPF_FOURPORT) {
+	spin_lock_irqsave(&port->lock, flags);
+	if (port->flags & UPF_FOURPORT) {
 		/* reset interrupts on the AST Fourport board */
-		inb((up->port.iobase & 0xfe0) | 0x1f);
-		up->port.mctrl |= TIOCM_OUT1;
+		inb((port->iobase & 0xfe0) | 0x1f);
+		port->mctrl |= TIOCM_OUT1;
 	} else
-		up->port.mctrl &= ~TIOCM_OUT2;
+		port->mctrl &= ~TIOCM_OUT2;
 
-	serial8250_set_mctrl(&up->port, up->port.mctrl);
-	spin_unlock_irqrestore(&up->port.lock, flags);
+	serial8250_set_mctrl(port, port->mctrl);
+	spin_unlock_irqrestore(&port->lock, flags);
 
 	/*
 	 * Disable break condition and FIFOs
 	 */
-	serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
+	serial_port_out(port, UART_LCR,
+			serial_port_in(port, UART_LCR) & ~UART_LCR_SBC);
 	serial8250_clear_fifos(up);
 
 #ifdef CONFIG_SERIAL_8250_RSA
@@ -2219,11 +2200,11 @@
 	 * Read data port to reset things, and then unlink from
 	 * the IRQ chain.
 	 */
-	(void) serial_in(up, UART_RX);
+	serial_port_in(port, UART_RX);
 
 	del_timer_sync(&up->timer);
 	up->timer.function = serial8250_timeout;
-	if (is_real_interrupt(up->port.irq))
+	if (port->irq)
 		serial_unlink_irq_chain(up);
 }
 
@@ -2298,11 +2279,11 @@
 	if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)
 		quot++;
 
-	if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
+	if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
 		if (baud < 2400)
 			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
 		else
-			fcr = uart_config[up->port.type].fcr;
+			fcr = uart_config[port->type].fcr;
 	}
 
 	/*
@@ -2313,7 +2294,7 @@
 	 * have sufficient FIFO entries for the latency of the remote
 	 * UART to respond.  IOW, at least 32 bytes of FIFO.
 	 */
-	if (up->capabilities & UART_CAP_AFE && up->port.fifosize >= 32) {
+	if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) {
 		up->mcr &= ~UART_MCR_AFE;
 		if (termios->c_cflag & CRTSCTS)
 			up->mcr |= UART_MCR_AFE;
@@ -2323,40 +2304,40 @@
 	 * Ok, we're now changing the port state.  Do it with
 	 * interrupts disabled.
 	 */
-	spin_lock_irqsave(&up->port.lock, flags);
+	spin_lock_irqsave(&port->lock, flags);
 
 	/*
 	 * Update the per-port timeout.
 	 */
 	uart_update_timeout(port, termios->c_cflag, baud);
 
-	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+	port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
 	if (termios->c_iflag & INPCK)
-		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+		port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
 	if (termios->c_iflag & (BRKINT | PARMRK))
-		up->port.read_status_mask |= UART_LSR_BI;
+		port->read_status_mask |= UART_LSR_BI;
 
 	/*
 	 * Characteres to ignore
 	 */
-	up->port.ignore_status_mask = 0;
+	port->ignore_status_mask = 0;
 	if (termios->c_iflag & IGNPAR)
-		up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+		port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
 	if (termios->c_iflag & IGNBRK) {
-		up->port.ignore_status_mask |= UART_LSR_BI;
+		port->ignore_status_mask |= UART_LSR_BI;
 		/*
 		 * If we're ignoring parity and break indicators,
 		 * ignore overruns too (for real raw support).
 		 */
 		if (termios->c_iflag & IGNPAR)
-			up->port.ignore_status_mask |= UART_LSR_OE;
+			port->ignore_status_mask |= UART_LSR_OE;
 	}
 
 	/*
 	 * ignore all characters if CREAD is not set
 	 */
 	if ((termios->c_cflag & CREAD) == 0)
-		up->port.ignore_status_mask |= UART_LSR_DR;
+		port->ignore_status_mask |= UART_LSR_DR;
 
 	/*
 	 * CTS flow control flag and modem status interrupts
@@ -2370,7 +2351,7 @@
 	if (up->capabilities & UART_CAP_RTOIE)
 		up->ier |= UART_IER_RTOIE;
 
-	serial_out(up, UART_IER, up->ier);
+	serial_port_out(port, UART_IER, up->ier);
 
 	if (up->capabilities & UART_CAP_EFR) {
 		unsigned char efr = 0;
@@ -2382,11 +2363,11 @@
 		if (termios->c_cflag & CRTSCTS)
 			efr |= UART_EFR_CTS;
 
-		serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
-		if (up->port.flags & UPF_EXAR_EFR)
-			serial_outp(up, UART_XR_EFR, efr);
+		serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B);
+		if (port->flags & UPF_EXAR_EFR)
+			serial_port_out(port, UART_XR_EFR, efr);
 		else
-			serial_outp(up, UART_EFR, efr);
+			serial_port_out(port, UART_EFR, efr);
 	}
 
 #ifdef CONFIG_ARCH_OMAP
@@ -2394,18 +2375,20 @@
 	if (cpu_is_omap1510() && is_omap_port(up)) {
 		if (baud == 115200) {
 			quot = 1;
-			serial_out(up, UART_OMAP_OSC_12M_SEL, 1);
+			serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1);
 		} else
-			serial_out(up, UART_OMAP_OSC_12M_SEL, 0);
+			serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0);
 	}
 #endif
 
-	if (up->capabilities & UART_NATSEMI) {
-		/* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */
-		serial_outp(up, UART_LCR, 0xe0);
-	} else {
-		serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
-	}
+	/*
+	 * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2,
+	 * otherwise just set DLAB
+	 */
+	if (up->capabilities & UART_NATSEMI)
+		serial_port_out(port, UART_LCR, 0xe0);
+	else
+		serial_port_out(port, UART_LCR, cval | UART_LCR_DLAB);
 
 	serial_dl_write(up, quot);
 
@@ -2413,20 +2396,19 @@
 	 * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
 	 * is written without DLAB set, this mode will be disabled.
 	 */
-	if (up->port.type == PORT_16750)
-		serial_outp(up, UART_FCR, fcr);
+	if (port->type == PORT_16750)
+		serial_port_out(port, UART_FCR, fcr);
 
-	serial_outp(up, UART_LCR, cval);		/* reset DLAB */
+	serial_port_out(port, UART_LCR, cval);		/* reset DLAB */
 	up->lcr = cval;					/* Save LCR */
-	if (up->port.type != PORT_16750) {
-		if (fcr & UART_FCR_ENABLE_FIFO) {
-			/* emulated UARTs (Lucent Venus 167x) need two steps */
-			serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-		}
-		serial_outp(up, UART_FCR, fcr);		/* set fcr */
+	if (port->type != PORT_16750) {
+		/* emulated UARTs (Lucent Venus 167x) need two steps */
+		if (fcr & UART_FCR_ENABLE_FIFO)
+			serial_port_out(port, UART_FCR, UART_FCR_ENABLE_FIFO);
+		serial_port_out(port, UART_FCR, fcr);		/* set fcr */
 	}
-	serial8250_set_mctrl(&up->port, up->port.mctrl);
-	spin_unlock_irqrestore(&up->port.lock, flags);
+	serial8250_set_mctrl(port, port->mctrl);
+	spin_unlock_irqrestore(&port->lock, flags);
 	/* Don't rewrite B0 */
 	if (tty_termios_baud_rate(termios))
 		tty_termios_encode_baud_rate(termios, baud, baud);
@@ -2491,26 +2473,26 @@
 static int serial8250_request_std_resource(struct uart_8250_port *up)
 {
 	unsigned int size = serial8250_port_size(up);
+	struct uart_port *port = &up->port;
 	int ret = 0;
 
-	switch (up->port.iotype) {
+	switch (port->iotype) {
 	case UPIO_AU:
 	case UPIO_TSI:
 	case UPIO_MEM32:
 	case UPIO_MEM:
-		if (!up->port.mapbase)
+		if (!port->mapbase)
 			break;
 
-		if (!request_mem_region(up->port.mapbase, size, "serial")) {
+		if (!request_mem_region(port->mapbase, size, "serial")) {
 			ret = -EBUSY;
 			break;
 		}
 
-		if (up->port.flags & UPF_IOREMAP) {
-			up->port.membase = ioremap_nocache(up->port.mapbase,
-									size);
-			if (!up->port.membase) {
-				release_mem_region(up->port.mapbase, size);
+		if (port->flags & UPF_IOREMAP) {
+			port->membase = ioremap_nocache(port->mapbase, size);
+			if (!port->membase) {
+				release_mem_region(port->mapbase, size);
 				ret = -ENOMEM;
 			}
 		}
@@ -2518,7 +2500,7 @@
 
 	case UPIO_HUB6:
 	case UPIO_PORT:
-		if (!request_region(up->port.iobase, size, "serial"))
+		if (!request_region(port->iobase, size, "serial"))
 			ret = -EBUSY;
 		break;
 	}
@@ -2528,26 +2510,27 @@
 static void serial8250_release_std_resource(struct uart_8250_port *up)
 {
 	unsigned int size = serial8250_port_size(up);
+	struct uart_port *port = &up->port;
 
-	switch (up->port.iotype) {
+	switch (port->iotype) {
 	case UPIO_AU:
 	case UPIO_TSI:
 	case UPIO_MEM32:
 	case UPIO_MEM:
-		if (!up->port.mapbase)
+		if (!port->mapbase)
 			break;
 
-		if (up->port.flags & UPF_IOREMAP) {
-			iounmap(up->port.membase);
-			up->port.membase = NULL;
+		if (port->flags & UPF_IOREMAP) {
+			iounmap(port->membase);
+			port->membase = NULL;
 		}
 
-		release_mem_region(up->port.mapbase, size);
+		release_mem_region(port->mapbase, size);
 		break;
 
 	case UPIO_HUB6:
 	case UPIO_PORT:
-		release_region(up->port.iobase, size);
+		release_region(port->iobase, size);
 		break;
 	}
 }
@@ -2556,12 +2539,13 @@
 {
 	unsigned long start = UART_RSA_BASE << up->port.regshift;
 	unsigned int size = 8 << up->port.regshift;
+	struct uart_port *port = &up->port;
 	int ret = -EINVAL;
 
-	switch (up->port.iotype) {
+	switch (port->iotype) {
 	case UPIO_HUB6:
 	case UPIO_PORT:
-		start += up->port.iobase;
+		start += port->iobase;
 		if (request_region(start, size, "serial-rsa"))
 			ret = 0;
 		else
@@ -2576,11 +2560,12 @@
 {
 	unsigned long offset = UART_RSA_BASE << up->port.regshift;
 	unsigned int size = 8 << up->port.regshift;
+	struct uart_port *port = &up->port;
 
-	switch (up->port.iotype) {
+	switch (port->iotype) {
 	case UPIO_HUB6:
 	case UPIO_PORT:
-		release_region(up->port.iobase + offset, size);
+		release_region(port->iobase + offset, size);
 		break;
 	}
 }
@@ -2591,7 +2576,7 @@
 		container_of(port, struct uart_8250_port, port);
 
 	serial8250_release_std_resource(up);
-	if (up->port.type == PORT_RSA)
+	if (port->type == PORT_RSA)
 		serial8250_release_rsa_resource(up);
 }
 
@@ -2602,7 +2587,7 @@
 	int ret = 0;
 
 	ret = serial8250_request_std_resource(up);
-	if (ret == 0 && up->port.type == PORT_RSA) {
+	if (ret == 0 && port->type == PORT_RSA) {
 		ret = serial8250_request_rsa_resource(up);
 		if (ret < 0)
 			serial8250_release_std_resource(up);
@@ -2630,22 +2615,22 @@
 	if (ret < 0)
 		probeflags &= ~PROBE_RSA;
 
-	if (up->port.iotype != up->cur_iotype)
+	if (port->iotype != up->cur_iotype)
 		set_io_from_upio(port);
 
 	if (flags & UART_CONFIG_TYPE)
 		autoconfig(up, probeflags);
 
 	/* if access method is AU, it is a 16550 with a quirk */
-	if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU)
+	if (port->type == PORT_16550A && port->iotype == UPIO_AU)
 		up->bugs |= UART_BUG_NOMSR;
 
-	if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
+	if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
 		autoconfig_irq(up);
 
-	if (up->port.type != PORT_RSA && probeflags & PROBE_RSA)
+	if (port->type != PORT_RSA && probeflags & PROBE_RSA)
 		serial8250_release_rsa_resource(up);
-	if (up->port.type == PORT_UNKNOWN)
+	if (port->type == PORT_UNKNOWN)
 		serial8250_release_std_resource(up);
 }
 
@@ -2719,9 +2704,10 @@
 
 	for (i = 0; i < nr_uarts; i++) {
 		struct uart_8250_port *up = &serial8250_ports[i];
+		struct uart_port *port = &up->port;
 
-		up->port.line = i;
-		spin_lock_init(&up->port.lock);
+		port->line = i;
+		spin_lock_init(&port->lock);
 
 		init_timer(&up->timer);
 		up->timer.function = serial8250_timeout;
@@ -2732,7 +2718,7 @@
 		up->mcr_mask = ~ALPHA_KLUDGE_MCR;
 		up->mcr_force = ALPHA_KLUDGE_MCR;
 
-		up->port.ops = &serial8250_pops;
+		port->ops = &serial8250_pops;
 	}
 
 	if (share_irqs)
@@ -2741,17 +2727,19 @@
 	for (i = 0, up = serial8250_ports;
 	     i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
 	     i++, up++) {
-		up->port.iobase   = old_serial_port[i].port;
-		up->port.irq      = irq_canonicalize(old_serial_port[i].irq);
-		up->port.irqflags = old_serial_port[i].irqflags;
-		up->port.uartclk  = old_serial_port[i].baud_base * 16;
-		up->port.flags    = old_serial_port[i].flags;
-		up->port.hub6     = old_serial_port[i].hub6;
-		up->port.membase  = old_serial_port[i].iomem_base;
-		up->port.iotype   = old_serial_port[i].io_type;
-		up->port.regshift = old_serial_port[i].iomem_reg_shift;
-		set_io_from_upio(&up->port);
-		up->port.irqflags |= irqflag;
+		struct uart_port *port = &up->port;
+
+		port->iobase   = old_serial_port[i].port;
+		port->irq      = irq_canonicalize(old_serial_port[i].irq);
+		port->irqflags = old_serial_port[i].irqflags;
+		port->uartclk  = old_serial_port[i].baud_base * 16;
+		port->flags    = old_serial_port[i].flags;
+		port->hub6     = old_serial_port[i].hub6;
+		port->membase  = old_serial_port[i].iomem_base;
+		port->iotype   = old_serial_port[i].io_type;
+		port->regshift = old_serial_port[i].iomem_reg_shift;
+		set_io_from_upio(port);
+		port->irqflags |= irqflag;
 		if (serial8250_isa_config != NULL)
 			serial8250_isa_config(i, &up->port, &up->capabilities);
 
@@ -2799,7 +2787,7 @@
 		container_of(port, struct uart_8250_port, port);
 
 	wait_for_xmitr(up, UART_LSR_THRE);
-	serial_out(up, UART_TX, ch);
+	serial_port_out(port, UART_TX, ch);
 }
 
 /*
@@ -2812,6 +2800,7 @@
 serial8250_console_write(struct console *co, const char *s, unsigned int count)
 {
 	struct uart_8250_port *up = &serial8250_ports[co->index];
+	struct uart_port *port = &up->port;
 	unsigned long flags;
 	unsigned int ier;
 	int locked = 1;
@@ -2819,32 +2808,32 @@
 	touch_nmi_watchdog();
 
 	local_irq_save(flags);
-	if (up->port.sysrq) {
+	if (port->sysrq) {
 		/* serial8250_handle_irq() already took the lock */
 		locked = 0;
 	} else if (oops_in_progress) {
-		locked = spin_trylock(&up->port.lock);
+		locked = spin_trylock(&port->lock);
 	} else
-		spin_lock(&up->port.lock);
+		spin_lock(&port->lock);
 
 	/*
 	 *	First save the IER then disable the interrupts
 	 */
-	ier = serial_in(up, UART_IER);
+	ier = serial_port_in(port, UART_IER);
 
 	if (up->capabilities & UART_CAP_UUE)
-		serial_out(up, UART_IER, UART_IER_UUE);
+		serial_port_out(port, UART_IER, UART_IER_UUE);
 	else
-		serial_out(up, UART_IER, 0);
+		serial_port_out(port, UART_IER, 0);
 
-	uart_console_write(&up->port, s, count, serial8250_console_putchar);
+	uart_console_write(port, s, count, serial8250_console_putchar);
 
 	/*
 	 *	Finally, wait for transmitter to become empty
 	 *	and restore the IER
 	 */
 	wait_for_xmitr(up, BOTH_EMPTY);
-	serial_out(up, UART_IER, ier);
+	serial_port_out(port, UART_IER, ier);
 
 	/*
 	 *	The receive handling will happen properly because the
@@ -2857,7 +2846,7 @@
 		serial8250_modem_status(up);
 
 	if (locked)
-		spin_unlock(&up->port.lock);
+		spin_unlock(&port->lock);
 	local_irq_restore(flags);
 }
 
@@ -3002,17 +2991,18 @@
 void serial8250_resume_port(int line)
 {
 	struct uart_8250_port *up = &serial8250_ports[line];
+	struct uart_port *port = &up->port;
 
 	if (up->capabilities & UART_NATSEMI) {
 		/* Ensure it's still in high speed mode */
-		serial_outp(up, UART_LCR, 0xE0);
+		serial_port_out(port, UART_LCR, 0xE0);
 
 		ns16550a_goto_highspeed(up);
 
-		serial_outp(up, UART_LCR, 0);
-		up->port.uartclk = 921600*16;
+		serial_port_out(port, UART_LCR, 0);
+		port->uartclk = 921600*16;
 	}
-	uart_resume_port(&serial8250_reg, &up->port);
+	uart_resume_port(&serial8250_reg, port);
 }
 
 /*
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index ae027be..2868a1d 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -86,6 +86,16 @@
 #define SERIAL8250_SHARE_IRQS 0
 #endif
 
+static inline int serial_in(struct uart_8250_port *up, int offset)
+{
+	return up->port.serial_in(&up->port, offset);
+}
+
+static inline void serial_out(struct uart_8250_port *up, int offset, int value)
+{
+	up->port.serial_out(&up->port, offset, value);
+}
+
 #if defined(__alpha__) && !defined(CONFIG_PCI)
 /*
  * Digital did something really horribly wrong with the OUT1 and OUT2
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 2de9924..76e7764 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1347,4 +1347,17 @@
 	  Set this to the number of serial ports you want the driver
 	  to support.
 
+config SERIAL_EFM32_UART
+	tristate "EFM32 UART/USART port."
+	depends on ARCH_EFM32
+	select SERIAL_CORE
+	help
+	  This driver support the USART and UART ports on
+	  Energy Micro's efm32 SoCs.
+
+config SERIAL_EFM32_UART_CONSOLE
+	bool "EFM32 UART/USART console support"
+	depends on SERIAL_EFM32_UART=y
+	select SERIAL_CORE_CONSOLE
+
 endmenu
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index fef32e1..7257c5d 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -61,12 +61,12 @@
 obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
 obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
 obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
+obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
 obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
 obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
 obj-$(CONFIG_SERIAL_TIMBERDALE)	+= timbuart.o
 obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
 obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
-obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
 obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
 obj-$(CONFIG_SERIAL_MRST_MAX3110)	+= mrst_max3110.o
 obj-$(CONFIG_SERIAL_MFD_HSU)	+= mfd.o
@@ -78,3 +78,4 @@
 obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
 obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
 obj-$(CONFIG_SERIAL_AR933X)   += ar933x_uart.o
+obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 1d04c50..e790375 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -377,6 +377,26 @@
 	return 0;
 }
 
+#ifdef CONFIG_CONSOLE_POLL
+static int altera_uart_poll_get_char(struct uart_port *port)
+{
+	while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
+		 ALTERA_UART_STATUS_RRDY_MSK))
+		cpu_relax();
+
+	return altera_uart_readl(port, ALTERA_UART_RXDATA_REG);
+}
+
+static void altera_uart_poll_put_char(struct uart_port *port, unsigned char c)
+{
+	while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
+		 ALTERA_UART_STATUS_TRDY_MSK))
+		cpu_relax();
+
+	altera_uart_writel(port, c, ALTERA_UART_TXDATA_REG);
+}
+#endif
+
 /*
  *	Define the basic serial functions we support.
  */
@@ -397,35 +417,16 @@
 	.release_port	= altera_uart_release_port,
 	.config_port	= altera_uart_config_port,
 	.verify_port	= altera_uart_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+	.poll_get_char	= altera_uart_poll_get_char,
+	.poll_put_char	= altera_uart_poll_put_char,
+#endif
 };
 
 static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
 
 #if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
 
-int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp)
-{
-	struct uart_port *port;
-	int i;
-
-	for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
-		port = &altera_uart_ports[i].port;
-
-		port->line = i;
-		port->type = PORT_ALTERA_UART;
-		port->mapbase = platp[i].mapbase;
-		port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
-		port->iotype = SERIAL_IO_MEM;
-		port->irq = platp[i].irq;
-		port->uartclk = platp[i].uartclk;
-		port->flags = UPF_BOOT_AUTOCONF;
-		port->ops = &altera_uart_ops;
-		port->private_data = platp;
-	}
-
-	return 0;
-}
-
 static void altera_uart_console_putc(struct uart_port *port, const char c)
 {
 	while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 6800f5f..20d795d 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -827,7 +827,12 @@
 {
 	struct uart_amba_port *uap = data;
 	struct pl011_dmarx_data *dmarx = &uap->dmarx;
+	struct dma_chan *rxchan = dmarx->chan;
 	bool lastbuf = dmarx->use_buf_b;
+	struct pl011_sgbuf *sgbuf = dmarx->use_buf_b ?
+		&dmarx->sgbuf_b : &dmarx->sgbuf_a;
+	size_t pending;
+	struct dma_tx_state state;
 	int ret;
 
 	/*
@@ -838,11 +843,21 @@
 	 * we immediately trigger the next DMA job.
 	 */
 	spin_lock_irq(&uap->port.lock);
+	/*
+	 * Rx data can be taken by the UART interrupts during
+	 * the DMA irq handler. So we check the residue here.
+	 */
+	rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
+	pending = sgbuf->sg.length - state.residue;
+	BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
+	/* Then we terminate the transfer - we now know our residue */
+	dmaengine_terminate_all(rxchan);
+
 	uap->dmarx.running = false;
 	dmarx->use_buf_b = !lastbuf;
 	ret = pl011_dma_rx_trigger_dma(uap);
 
-	pl011_dma_rx_chars(uap, PL011_DMA_BUFFER_SIZE, lastbuf, false);
+	pl011_dma_rx_chars(uap, pending, lastbuf, false);
 	spin_unlock_irq(&uap->port.lock);
 	/*
 	 * Do this check after we picked the DMA chars so we don't
@@ -1381,6 +1396,10 @@
 
 	uap->port.uartclk = clk_get_rate(uap->clk);
 
+	/* Clear pending error and receive interrupts */
+	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
+	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+
 	/*
 	 * Allocate the IRQ
 	 */
@@ -1417,10 +1436,6 @@
 	cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
 	writew(cr, uap->port.membase + UART011_CR);
 
-	/* Clear pending error interrupts */
-	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
-	       uap->port.membase + UART011_ICR);
-
 	/*
 	 * initialise the old status of the modem signals
 	 */
@@ -1435,6 +1450,9 @@
 	 * as well.
 	 */
 	spin_lock_irq(&uap->port.lock);
+	/* Clear out any spuriously appearing RX interrupts */
+	 writew(UART011_RTIS | UART011_RXIS,
+		uap->port.membase + UART011_ICR);
 	uap->im = UART011_RTIM;
 	if (!pl011_dma_rx_running(uap))
 		uap->im |= UART011_RXIM;
@@ -1927,6 +1945,10 @@
 		goto unmap;
 	}
 
+	/* Ensure interrupts from this UART are masked and cleared */
+	writew(0, uap->port.membase + UART011_IMSC);
+	writew(0xffff, uap->port.membase + UART011_ICR);
+
 	uap->vendor = vendor;
 	uap->lcrh_rx = vendor->lcrh_rx;
 	uap->lcrh_tx = vendor->lcrh_tx;
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index 26953bf..5832fde 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -535,11 +535,13 @@
 		 *		when start a new tx.
 		 */
 		UART_CLEAR_IER(uart, ETBEI);
-		xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
 		uart->port.icount.tx += uart->tx_count;
+		if (!uart_circ_empty(xmit)) {
+			xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
 
-		if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-			uart_write_wakeup(&uart->port);
+			if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+				uart_write_wakeup(&uart->port);
+		}
 
 		bfin_serial_dma_tx_chars(uart);
 	}
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index 1dfba7b..23d7916 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -4105,20 +4105,11 @@
 rs_open(struct tty_struct *tty, struct file * filp)
 {
 	struct e100_serial	*info;
-	int 			retval, line;
+	int 			retval;
 	unsigned long           page;
 	int                     allocated_resources = 0;
 
-	/* find which port we want to open */
-	line = tty->index;
-
-	if (line < 0 || line >= NR_PORTS)
-		return -ENODEV;
-
-	/* find the corresponding e100_serial struct in the table */
-	info = rs_table + line;
-
-	/* don't allow the opening of ports that are not enabled in the HW config */
+	info = rs_table + tty->index;
 	if (!info->enabled)
 		return -ENODEV;
 
@@ -4131,7 +4122,7 @@
 	tty->driver_data = info;
 	info->port.tty = tty;
 
-	info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+	tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY);
 
 	if (!tmp_buf) {
 		page = get_zeroed_page(GFP_KERNEL);
diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c
new file mode 100644
index 0000000..615e464
--- /dev/null
+++ b/drivers/tty/serial/efm32-uart.c
@@ -0,0 +1,830 @@
+#if defined(CONFIG_SERIAL_EFM32_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/serial_core.h>
+#include <linux/tty_flip.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <linux/platform_data/efm32-uart.h>
+
+#define DRIVER_NAME "efm32-uart"
+#define DEV_NAME "ttyefm"
+
+#define UARTn_CTRL		0x00
+#define UARTn_CTRL_SYNC		0x0001
+#define UARTn_CTRL_TXBIL		0x1000
+
+#define UARTn_FRAME		0x04
+#define UARTn_FRAME_DATABITS__MASK	0x000f
+#define UARTn_FRAME_DATABITS(n)		((n) - 3)
+#define UARTn_FRAME_PARITY_NONE		0x0000
+#define UARTn_FRAME_PARITY_EVEN		0x0200
+#define UARTn_FRAME_PARITY_ODD		0x0300
+#define UARTn_FRAME_STOPBITS_HALF	0x0000
+#define UARTn_FRAME_STOPBITS_ONE	0x1000
+#define UARTn_FRAME_STOPBITS_TWO	0x3000
+
+#define UARTn_CMD		0x0c
+#define UARTn_CMD_RXEN			0x0001
+#define UARTn_CMD_RXDIS		0x0002
+#define UARTn_CMD_TXEN			0x0004
+#define UARTn_CMD_TXDIS		0x0008
+
+#define UARTn_STATUS		0x10
+#define UARTn_STATUS_TXENS		0x0002
+#define UARTn_STATUS_TXC		0x0020
+#define UARTn_STATUS_TXBL		0x0040
+#define UARTn_STATUS_RXDATAV		0x0080
+
+#define UARTn_CLKDIV		0x14
+
+#define UARTn_RXDATAX		0x18
+#define UARTn_RXDATAX_RXDATA__MASK	0x01ff
+#define UARTn_RXDATAX_PERR		0x4000
+#define UARTn_RXDATAX_FERR		0x8000
+/*
+ * This is a software only flag used for ignore_status_mask and
+ * read_status_mask! It's used for breaks that the hardware doesn't report
+ * explicitly.
+ */
+#define SW_UARTn_RXDATAX_BERR		0x2000
+
+#define UARTn_TXDATA		0x34
+
+#define UARTn_IF		0x40
+#define UARTn_IF_TXC			0x0001
+#define UARTn_IF_TXBL			0x0002
+#define UARTn_IF_RXDATAV		0x0004
+#define UARTn_IF_RXOF			0x0010
+
+#define UARTn_IFS		0x44
+#define UARTn_IFC		0x48
+#define UARTn_IEN		0x4c
+
+#define UARTn_ROUTE		0x54
+#define UARTn_ROUTE_LOCATION__MASK	0x0700
+#define UARTn_ROUTE_LOCATION(n)		(((n) << 8) & UARTn_ROUTE_LOCATION__MASK)
+#define UARTn_ROUTE_RXPEN		0x0001
+#define UARTn_ROUTE_TXPEN		0x0002
+
+struct efm32_uart_port {
+	struct uart_port port;
+	unsigned int txirq;
+	struct clk *clk;
+};
+#define to_efm_port(_port) container_of(_port, struct efm32_uart_port, port)
+#define efm_debug(efm_port, format, arg...)			\
+	dev_dbg(efm_port->port.dev, format, ##arg)
+
+static void efm32_uart_write32(struct efm32_uart_port *efm_port,
+		u32 value, unsigned offset)
+{
+	writel_relaxed(value, efm_port->port.membase + offset);
+}
+
+static u32 efm32_uart_read32(struct efm32_uart_port *efm_port,
+		unsigned offset)
+{
+	return readl_relaxed(efm_port->port.membase + offset);
+}
+
+static unsigned int efm32_uart_tx_empty(struct uart_port *port)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+	u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
+
+	if (status & UARTn_STATUS_TXC)
+		return TIOCSER_TEMT;
+	else
+		return 0;
+}
+
+static void efm32_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/* sorry, neither handshaking lines nor loop functionallity */
+}
+
+static unsigned int efm32_uart_get_mctrl(struct uart_port *port)
+{
+	/* sorry, no handshaking lines available */
+	return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR;
+}
+
+static void efm32_uart_stop_tx(struct uart_port *port)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+	u32 ien = efm32_uart_read32(efm_port,  UARTn_IEN);
+
+	efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD);
+	ien &= ~(UARTn_IF_TXC | UARTn_IF_TXBL);
+	efm32_uart_write32(efm_port, ien, UARTn_IEN);
+}
+
+static void efm32_uart_tx_chars(struct efm32_uart_port *efm_port)
+{
+	struct uart_port *port = &efm_port->port;
+	struct circ_buf *xmit = &port->state->xmit;
+
+	while (efm32_uart_read32(efm_port, UARTn_STATUS) &
+			UARTn_STATUS_TXBL) {
+		if (port->x_char) {
+			port->icount.tx++;
+			efm32_uart_write32(efm_port, port->x_char,
+					UARTn_TXDATA);
+			port->x_char = 0;
+			continue;
+		}
+		if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
+			port->icount.tx++;
+			efm32_uart_write32(efm_port, xmit->buf[xmit->tail],
+					UARTn_TXDATA);
+			xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		} else
+			break;
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (!port->x_char && uart_circ_empty(xmit) &&
+			efm32_uart_read32(efm_port, UARTn_STATUS) &
+				UARTn_STATUS_TXC)
+		efm32_uart_stop_tx(port);
+}
+
+static void efm32_uart_start_tx(struct uart_port *port)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+	u32 ien;
+
+	efm32_uart_write32(efm_port,
+			UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IFC);
+	ien = efm32_uart_read32(efm_port, UARTn_IEN);
+	efm32_uart_write32(efm_port,
+			ien | UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IEN);
+	efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD);
+
+	efm32_uart_tx_chars(efm_port);
+}
+
+static void efm32_uart_stop_rx(struct uart_port *port)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+
+	efm32_uart_write32(efm_port, UARTn_CMD_RXDIS, UARTn_CMD);
+}
+
+static void efm32_uart_enable_ms(struct uart_port *port)
+{
+	/* no handshake lines, no modem status interrupts */
+}
+
+static void efm32_uart_break_ctl(struct uart_port *port, int ctl)
+{
+	/* not possible without fiddling with gpios */
+}
+
+static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port,
+		struct tty_struct *tty)
+{
+	struct uart_port *port = &efm_port->port;
+
+	while (efm32_uart_read32(efm_port, UARTn_STATUS) &
+			UARTn_STATUS_RXDATAV) {
+		u32 rxdata = efm32_uart_read32(efm_port, UARTn_RXDATAX);
+		int flag = 0;
+
+		/*
+		 * This is a reserved bit and I only saw it read as 0. But to be
+		 * sure not to be confused too much by new devices adhere to the
+		 * warning in the reference manual that reserverd bits might
+		 * read as 1 in the future.
+		 */
+		rxdata &= ~SW_UARTn_RXDATAX_BERR;
+
+		port->icount.rx++;
+
+		if ((rxdata & UARTn_RXDATAX_FERR) &&
+				!(rxdata & UARTn_RXDATAX_RXDATA__MASK)) {
+			rxdata |= SW_UARTn_RXDATAX_BERR;
+			port->icount.brk++;
+			if (uart_handle_break(port))
+				continue;
+		} else if (rxdata & UARTn_RXDATAX_PERR)
+			port->icount.parity++;
+		else if (rxdata & UARTn_RXDATAX_FERR)
+			port->icount.frame++;
+
+		rxdata &= port->read_status_mask;
+
+		if (rxdata & SW_UARTn_RXDATAX_BERR)
+			flag = TTY_BREAK;
+		else if (rxdata & UARTn_RXDATAX_PERR)
+			flag = TTY_PARITY;
+		else if (rxdata & UARTn_RXDATAX_FERR)
+			flag = TTY_FRAME;
+		else if (uart_handle_sysrq_char(port,
+					rxdata & UARTn_RXDATAX_RXDATA__MASK))
+			continue;
+
+		if (tty && (rxdata & port->ignore_status_mask) == 0)
+			tty_insert_flip_char(tty,
+					rxdata & UARTn_RXDATAX_RXDATA__MASK, flag);
+	}
+}
+
+static irqreturn_t efm32_uart_rxirq(int irq, void *data)
+{
+	struct efm32_uart_port *efm_port = data;
+	u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF);
+	int handled = IRQ_NONE;
+	struct uart_port *port = &efm_port->port;
+	struct tty_struct *tty;
+
+	spin_lock(&port->lock);
+
+	tty = tty_kref_get(port->state->port.tty);
+
+	if (irqflag & UARTn_IF_RXDATAV) {
+		efm32_uart_write32(efm_port, UARTn_IF_RXDATAV, UARTn_IFC);
+		efm32_uart_rx_chars(efm_port, tty);
+
+		handled = IRQ_HANDLED;
+	}
+
+	if (irqflag & UARTn_IF_RXOF) {
+		efm32_uart_write32(efm_port, UARTn_IF_RXOF, UARTn_IFC);
+		port->icount.overrun++;
+		if (tty)
+			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+		handled = IRQ_HANDLED;
+	}
+
+	if (tty) {
+		tty_flip_buffer_push(tty);
+		tty_kref_put(tty);
+	}
+
+	spin_unlock(&port->lock);
+
+	return handled;
+}
+
+static irqreturn_t efm32_uart_txirq(int irq, void *data)
+{
+	struct efm32_uart_port *efm_port = data;
+	u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF);
+
+	/* TXBL doesn't need to be cleared */
+	if (irqflag & UARTn_IF_TXC)
+		efm32_uart_write32(efm_port, UARTn_IF_TXC, UARTn_IFC);
+
+	if (irqflag & (UARTn_IF_TXC | UARTn_IF_TXBL)) {
+		efm32_uart_tx_chars(efm_port);
+		return IRQ_HANDLED;
+	} else
+		return IRQ_NONE;
+}
+
+static int efm32_uart_startup(struct uart_port *port)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+	u32 location = 0;
+	struct efm32_uart_pdata *pdata = dev_get_platdata(port->dev);
+	int ret;
+
+	if (pdata)
+		location = UARTn_ROUTE_LOCATION(pdata->location);
+
+	ret = clk_enable(efm_port->clk);
+	if (ret) {
+		efm_debug(efm_port, "failed to enable clk\n");
+		goto err_clk_enable;
+	}
+	port->uartclk = clk_get_rate(efm_port->clk);
+
+	/* Enable pins at configured location */
+	efm32_uart_write32(efm_port, location | UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN,
+			UARTn_ROUTE);
+
+	ret = request_irq(port->irq, efm32_uart_rxirq, 0,
+			DRIVER_NAME, efm_port);
+	if (ret) {
+		efm_debug(efm_port, "failed to register rxirq\n");
+		goto err_request_irq_rx;
+	}
+
+	/* disable all irqs */
+	efm32_uart_write32(efm_port, 0, UARTn_IEN);
+
+	ret = request_irq(efm_port->txirq, efm32_uart_txirq, 0,
+			DRIVER_NAME, efm_port);
+	if (ret) {
+		efm_debug(efm_port, "failed to register txirq\n");
+		free_irq(port->irq, efm_port);
+err_request_irq_rx:
+
+		clk_disable(efm_port->clk);
+	} else {
+		efm32_uart_write32(efm_port,
+				UARTn_IF_RXDATAV | UARTn_IF_RXOF, UARTn_IEN);
+		efm32_uart_write32(efm_port, UARTn_CMD_RXEN, UARTn_CMD);
+	}
+
+err_clk_enable:
+	return ret;
+}
+
+static void efm32_uart_shutdown(struct uart_port *port)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+
+	efm32_uart_write32(efm_port, 0, UARTn_IEN);
+	free_irq(port->irq, efm_port);
+
+	clk_disable(efm_port->clk);
+}
+
+static void efm32_uart_set_termios(struct uart_port *port,
+		struct ktermios *new, struct ktermios *old)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+	unsigned long flags;
+	unsigned baud;
+	u32 clkdiv;
+	u32 frame = 0;
+
+	/* no modem control lines */
+	new->c_cflag &= ~(CRTSCTS | CMSPAR);
+
+	baud = uart_get_baud_rate(port, new, old,
+			DIV_ROUND_CLOSEST(port->uartclk, 16 * 8192),
+			DIV_ROUND_CLOSEST(port->uartclk, 16));
+
+	switch (new->c_cflag & CSIZE) {
+	case CS5:
+		frame |= UARTn_FRAME_DATABITS(5);
+		break;
+	case CS6:
+		frame |= UARTn_FRAME_DATABITS(6);
+		break;
+	case CS7:
+		frame |= UARTn_FRAME_DATABITS(7);
+		break;
+	case CS8:
+		frame |= UARTn_FRAME_DATABITS(8);
+		break;
+	}
+
+	if (new->c_cflag & CSTOPB)
+		/* the receiver only verifies the first stop bit */
+		frame |= UARTn_FRAME_STOPBITS_TWO;
+	else
+		frame |= UARTn_FRAME_STOPBITS_ONE;
+
+	if (new->c_cflag & PARENB) {
+		if (new->c_cflag & PARODD)
+			frame |= UARTn_FRAME_PARITY_ODD;
+		else
+			frame |= UARTn_FRAME_PARITY_EVEN;
+	} else
+		frame |= UARTn_FRAME_PARITY_NONE;
+
+	/*
+	 * the 6 lowest bits of CLKDIV are dc, bit 6 has value 0.25.
+	 * port->uartclk <= 14e6, so 4 * port->uartclk doesn't overflow.
+	 */
+	clkdiv = (DIV_ROUND_CLOSEST(4 * port->uartclk, 16 * baud) - 4) << 6;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	efm32_uart_write32(efm_port,
+			UARTn_CMD_TXDIS | UARTn_CMD_RXDIS, UARTn_CMD);
+
+	port->read_status_mask = UARTn_RXDATAX_RXDATA__MASK;
+	if (new->c_iflag & INPCK)
+		port->read_status_mask |=
+			UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR;
+	if (new->c_iflag & (BRKINT | PARMRK))
+		port->read_status_mask |= SW_UARTn_RXDATAX_BERR;
+
+	port->ignore_status_mask = 0;
+	if (new->c_iflag & IGNPAR)
+		port->ignore_status_mask |=
+			UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR;
+	if (new->c_iflag & IGNBRK)
+		port->ignore_status_mask |= SW_UARTn_RXDATAX_BERR;
+
+	uart_update_timeout(port, new->c_cflag, baud);
+
+	efm32_uart_write32(efm_port, UARTn_CTRL_TXBIL, UARTn_CTRL);
+	efm32_uart_write32(efm_port, frame, UARTn_FRAME);
+	efm32_uart_write32(efm_port, clkdiv, UARTn_CLKDIV);
+
+	efm32_uart_write32(efm_port, UARTn_CMD_TXEN | UARTn_CMD_RXEN,
+			UARTn_CMD);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *efm32_uart_type(struct uart_port *port)
+{
+	return port->type == PORT_EFMUART ? "efm32-uart" : NULL;
+}
+
+static void efm32_uart_release_port(struct uart_port *port)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+
+	clk_unprepare(efm_port->clk);
+	clk_put(efm_port->clk);
+	iounmap(port->membase);
+}
+
+static int efm32_uart_request_port(struct uart_port *port)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+	int ret;
+
+	port->membase = ioremap(port->mapbase, 60);
+	if (!efm_port->port.membase) {
+		ret = -ENOMEM;
+		efm_debug(efm_port, "failed to remap\n");
+		goto err_ioremap;
+	}
+
+	efm_port->clk = clk_get(port->dev, NULL);
+	if (IS_ERR(efm_port->clk)) {
+		ret = PTR_ERR(efm_port->clk);
+		efm_debug(efm_port, "failed to get clock\n");
+		goto err_clk_get;
+	}
+
+	ret = clk_prepare(efm_port->clk);
+	if (ret) {
+		clk_put(efm_port->clk);
+err_clk_get:
+
+		iounmap(port->membase);
+err_ioremap:
+		return ret;
+	}
+	return 0;
+}
+
+static void efm32_uart_config_port(struct uart_port *port, int type)
+{
+	if (type & UART_CONFIG_TYPE &&
+			!efm32_uart_request_port(port))
+		port->type = PORT_EFMUART;
+}
+
+static int efm32_uart_verify_port(struct uart_port *port,
+		struct serial_struct *serinfo)
+{
+	int ret = 0;
+
+	if (serinfo->type != PORT_UNKNOWN && serinfo->type != PORT_EFMUART)
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static struct uart_ops efm32_uart_pops = {
+	.tx_empty = efm32_uart_tx_empty,
+	.set_mctrl = efm32_uart_set_mctrl,
+	.get_mctrl = efm32_uart_get_mctrl,
+	.stop_tx = efm32_uart_stop_tx,
+	.start_tx = efm32_uart_start_tx,
+	.stop_rx = efm32_uart_stop_rx,
+	.enable_ms = efm32_uart_enable_ms,
+	.break_ctl = efm32_uart_break_ctl,
+	.startup = efm32_uart_startup,
+	.shutdown = efm32_uart_shutdown,
+	.set_termios = efm32_uart_set_termios,
+	.type = efm32_uart_type,
+	.release_port = efm32_uart_release_port,
+	.request_port = efm32_uart_request_port,
+	.config_port = efm32_uart_config_port,
+	.verify_port = efm32_uart_verify_port,
+};
+
+static struct efm32_uart_port *efm32_uart_ports[5];
+
+#ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE
+static void efm32_uart_console_putchar(struct uart_port *port, int ch)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+	unsigned int timeout = 0x400;
+	u32 status;
+
+	while (1) {
+		status = efm32_uart_read32(efm_port, UARTn_STATUS);
+
+		if (status & UARTn_STATUS_TXBL)
+			break;
+		if (!timeout--)
+			return;
+	}
+	efm32_uart_write32(efm_port, ch, UARTn_TXDATA);
+}
+
+static void efm32_uart_console_write(struct console *co, const char *s,
+		unsigned int count)
+{
+	struct efm32_uart_port *efm_port = efm32_uart_ports[co->index];
+	u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
+	unsigned int timeout = 0x400;
+
+	if (!(status & UARTn_STATUS_TXENS))
+		efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD);
+
+	uart_console_write(&efm_port->port, s, count,
+			efm32_uart_console_putchar);
+
+	/* Wait for the transmitter to become empty */
+	while (1) {
+		u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
+		if (status & UARTn_STATUS_TXC)
+			break;
+		if (!timeout--)
+			break;
+	}
+
+	if (!(status & UARTn_STATUS_TXENS))
+		efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD);
+}
+
+static void efm32_uart_console_get_options(struct efm32_uart_port *efm_port,
+		int *baud, int *parity, int *bits)
+{
+	u32 ctrl = efm32_uart_read32(efm_port, UARTn_CTRL);
+	u32 route, clkdiv, frame;
+
+	if (ctrl & UARTn_CTRL_SYNC)
+		/* not operating in async mode */
+		return;
+
+	route = efm32_uart_read32(efm_port, UARTn_ROUTE);
+	if (!(route & UARTn_ROUTE_TXPEN))
+		/* tx pin not routed */
+		return;
+
+	clkdiv = efm32_uart_read32(efm_port, UARTn_CLKDIV);
+
+	*baud = DIV_ROUND_CLOSEST(4 * efm_port->port.uartclk,
+			16 * (4 + (clkdiv >> 6)));
+
+	frame = efm32_uart_read32(efm_port, UARTn_FRAME);
+	if (frame & UARTn_FRAME_PARITY_ODD)
+		*parity = 'o';
+	else if (frame & UARTn_FRAME_PARITY_EVEN)
+		*parity = 'e';
+	else
+		*parity = 'n';
+
+	*bits = (frame & UARTn_FRAME_DATABITS__MASK) -
+			UARTn_FRAME_DATABITS(4) + 4;
+
+	efm_debug(efm_port, "get_opts: options=%d%c%d\n",
+			*baud, *parity, *bits);
+}
+
+static int efm32_uart_console_setup(struct console *co, char *options)
+{
+	struct efm32_uart_port *efm_port;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+	int ret;
+
+	if (co->index < 0 || co->index >= ARRAY_SIZE(efm32_uart_ports)) {
+		unsigned i;
+		for (i = 0; i < ARRAY_SIZE(efm32_uart_ports); ++i) {
+			if (efm32_uart_ports[i]) {
+				pr_warn("efm32-console: fall back to console index %u (from %hhi)\n",
+						i, co->index);
+				co->index = i;
+				break;
+			}
+		}
+	}
+
+	efm_port = efm32_uart_ports[co->index];
+	if (!efm_port) {
+		pr_warn("efm32-console: No port at %d\n", co->index);
+		return -ENODEV;
+	}
+
+	ret = clk_prepare(efm_port->clk);
+	if (ret) {
+		dev_warn(efm_port->port.dev,
+				"console: clk_prepare failed: %d\n", ret);
+		return ret;
+	}
+
+	efm_port->port.uartclk = clk_get_rate(efm_port->clk);
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+	else
+		efm32_uart_console_get_options(efm_port,
+				&baud, &parity, &bits);
+
+	return uart_set_options(&efm_port->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver efm32_uart_reg;
+
+static struct console efm32_uart_console = {
+	.name = DEV_NAME,
+	.write = efm32_uart_console_write,
+	.device = uart_console_device,
+	.setup = efm32_uart_console_setup,
+	.flags = CON_PRINTBUFFER,
+	.index = -1,
+	.data = &efm32_uart_reg,
+};
+
+#else
+#define efm32_uart_console (*(struct console *)NULL)
+#endif /* ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE / else */
+
+static struct uart_driver efm32_uart_reg = {
+	.owner = THIS_MODULE,
+	.driver_name = DRIVER_NAME,
+	.dev_name = DEV_NAME,
+	.nr = ARRAY_SIZE(efm32_uart_ports),
+	.cons = &efm32_uart_console,
+};
+
+static int efm32_uart_probe_dt(struct platform_device *pdev,
+		struct efm32_uart_port *efm_port)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	if (!np)
+		return 1;
+
+	ret = of_alias_get_id(np, "serial");
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to get alias id: %d\n", ret);
+		return ret;
+	} else {
+		efm_port->port.line = ret;
+		return 0;
+	}
+
+}
+
+static int __devinit efm32_uart_probe(struct platform_device *pdev)
+{
+	struct efm32_uart_port *efm_port;
+	struct resource *res;
+	int ret;
+
+	efm_port = kzalloc(sizeof(*efm_port), GFP_KERNEL);
+	if (!efm_port) {
+		dev_dbg(&pdev->dev, "failed to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENODEV;
+		dev_dbg(&pdev->dev, "failed to determine base address\n");
+		goto err_get_base;
+	}
+
+	if (resource_size(res) < 60) {
+		ret = -EINVAL;
+		dev_dbg(&pdev->dev, "memory resource too small\n");
+		goto err_too_small;
+	}
+
+	ret = platform_get_irq(pdev, 0);
+	if (ret <= 0) {
+		dev_dbg(&pdev->dev, "failed to get rx irq\n");
+		goto err_get_rxirq;
+	}
+
+	efm_port->port.irq = ret;
+
+	ret = platform_get_irq(pdev, 1);
+	if (ret <= 0)
+		ret = efm_port->port.irq + 1;
+
+	efm_port->txirq = ret;
+
+	efm_port->port.dev = &pdev->dev;
+	efm_port->port.mapbase = res->start;
+	efm_port->port.type = PORT_EFMUART;
+	efm_port->port.iotype = UPIO_MEM32;
+	efm_port->port.fifosize = 2;
+	efm_port->port.ops = &efm32_uart_pops;
+	efm_port->port.flags = UPF_BOOT_AUTOCONF;
+
+	ret = efm32_uart_probe_dt(pdev, efm_port);
+	if (ret > 0)
+		/* not created by device tree */
+		efm_port->port.line = pdev->id;
+
+	if (efm_port->port.line >= 0 &&
+			efm_port->port.line < ARRAY_SIZE(efm32_uart_ports))
+		efm32_uart_ports[efm_port->port.line] = efm_port;
+
+	ret = uart_add_one_port(&efm32_uart_reg, &efm_port->port);
+	if (ret) {
+		dev_dbg(&pdev->dev, "failed to add port: %d\n", ret);
+
+		if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(efm32_uart_ports))
+			efm32_uart_ports[pdev->id] = NULL;
+err_get_rxirq:
+err_too_small:
+err_get_base:
+		kfree(efm_port);
+	} else {
+		platform_set_drvdata(pdev, efm_port);
+		dev_dbg(&pdev->dev, "\\o/\n");
+	}
+
+	return ret;
+}
+
+static int __devexit efm32_uart_remove(struct platform_device *pdev)
+{
+	struct efm32_uart_port *efm_port = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	uart_remove_one_port(&efm32_uart_reg, &efm_port->port);
+
+	if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(efm32_uart_ports))
+		efm32_uart_ports[pdev->id] = NULL;
+
+	kfree(efm_port);
+
+	return 0;
+}
+
+static struct of_device_id efm32_uart_dt_ids[] = {
+	{
+		.compatible = "efm32,uart",
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(of, efm32_uart_dt_ids);
+
+static struct platform_driver efm32_uart_driver = {
+	.probe = efm32_uart_probe,
+	.remove = __devexit_p(efm32_uart_remove),
+
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = efm32_uart_dt_ids,
+	},
+};
+
+static int __init efm32_uart_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&efm32_uart_reg);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&efm32_uart_driver);
+	if (ret)
+		uart_unregister_driver(&efm32_uart_reg);
+
+	pr_info("EFM32 UART/USART driver\n");
+
+	return ret;
+}
+module_init(efm32_uart_init);
+
+static void __exit efm32_uart_exit(void)
+{
+	platform_driver_unregister(&efm32_uart_driver);
+	uart_unregister_driver(&efm32_uart_reg);
+}
+
+MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
+MODULE_DESCRIPTION("EFM32 UART/USART driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index 7e925e2..144cd39 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -1375,12 +1375,9 @@
 		return -ENOMEM;
 	}
 
-	tty_drv->magic = TTY_DRIVER_MAGIC;
-	tty_drv->owner = THIS_MODULE;
 	tty_drv->driver_name = DRVNAME;
 	tty_drv->name = TTYNAME;
 	tty_drv->minor_start = IFX_SPI_TTY_ID;
-	tty_drv->num = 1;
 	tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
 	tty_drv->subtype = SERIAL_TYPE_NORMAL;
 	tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c
index 6b36c15..e16894f 100644
--- a/drivers/tty/serial/ioc4_serial.c
+++ b/drivers/tty/serial/ioc4_serial.c
@@ -16,7 +16,6 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
-#include <linux/serialP.h>
 #include <linux/circ_buf.h>
 #include <linux/serial_reg.h>
 #include <linux/module.h>
@@ -975,7 +974,7 @@
 	BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
 	       || (type == IOC4_OTHER_INTR_TYPE)));
 
-	i = atomic_inc(&soft-> is_intr_type[type].is_num_intrs) - 1;
+	i = atomic_inc_return(&soft-> is_intr_type[type].is_num_intrs) - 1;
 	BUG_ON(!(i < MAX_IOC4_INTR_ENTS || (printk("i %d\n", i), 0)));
 
 	/* Save off the lower level interrupt handler */
diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c
index 94a6792..a070362 100644
--- a/drivers/tty/serial/m32r_sio.c
+++ b/drivers/tty/serial/m32r_sio.c
@@ -38,7 +38,6 @@
 #include <linux/console.h>
 #include <linux/sysrq.h>
 #include <linux/serial.h>
-#include <linux/serialP.h>
 #include <linux/delay.h>
 
 #include <asm/m32r.h>
@@ -70,13 +69,6 @@
 
 #define PASS_LIMIT	256
 
-/*
- * We default to IRQ0 for the "no irq" hack.   Some
- * machine types want others as well - they're free
- * to redefine this in their header file.
- */
-#define is_real_interrupt(irq)	((irq) != 0)
-
 #define BASE_BAUD	115200
 
 /* Standard COM flags */
@@ -640,7 +632,7 @@
 	 * hardware interrupt, we use a timer-based system.  The original
 	 * driver used to do this with IRQ0.
 	 */
-	if (!is_real_interrupt(up->port.irq)) {
+	if (!up->port.irq) {
 		unsigned int timeout = up->port.timeout;
 
 		timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
@@ -687,7 +679,7 @@
 
 	sio_init();
 
-	if (!is_real_interrupt(up->port.irq))
+	if (!up->port.irq)
 		del_timer_sync(&up->timer);
 	else
 		serial_unlink_irq_chain(up);
diff --git a/drivers/tty/serial/m32r_sio.h b/drivers/tty/serial/m32r_sio.h
index e9b7e11..8129824 100644
--- a/drivers/tty/serial/m32r_sio.h
+++ b/drivers/tty/serial/m32r_sio.h
@@ -15,6 +15,7 @@
  * (at your option) any later version.
  */
 
+#include <linux/pci.h>
 
 struct m32r_sio_probe {
 	struct module	*owner;
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 1093a88..bedac0d 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -262,8 +262,9 @@
 				  port->uartclk / 4);
 	divisor = (port->uartclk + 2 * baud) / (4 * baud);
 
-	/* select the proper prescaler and set the divisor */
-	if (divisor > 0xffff) {
+	/* select the proper prescaler and set the divisor
+	 * prefer high prescaler for more tolerance on low baudrates */
+	if (divisor > 0xffff || baud <= 115200) {
 		divisor = (divisor + 4) / 8;
 		prescaler = 0xdd00; /* /32 */
 	} else
@@ -507,7 +508,7 @@
 
 	psc_fifoc_irq = irq_of_parse_and_map(np, 0);
 	of_node_put(np);
-	if (psc_fifoc_irq == NO_IRQ) {
+	if (psc_fifoc_irq == 0) {
 		pr_err("%s: Can't get FIFOC irq\n", __func__);
 		iounmap(psc_fifoc);
 		return -ENODEV;
@@ -1354,7 +1355,7 @@
 	}
 
 	psc_ops->get_irq(port, op->dev.of_node);
-	if (port->irq == NO_IRQ) {
+	if (port->irq == 0) {
 		dev_dbg(&op->dev, "Could not get irq\n");
 		return -EINVAL;
 	}
diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c
index 4f41dcd..b25e6ee 100644
--- a/drivers/tty/serial/msm_smd_tty.c
+++ b/drivers/tty/serial/msm_smd_tty.c
@@ -203,7 +203,6 @@
 	if (smd_tty_driver == 0)
 		return -ENOMEM;
 
-	smd_tty_driver->owner = THIS_MODULE;
 	smd_tty_driver->driver_name = "smd_tty_driver";
 	smd_tty_driver->name = "smd";
 	smd_tty_driver->major = 0;
diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c
index 06f6aef..7ea8a26 100644
--- a/drivers/tty/serial/mux.c
+++ b/drivers/tty/serial/mux.c
@@ -17,7 +17,6 @@
 */
 
 #include <linux/module.h>
-#include <linux/tty.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/serial.h>
@@ -499,7 +498,7 @@
 		port->membase	= ioremap_nocache(port->mapbase, MUX_LINE_OFFSET);
 		port->iotype	= UPIO_MEM;
 		port->type	= PORT_MUX;
-		port->irq	= NO_IRQ;
+		port->irq	= 0;
 		port->uartclk	= 0;
 		port->fifosize	= MUX_FIFO_SIZE;
 		port->ops	= &mux_pops;
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index f809041..0121486 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -159,7 +159,7 @@
 		serial_out(up, UART_IER, up->ier);
 	}
 
-	if (!up->use_dma && pdata->set_forceidle)
+	if (!up->use_dma && pdata && pdata->set_forceidle)
 		pdata->set_forceidle(up->pdev);
 
 	pm_runtime_mark_last_busy(&up->pdev->dev);
@@ -298,7 +298,7 @@
 	if (!up->use_dma) {
 		pm_runtime_get_sync(&up->pdev->dev);
 		serial_omap_enable_ier_thri(up);
-		if (pdata->set_noidle)
+		if (pdata && pdata->set_noidle)
 			pdata->set_noidle(up->pdev);
 		pm_runtime_mark_last_busy(&up->pdev->dev);
 		pm_runtime_put_autosuspend(&up->pdev->dev);
@@ -1613,7 +1613,7 @@
 	struct uart_omap_port *up = dev_get_drvdata(dev);
 	struct omap_uart_port_info *pdata = dev->platform_data;
 
-	if (up) {
+	if (up && pdata) {
 		if (pdata->get_context_loss_count) {
 			u32 loss_cnt = pdata->get_context_loss_count(dev);
 
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 17ae657..332f2eb 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -29,6 +29,7 @@
 #include <linux/nmi.h>
 #include <linux/delay.h>
 
+#include <linux/debugfs.h>
 #include <linux/dmaengine.h>
 #include <linux/pch_dma.h>
 
@@ -144,6 +145,8 @@
 #define PCH_UART_DLL		0x00
 #define PCH_UART_DLM		0x01
 
+#define PCH_UART_BRCSR		0x0E
+
 #define PCH_UART_IID_RLS	(PCH_UART_IIR_REI)
 #define PCH_UART_IID_RDR	(PCH_UART_IIR_RRI)
 #define PCH_UART_IID_RDR_TO	(PCH_UART_IIR_RRI | PCH_UART_IIR_TOI)
@@ -203,7 +206,10 @@
 
 #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
 
-#define DEFAULT_BAUD_RATE 1843200 /* 1.8432MHz */
+#define DEFAULT_UARTCLK   1843200 /*   1.8432 MHz */
+#define CMITC_UARTCLK   192000000 /* 192.0000 MHz */
+#define FRI2_64_UARTCLK  64000000 /*  64.0000 MHz */
+#define FRI2_48_UARTCLK  48000000 /*  48.0000 MHz */
 
 struct pch_uart_buffer {
 	unsigned char *buf;
@@ -218,7 +224,7 @@
 	unsigned int iobase;
 	struct pci_dev *pdev;
 	int fifo_size;
-	int base_baud;
+	int uartclk;
 	int start_tx;
 	int start_rx;
 	int tx_empty;
@@ -243,6 +249,8 @@
 	int				tx_dma_use;
 	void				*rx_buf_virt;
 	dma_addr_t			rx_buf_dma;
+
+	struct dentry	*debugfs;
 };
 
 /**
@@ -287,26 +295,100 @@
 static struct eg20t_port *pch_uart_ports[PCH_UART_NR];
 #endif
 static unsigned int default_baud = 9600;
+static unsigned int user_uartclk = 0;
 static const int trigger_level_256[4] = { 1, 64, 128, 224 };
 static const int trigger_level_64[4] = { 1, 16, 32, 56 };
 static const int trigger_level_16[4] = { 1, 4, 8, 14 };
 static const int trigger_level_1[4] = { 1, 1, 1, 1 };
 
-static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize,
-				 int base_baud)
-{
-	struct eg20t_port *priv = pci_get_drvdata(pdev);
+#ifdef CONFIG_DEBUG_FS
 
-	priv->trigger_level = 1;
-	priv->fcr = 0;
+#define PCH_REGS_BUFSIZE	1024
+static int pch_show_regs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
 }
 
-static unsigned int get_msr(struct eg20t_port *priv, void __iomem *base)
+static ssize_t port_show_regs(struct file *file, char __user *user_buf,
+				size_t count, loff_t *ppos)
 {
-	unsigned int msr = ioread8(base + UART_MSR);
-	priv->dmsr |= msr & PCH_UART_MSR_DELTA;
+	struct eg20t_port *priv = file->private_data;
+	char *buf;
+	u32 len = 0;
+	ssize_t ret;
+	unsigned char lcr;
 
-	return msr;
+	buf = kzalloc(PCH_REGS_BUFSIZE, GFP_KERNEL);
+	if (!buf)
+		return 0;
+
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"PCH EG20T port[%d] regs:\n", priv->port.line);
+
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"=================================\n");
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"IER: \t0x%02x\n", ioread8(priv->membase + UART_IER));
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"IIR: \t0x%02x\n", ioread8(priv->membase + UART_IIR));
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"LCR: \t0x%02x\n", ioread8(priv->membase + UART_LCR));
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"MCR: \t0x%02x\n", ioread8(priv->membase + UART_MCR));
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"LSR: \t0x%02x\n", ioread8(priv->membase + UART_LSR));
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"MSR: \t0x%02x\n", ioread8(priv->membase + UART_MSR));
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"BRCSR: \t0x%02x\n",
+			ioread8(priv->membase + PCH_UART_BRCSR));
+
+	lcr = ioread8(priv->membase + UART_LCR);
+	iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"DLL: \t0x%02x\n", ioread8(priv->membase + UART_DLL));
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"DLM: \t0x%02x\n", ioread8(priv->membase + UART_DLM));
+	iowrite8(lcr, priv->membase + UART_LCR);
+
+	if (len > PCH_REGS_BUFSIZE)
+		len = PCH_REGS_BUFSIZE;
+
+	ret =  simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations port_regs_ops = {
+	.owner		= THIS_MODULE,
+	.open		= pch_show_regs_open,
+	.read		= port_show_regs,
+	.llseek		= default_llseek,
+};
+#endif	/* CONFIG_DEBUG_FS */
+
+/* Return UART clock, checking for board specific clocks. */
+static int pch_uart_get_uartclk(void)
+{
+	const char *cmp;
+
+	if (user_uartclk)
+		return user_uartclk;
+
+	cmp = dmi_get_system_info(DMI_BOARD_NAME);
+	if (cmp && strstr(cmp, "CM-iTC"))
+		return CMITC_UARTCLK;
+
+	cmp = dmi_get_system_info(DMI_BIOS_VERSION);
+	if (cmp && strnstr(cmp, "FRI2", 4))
+		return FRI2_64_UARTCLK;
+
+	cmp = dmi_get_system_info(DMI_PRODUCT_NAME);
+	if (cmp && strstr(cmp, "Fish River Island II"))
+		return FRI2_48_UARTCLK;
+
+	return DEFAULT_UARTCLK;
 }
 
 static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv,
@@ -332,7 +414,7 @@
 	unsigned int dll, dlm, lcr;
 	int div;
 
-	div = DIV_ROUND_CLOSEST(priv->base_baud / 16, baud);
+	div = DIV_ROUND_CLOSEST(priv->uartclk / 16, baud);
 	if (div < 0 || USHRT_MAX <= div) {
 		dev_err(priv->port.dev, "Invalid Baud(div=0x%x)\n", div);
 		return -EINVAL;
@@ -442,8 +524,9 @@
 
 static u8 pch_uart_hal_get_modem(struct eg20t_port *priv)
 {
-	priv->dmsr = 0;
-	return get_msr(priv, priv->membase);
+	unsigned int msr = ioread8(priv->membase + UART_MSR);
+	priv->dmsr = msr & PCH_UART_MSR_DELTA;
+	return (u8)msr;
 }
 
 static void pch_uart_hal_write(struct eg20t_port *priv,
@@ -524,7 +607,7 @@
 
 static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
 {
-	int ret;
+	int ret = 0;
 	struct uart_port *port = &priv->port;
 
 	if (port->x_char) {
@@ -533,8 +616,6 @@
 		buf[0] = port->x_char;
 		port->x_char = 0;
 		ret = 1;
-	} else {
-		ret = 0;
 	}
 
 	return ret;
@@ -1032,14 +1113,12 @@
 static unsigned int pch_uart_tx_empty(struct uart_port *port)
 {
 	struct eg20t_port *priv;
-	int ret;
+
 	priv = container_of(port, struct eg20t_port, port);
 	if (priv->tx_empty)
-		ret = TIOCSER_TEMT;
+		return TIOCSER_TEMT;
 	else
-		ret = 0;
-
-	return ret;
+		return 0;
 }
 
 /* Returns the current state of modem control inputs. */
@@ -1153,9 +1232,9 @@
 	priv->tx_empty = 1;
 
 	if (port->uartclk)
-		priv->base_baud = port->uartclk;
+		priv->uartclk = port->uartclk;
 	else
-		port->uartclk = priv->base_baud;
+		port->uartclk = priv->uartclk;
 
 	pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
 	ret = pch_uart_hal_set_line(priv, default_baud,
@@ -1273,9 +1352,8 @@
 		else
 			parity = PCH_UART_HAL_PARITY_EVEN;
 
-	} else {
+	} else
 		parity = PCH_UART_HAL_PARITY_NONE;
-	}
 
 	/* Only UART0 has auto hardware flow function */
 	if ((termios->c_cflag & CRTSCTS) && (priv->fifo_size == 256))
@@ -1447,7 +1525,6 @@
 pch_console_write(struct console *co, const char *s, unsigned int count)
 {
 	struct eg20t_port *priv;
-
 	unsigned long flags;
 	u8 ier;
 	int locked = 1;
@@ -1489,7 +1566,7 @@
 static int __init pch_console_setup(struct console *co, char *options)
 {
 	struct uart_port *port;
-	int baud = 9600;
+	int baud = default_baud;
 	int bits = 8;
 	int parity = 'n';
 	int flow = 'n';
@@ -1506,8 +1583,7 @@
 	if (!port || (!port->iobase && !port->membase))
 		return -ENODEV;
 
-	/* setup uartclock */
-	port->uartclk = DEFAULT_BAUD_RATE;
+	port->uartclk = pch_uart_get_uartclk();
 
 	if (options)
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -1550,10 +1626,10 @@
 	unsigned int iobase;
 	unsigned int mapbase;
 	unsigned char *rxbuf;
-	int fifosize, base_baud;
+	int fifosize;
 	int port_type;
 	struct pch_uart_driver_data *board;
-	const char *board_name;
+	char name[32];	/* for debugfs file name */
 
 	board = &drv_dat[id->driver_data];
 	port_type = board->port_type;
@@ -1566,13 +1642,6 @@
 	if (!rxbuf)
 		goto init_port_free_txbuf;
 
-	base_baud = DEFAULT_BAUD_RATE;
-
-	/* quirk for CM-iTC board */
-	board_name = dmi_get_system_info(DMI_BOARD_NAME);
-	if (board_name && strstr(board_name, "CM-iTC"))
-		base_baud = 192000000; /* 192.0MHz */
-
 	switch (port_type) {
 	case PORT_UNKNOWN:
 		fifosize = 256; /* EG20T/ML7213: UART0 */
@@ -1597,7 +1666,7 @@
 	priv->rxbuf.size = PAGE_SIZE;
 
 	priv->fifo_size = fifosize;
-	priv->base_baud = base_baud;
+	priv->uartclk = pch_uart_get_uartclk();
 	priv->port_type = PORT_MAX_8250 + port_type + 1;
 	priv->port.dev = &pdev->dev;
 	priv->port.iobase = iobase;
@@ -1614,7 +1683,8 @@
 	spin_lock_init(&priv->port.lock);
 
 	pci_set_drvdata(pdev, priv);
-	pch_uart_hal_request(pdev, fifosize, base_baud);
+	priv->trigger_level = 1;
+	priv->fcr = 0;
 
 #ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
 	pch_uart_ports[board->line_no] = priv;
@@ -1623,6 +1693,12 @@
 	if (ret < 0)
 		goto init_port_hal_free;
 
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof(name), "uart%d_regs", board->line_no);
+	priv->debugfs = debugfs_create_file(name, S_IFREG | S_IRUGO,
+				NULL, priv, &port_regs_ops);
+#endif
+
 	return priv;
 
 init_port_hal_free:
@@ -1639,6 +1715,11 @@
 
 static void pch_uart_exit_port(struct eg20t_port *priv)
 {
+
+#ifdef CONFIG_DEBUG_FS
+	if (priv->debugfs)
+		debugfs_remove(priv->debugfs);
+#endif
 	uart_remove_one_port(&pch_uart_driver, &priv->port);
 	pci_set_drvdata(priv->pdev, NULL);
 	free_page((unsigned long)priv->rxbuf.buf);
@@ -1646,9 +1727,7 @@
 
 static void pch_uart_pci_remove(struct pci_dev *pdev)
 {
-	struct eg20t_port *priv;
-
-	priv = (struct eg20t_port *)pci_get_drvdata(pdev);
+	struct eg20t_port *priv = pci_get_drvdata(pdev);
 
 	pci_disable_msi(pdev);
 
@@ -1785,3 +1864,8 @@
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver");
 module_param(default_baud, uint, S_IRUGO);
+MODULE_PARM_DESC(default_baud,
+                 "Default BAUD for initial driver state and console (default 9600)");
+module_param(user_uartclk, uint, S_IRUGO);
+MODULE_PARM_DESC(user_uartclk,
+                 "Override UART default or board specific UART clock");
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index e9c2dfe4..08ebe90 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -1506,7 +1506,7 @@
 	 * fixed up interrupt info, but we use the device-tree directly
 	 * here due to early probing so we need the fixup too.
 	 */
-	if (uap->port.irq == NO_IRQ &&
+	if (uap->port.irq == 0 &&
 	    np->parent && np->parent->parent &&
 	    of_device_is_compatible(np->parent->parent, "gatwick")) {
 		/* IRQs on gatwick are offset by 64 */
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 5c8e3bb..e2fd3d8 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -579,9 +579,9 @@
 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
 
 	if (!state)
-		clk_enable(up->clk);
+		clk_prepare_enable(up->clk);
 	else
-		clk_disable(up->clk);
+		clk_disable_unprepare(up->clk);
 }
 
 static void serial_pxa_release_port(struct uart_port *port)
@@ -668,7 +668,7 @@
 	struct uart_pxa_port *up = serial_pxa_ports[co->index];
 	unsigned int ier;
 
-	clk_enable(up->clk);
+	clk_prepare_enable(up->clk);
 
 	/*
 	 *	First save the IER then disable the interrupts
@@ -685,7 +685,7 @@
 	wait_for_xmitr(up);
 	serial_out(up, UART_IER, ier);
 
-	clk_disable(up->clk);
+	clk_disable_unprepare(up->clk);
 }
 
 static int __init
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index c55e5fb..de249d2 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -1507,7 +1507,7 @@
 #endif
 
 #if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2416) || \
-	defined(CONFIG_CPU_S3C2443)
+	defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2442)
 static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = {
 	.info = &(struct s3c24xx_uart_info) {
 		.name		= "Samsung S3C2440 UART",
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 1305618..9c4c05b 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2230,7 +2230,6 @@
 
 	drv->tty_driver = normal;
 
-	normal->owner		= drv->owner;
 	normal->driver_name	= drv->driver_name;
 	normal->name		= drv->dev_name;
 	normal->major		= drv->major;
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 7508579..61b7fd2 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1710,6 +1710,8 @@
 
 	dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
 
+	pm_runtime_put_noidle(port->dev);
+
 	sci_port_enable(s);
 
 	ret = sci_request_irq(s);
@@ -1737,6 +1739,8 @@
 	sci_free_irq(s);
 
 	sci_port_disable(s);
+
+	pm_runtime_get_noresume(port->dev);
 }
 
 static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps,
@@ -2075,6 +2079,7 @@
 		sci_init_gpios(sci_port);
 
 		pm_runtime_irq_safe(&dev->dev);
+		pm_runtime_get_noresume(&dev->dev);
 		pm_runtime_enable(&dev->dev);
 	}
 
diff --git a/drivers/tty/serial/sn_console.c b/drivers/tty/serial/sn_console.c
index 238c7df..4e1b551 100644
--- a/drivers/tty/serial/sn_console.c
+++ b/drivers/tty/serial/sn_console.c
@@ -461,12 +461,12 @@
 	struct tty_struct *tty;
 
 	if (!port) {
-		printk(KERN_ERR "sn_receive_chars - port NULL so can't receieve\n");
+		printk(KERN_ERR "sn_receive_chars - port NULL so can't receive\n");
 		return;
 	}
 
 	if (!port->sc_ops) {
-		printk(KERN_ERR "sn_receive_chars - port->sc_ops  NULL so can't receieve\n");
+		printk(KERN_ERR "sn_receive_chars - port->sc_ops  NULL so can't receive\n");
 		return;
 	}
 
diff --git a/drivers/tty/serial/suncore.c b/drivers/tty/serial/suncore.c
index 6381a02..6e4ac8d 100644
--- a/drivers/tty/serial/suncore.c
+++ b/drivers/tty/serial/suncore.c
@@ -17,11 +17,11 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/serial_core.h>
+#include <linux/sunserialcore.h>
 #include <linux/init.h>
 
 #include <asm/prom.h>
 
-#include "suncore.h"
 
 static int sunserial_current_minor = 64;
 
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index c0b7246..3ba5d28 100644
--- a/drivers/tty/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
@@ -29,8 +29,7 @@
 #endif
 
 #include <linux/serial_core.h>
-
-#include "suncore.h"
+#include <linux/sunserialcore.h>
 
 #define CON_BREAK	((long)-1)
 #define CON_HUP		((long)-2)
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
index b5fa2a5..62dacd0 100644
--- a/drivers/tty/serial/sunsab.c
+++ b/drivers/tty/serial/sunsab.c
@@ -43,8 +43,8 @@
 #endif
 
 #include <linux/serial_core.h>
+#include <linux/sunserialcore.h>
 
-#include "suncore.h"
 #include "sunsab.h"
 
 struct uart_sunsab_port {
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index ad0f8f5..d3ca6da 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -47,8 +47,7 @@
 #endif
 
 #include <linux/serial_core.h>
-
-#include "suncore.h"
+#include <linux/sunserialcore.h>
 
 /* We are on a NS PC87303 clocked with 24.0 MHz, which results
  * in a UART clock of 1.8462 MHz.
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
index 8e916e7..da44158 100644
--- a/drivers/tty/serial/sunzilog.c
+++ b/drivers/tty/serial/sunzilog.c
@@ -43,8 +43,8 @@
 #endif
 
 #include <linux/serial_core.h>
+#include <linux/sunserialcore.h>
 
-#include "suncore.h"
 #include "sunzilog.h"
 
 /* On 32-bit sparcs we need to delay after register accesses
@@ -1397,7 +1397,7 @@
 #endif
 }
 
-static int zilog_irq = -1;
+static int zilog_irq;
 
 static int __devinit zs_probe(struct platform_device *op)
 {
@@ -1425,7 +1425,7 @@
 
 	rp = sunzilog_chip_regs[inst];
 
-	if (zilog_irq == -1)
+	if (!zilog_irq)
 		zilog_irq = op->archdata.irqs[0];
 
 	up = &sunzilog_port_table[inst * 2];
@@ -1580,7 +1580,7 @@
 	if (err)
 		goto out_unregister_uart;
 
-	if (zilog_irq != -1) {
+	if (!zilog_irq) {
 		struct uart_sunzilog_port *up = sunzilog_irq_chain;
 		err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
 				  "zs", sunzilog_irq_chain);
@@ -1621,7 +1621,7 @@
 {
 	platform_driver_unregister(&zs_driver);
 
-	if (zilog_irq != -1) {
+	if (!zilog_irq) {
 		struct uart_sunzilog_port *up = sunzilog_irq_chain;
 
 		/* Disable Interrupts */
@@ -1637,7 +1637,7 @@
 		}
 
 		free_irq(zilog_irq, sunzilog_irq_chain);
-		zilog_irq = -1;
+		zilog_irq = 0;
 	}
 
 	if (sunzilog_reg.nr) {
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index 2ebe606..f99b0c9 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -1360,7 +1360,7 @@
 	}
 
 	qe_port->port.irq = irq_of_parse_and_map(np, 0);
-	if (qe_port->port.irq == NO_IRQ) {
+	if (qe_port->port.irq == 0) {
 		dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n",
 		       qe_port->ucc_num + 1);
 		ret = -EINVAL;
diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c
index 83148e7..cf0d948 100644
--- a/drivers/tty/serial/vr41xx_siu.c
+++ b/drivers/tty/serial/vr41xx_siu.c
@@ -61,7 +61,7 @@
 static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = {
 	[0 ... SIU_PORTS_MAX-1] = {
 		.lock	= __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock),
-		.irq	= -1,
+		.irq	= 0,
 	},
 };
 
@@ -171,7 +171,7 @@
 {
 	if (port->line == 0)
 		return PORT_VR41XX_SIU;
-	if (port->line == 1 && port->irq != -1)
+	if (port->line == 1 && port->irq)
 		return PORT_VR41XX_DSIU;
 
 	return PORT_UNKNOWN;
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index 026cb9e..2be006f 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -544,7 +544,7 @@
 	.cons		= VT8500_CONSOLE,
 };
 
-static int __init vt8500_serial_probe(struct platform_device *pdev)
+static int __devinit vt8500_serial_probe(struct platform_device *pdev)
 {
 	struct vt8500_port *vt8500_port;
 	struct resource *mmres, *irqres;
@@ -605,7 +605,7 @@
 
 static struct platform_driver vt8500_platform_driver = {
 	.probe  = vt8500_serial_probe,
-	.remove = vt8500_serial_remove,
+	.remove = __devexit_p(vt8500_serial_remove),
 	.driver = {
 		.name = "vt8500_serial",
 		.owner = THIS_MODULE,
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index ff8017f..8e518da 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -3381,7 +3381,7 @@
 
 	/* verify range of specified line number */	
 	line = tty->index;
-	if ((line < 0) || (line >= mgsl_device_count)) {
+	if (line >= mgsl_device_count) {
 		printk("%s(%d):mgsl_open with invalid line #%d.\n",
 			__FILE__,__LINE__,line);
 		return -ENODEV;
@@ -4333,7 +4333,6 @@
 	if (!serial_driver)
 		return -ENOMEM;
 	
-	serial_driver->owner = THIS_MODULE;
 	serial_driver->driver_name = "synclink";
 	serial_driver->name = "ttySL";
 	serial_driver->major = ttymajor;
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index 18b48cd..6bee490 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -654,7 +654,7 @@
 	unsigned long flags;
 
 	line = tty->index;
-	if ((line < 0) || (line >= slgt_device_count)) {
+	if (line >= slgt_device_count) {
 		DBGERR(("%s: open with invalid line #%d.\n", driver_name, line));
 		return -ENODEV;
 	}
@@ -3795,7 +3795,6 @@
 
 	/* Initialize the tty_driver structure */
 
-	serial_driver->owner = THIS_MODULE;
 	serial_driver->driver_name = tty_driver_name;
 	serial_driver->name = tty_dev_prefix;
 	serial_driver->major = ttymajor;
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index a7efe53..4fb6c4b 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -721,7 +721,7 @@
 	unsigned long flags;
 
 	line = tty->index;
-	if ((line < 0) || (line >= synclinkmp_device_count)) {
+	if (line >= synclinkmp_device_count) {
 		printk("%s(%d): open with invalid line #%d.\n",
 			__FILE__,__LINE__,line);
 		return -ENODEV;
@@ -3977,7 +3977,6 @@
 
 	/* Initialize the tty_driver structure */
 
-	serial_driver->owner = THIS_MODULE;
 	serial_driver->driver_name = "synclinkmp";
 	serial_driver->name = "ttySLM";
 	serial_driver->major = ttymajor;
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 7867b7c..ecb8e22 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -110,11 +110,9 @@
 #ifdef CONFIG_VT
 static void sysrq_handle_unraw(int key)
 {
-	struct kbd_struct *kbd = &kbd_table[fg_console];
-
-	if (kbd)
-		kbd->kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
+	vt_reset_unicode(fg_console);
 }
+
 static struct sysrq_key_op sysrq_unraw_op = {
 	.handler	= sysrq_handle_unraw,
 	.help_msg	= "unRaw",
@@ -322,11 +320,16 @@
 {
 	struct task_struct *p;
 
+	read_lock(&tasklist_lock);
 	for_each_process(p) {
-		if (p->mm && !is_global_init(p))
-			/* Not swapper, init nor kernel thread */
-			force_sig(sig, p);
+		if (p->flags & PF_KTHREAD)
+			continue;
+		if (is_global_init(p))
+			continue;
+
+		force_sig(sig, p);
 	}
+	read_unlock(&tasklist_lock);
 }
 
 static void sysrq_handle_term(int key)
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index e41b9bb..dd8a938 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1230,13 +1230,10 @@
 static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
 		struct inode *inode, int idx)
 {
-	struct tty_struct *tty;
-
 	if (driver->ops->lookup)
 		return driver->ops->lookup(driver, inode, idx);
 
-	tty = driver->ttys[idx];
-	return tty;
+	return driver->ttys[idx];
 }
 
 /**
@@ -1271,6 +1268,19 @@
 }
 EXPORT_SYMBOL_GPL(tty_init_termios);
 
+int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+	int ret = tty_init_termios(tty);
+	if (ret)
+		return ret;
+
+	tty_driver_kref_get(driver);
+	tty->count++;
+	driver->ttys[tty->index] = tty;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tty_standard_install);
+
 /**
  *	tty_driver_install_tty() - install a tty entry in the driver
  *	@driver: the driver for the tty
@@ -1286,21 +1296,8 @@
 static int tty_driver_install_tty(struct tty_driver *driver,
 						struct tty_struct *tty)
 {
-	int idx = tty->index;
-	int ret;
-
-	if (driver->ops->install) {
-		ret = driver->ops->install(driver, tty);
-		return ret;
-	}
-
-	if (tty_init_termios(tty) == 0) {
-		tty_driver_kref_get(driver);
-		tty->count++;
-		driver->ttys[idx] = tty;
-		return 0;
-	}
-	return -ENOMEM;
+	return driver->ops->install ? driver->ops->install(driver, tty) :
+		tty_standard_install(driver, tty);
 }
 
 /**
@@ -1351,7 +1348,6 @@
 		tty->link->count++;
 	}
 	tty->count++;
-	tty->driver = driver; /* N.B. why do this every time?? */
 
 	mutex_lock(&tty->ldisc_mutex);
 	WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
@@ -1365,7 +1361,6 @@
  *	@driver: tty driver we are opening a device on
  *	@idx: device index
  *	@ret_tty: returned tty structure
- *	@first_ok: ok to open a new device (used by ptmx)
  *
  *	Prepare a tty device. This may not be a "new" clean device but
  *	could also be an active device. The pty drivers require special
@@ -1385,18 +1380,11 @@
  * relaxed for the (most common) case of reopening a tty.
  */
 
-struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
-								int first_ok)
+struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
 {
 	struct tty_struct *tty;
 	int retval;
 
-	/* Check if pty master is being opened multiple times */
-	if (driver->subtype == PTY_TYPE_MASTER &&
-		(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
-		return ERR_PTR(-EIO);
-	}
-
 	/*
 	 * First time open is complex, especially for PTY devices.
 	 * This code guarantees that either everything succeeds and the
@@ -1950,7 +1938,7 @@
 		if (retval)
 			tty = ERR_PTR(retval);
 	} else
-		tty = tty_init_dev(driver, index, 0);
+		tty = tty_init_dev(driver, index);
 
 	mutex_unlock(&tty_mutex);
 	if (driver)
@@ -2941,7 +2929,6 @@
 	tty->session = NULL;
 	tty->pgrp = NULL;
 	tty->overrun_time = jiffies;
-	tty->buf.head = tty->buf.tail = NULL;
 	tty_buffer_init(tty);
 	mutex_init(&tty->termios_mutex);
 	mutex_init(&tty->ldisc_mutex);
@@ -3058,7 +3045,7 @@
 }
 EXPORT_SYMBOL(tty_unregister_device);
 
-struct tty_driver *alloc_tty_driver(int lines)
+struct tty_driver *__alloc_tty_driver(int lines, struct module *owner)
 {
 	struct tty_driver *driver;
 
@@ -3067,11 +3054,12 @@
 		kref_init(&driver->kref);
 		driver->magic = TTY_DRIVER_MAGIC;
 		driver->num = lines;
+		driver->owner = owner;
 		/* later we'll move allocation of tables here */
 	}
 	return driver;
 }
-EXPORT_SYMBOL(alloc_tty_driver);
+EXPORT_SYMBOL(__alloc_tty_driver);
 
 static void destruct_tty_driver(struct kref *kref)
 {
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index a0f3d6c..8308fc7 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -516,6 +516,7 @@
 	int err = 0, err1, i;
 	struct uni_pagedir *p, *q;
 
+	/* Save original vc_unipagdir_loc in case we allocate a new one */
 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 	if (p->readonly) return -EIO;
 	
@@ -528,26 +529,57 @@
 		err1 = con_clear_unimap(vc, NULL);
 		if (err1) return err1;
 		
+		/*
+		 * Since refcount was > 1, con_clear_unimap() allocated a
+		 * a new uni_pagedir for this vc.  Re: p != q
+		 */
 		q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-		for (i = 0, l = 0; i < 32; i++)
+
+		/*
+		 * uni_pgdir is a 32*32*64 table with rows allocated
+		 * when its first entry is added.  The unicode value must
+		 * still be incremented for empty rows.  We are copying
+		 * entries from "p" (old) to "q" (new).
+		 */
+		l = 0;		/* unicode value */
+		for (i = 0; i < 32; i++)
 		if ((p1 = p->uni_pgdir[i]))
 			for (j = 0; j < 32; j++)
-			if ((p2 = p1[j]))
+			if ((p2 = p1[j])) {
 				for (k = 0; k < 64; k++, l++)
 				if (p2[k] != 0xffff) {
+					/*
+					 * Found one, copy entry for unicode
+					 * l with fontpos value p2[k].
+					 */
 					err1 = con_insert_unipair(q, l, p2[k]);
 					if (err1) {
 						p->refcount++;
 						*vc->vc_uni_pagedir_loc = (unsigned long)p;
 						con_release_unimap(q);
 						kfree(q);
-						return err1; 
+						return err1;
 					}
-              			}
-              	p = q;
-	} else if (p == dflt)
+				}
+			} else {
+				/* Account for row of 64 empty entries */
+				l += 64;
+			}
+		else
+			/* Account for empty table */
+			l += 32 * 64;
+
+		/*
+		 * Finished copying font table, set vc_uni_pagedir to new table
+		 */
+		p = q;
+	} else if (p == dflt) {
 		dflt = NULL;
-	
+	}
+
+	/*
+	 * Insert user specified unicode pairs into new table.
+	 */
 	while (ct--) {
 		unsigned short unicode, fontpos;
 		__get_user(unicode, &list->unicode);
@@ -557,11 +589,14 @@
 		list++;
 	}
 	
+	/*
+	 * Merge with fontmaps of any other virtual consoles.
+	 */
 	if (con_unify_unimap(vc, p))
 		return err;
 
 	for (i = 0; i <= 3; i++)
-		set_inverse_transl(vc, p, i); /* Update all inverse translations */
+		set_inverse_transl(vc, p, i); /* Update inverse translations */
 	set_inverse_trans_unicode(vc, p);
   
 	return err;
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index a605549..86dd1e3 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -41,6 +41,7 @@
 #include <linux/reboot.h>
 #include <linux/notifier.h>
 #include <linux/jiffies.h>
+#include <linux/uaccess.h>
 
 #include <asm/irq_regs.h>
 
@@ -55,8 +56,8 @@
 /*
  * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
  * This seems a good reason to start with NumLock off. On HIL keyboards
- * of PARISC machines however there is no NumLock key and everyone expects the keypad
- * to be used for numbers.
+ * of PARISC machines however there is no NumLock key and everyone expects the
+ * keypad to be used for numbers.
  */
 
 #if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
@@ -67,8 +68,6 @@
 
 #define KBD_DEFLOCK 0
 
-void compute_shiftstate(void);
-
 /*
  * Handler Tables.
  */
@@ -99,35 +98,29 @@
  * Variables exported for vt_ioctl.c
  */
 
-/* maximum values each key_handler can handle */
-const int max_vals[] = {
-	255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
-	NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
-	255, NR_LOCK - 1, 255, NR_BRL - 1
-};
-
-const int NR_TYPES = ARRAY_SIZE(max_vals);
-
-struct kbd_struct kbd_table[MAX_NR_CONSOLES];
-EXPORT_SYMBOL_GPL(kbd_table);
-static struct kbd_struct *kbd = kbd_table;
-
 struct vt_spawn_console vt_spawn_con = {
 	.lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock),
 	.pid  = NULL,
 	.sig  = 0,
 };
 
-/*
- * Variables exported for vt.c
- */
-
-int shift_state = 0;
 
 /*
  * Internal Data.
  */
 
+static struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+static struct kbd_struct *kbd = kbd_table;
+
+/* maximum values each key_handler can handle */
+static const int max_vals[] = {
+	255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
+	NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
+	255, NR_LOCK - 1, 255, NR_BRL - 1
+};
+
+static const int NR_TYPES = ARRAY_SIZE(max_vals);
+
 static struct input_handler kbd_handler;
 static DEFINE_SPINLOCK(kbd_event_lock);
 static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];	/* keyboard key bitmap */
@@ -137,6 +130,8 @@
 static unsigned int diacr;
 static char rep;					/* flag telling character repeat */
 
+static int shift_state = 0;
+
 static unsigned char ledstate = 0xff;			/* undefined */
 static unsigned char ledioctl;
 
@@ -187,7 +182,7 @@
 	return d->error == 0; /* stop as soon as we successfully get one */
 }
 
-int getkeycode(unsigned int scancode)
+static int getkeycode(unsigned int scancode)
 {
 	struct getset_keycode_data d = {
 		.ke	= {
@@ -214,7 +209,7 @@
 	return d->error == 0; /* stop as soon as we successfully set one */
 }
 
-int setkeycode(unsigned int scancode, unsigned int keycode)
+static int setkeycode(unsigned int scancode, unsigned int keycode)
 {
 	struct getset_keycode_data d = {
 		.ke	= {
@@ -382,9 +377,11 @@
 /*
  * Called after returning from RAW mode or when changing consoles - recompute
  * shift_down[] and shift_state from key_down[] maybe called when keymap is
- * undefined, so that shiftkey release is seen
+ * undefined, so that shiftkey release is seen. The caller must hold the
+ * kbd_event_lock.
  */
-void compute_shiftstate(void)
+
+static void do_compute_shiftstate(void)
 {
 	unsigned int i, j, k, sym, val;
 
@@ -417,6 +414,15 @@
 	}
 }
 
+/* We still have to export this method to vt.c */
+void compute_shiftstate(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	do_compute_shiftstate();
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+}
+
 /*
  * We have a combining character DIACR here, followed by the character CH.
  * If the combination occurs in the table, return the corresponding value.
@@ -636,7 +642,7 @@
 
 static void fn_null(struct vc_data *vc)
 {
-	compute_shiftstate();
+	do_compute_shiftstate();
 }
 
 /*
@@ -989,6 +995,8 @@
 
 void setledstate(struct kbd_struct *kbd, unsigned int led)
 {
+        unsigned long flags;
+        spin_lock_irqsave(&kbd_event_lock, flags);
 	if (!(led & ~7)) {
 		ledioctl = led;
 		kbd->ledmode = LED_SHOW_IOCTL;
@@ -996,6 +1004,7 @@
 		kbd->ledmode = LED_SHOW_FLAGS;
 
 	set_leds();
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
 }
 
 static inline unsigned char getleds(void)
@@ -1035,6 +1044,75 @@
 	return 0;
 }
 
+/**
+ *	vt_get_leds	-	helper for braille console
+ *	@console: console to read
+ *	@flag: flag we want to check
+ *
+ *	Check the status of a keyboard led flag and report it back
+ */
+int vt_get_leds(int console, int flag)
+{
+	unsigned long flags;
+	struct kbd_struct * kbd = kbd_table + console;
+	int ret;
+
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	ret = vc_kbd_led(kbd, flag);
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(vt_get_leds);
+
+/**
+ *	vt_set_led_state	-	set LED state of a console
+ *	@console: console to set
+ *	@leds: LED bits
+ *
+ *	Set the LEDs on a console. This is a wrapper for the VT layer
+ *	so that we can keep kbd knowledge internal
+ */
+void vt_set_led_state(int console, int leds)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	setledstate(kbd, leds);
+}
+
+/**
+ *	vt_kbd_con_start	-	Keyboard side of console start
+ *	@console: console
+ *
+ *	Handle console start. This is a wrapper for the VT layer
+ *	so that we can keep kbd knowledge internal
+ */
+void vt_kbd_con_start(int console)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	unsigned long flags;
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	clr_vc_kbd_led(kbd, VC_SCROLLOCK);
+	set_leds();
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+}
+
+/**
+ *	vt_kbd_con_stop		-	Keyboard side of console stop
+ *	@console: console
+ *
+ *	Handle console stop. This is a wrapper for the VT layer
+ *	so that we can keep kbd knowledge internal
+ */
+void vt_kbd_con_stop(int console)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	unsigned long flags;
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	set_vc_kbd_led(kbd, VC_SCROLLOCK);
+	set_leds();
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+}
+
 /*
  * This is the tasklet that updates LED state on all keyboards
  * attached to the box. The reason we use tasklet is that we
@@ -1254,7 +1332,7 @@
 	if (rc == NOTIFY_STOP || !key_map) {
 		atomic_notifier_call_chain(&keyboard_notifier_list,
 					   KBD_UNBOUND_KEYCODE, &param);
-		compute_shiftstate();
+		do_compute_shiftstate();
 		kbd->slockstate = 0;
 		return;
 	}
@@ -1404,14 +1482,14 @@
 
 static const struct input_device_id kbd_ids[] = {
 	{
-                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-                .evbit = { BIT_MASK(EV_KEY) },
-        },
+		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+		.evbit = { BIT_MASK(EV_KEY) },
+	},
 
 	{
-                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-                .evbit = { BIT_MASK(EV_SND) },
-        },
+		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+		.evbit = { BIT_MASK(EV_SND) },
+	},
 
 	{ },    /* Terminating entry */
 };
@@ -1433,7 +1511,7 @@
 	int i;
 	int error;
 
-        for (i = 0; i < MAX_NR_CONSOLES; i++) {
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
 		kbd_table[i].ledflagstate = KBD_DEFLEDS;
 		kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
 		kbd_table[i].ledmode = LED_SHOW_FLAGS;
@@ -1452,3 +1530,658 @@
 
 	return 0;
 }
+
+/* Ioctl support code */
+
+/**
+ *	vt_do_diacrit		-	diacritical table updates
+ *	@cmd: ioctl request
+ *	@up: pointer to user data for ioctl
+ *	@perm: permissions check computed by caller
+ *
+ *	Update the diacritical tables atomically and safely. Lock them
+ *	against simultaneous keypresses
+ */
+int vt_do_diacrit(unsigned int cmd, void __user *up, int perm)
+{
+	struct kbdiacrs __user *a = up;
+	unsigned long flags;
+	int asize;
+	int ret = 0;
+
+	switch (cmd) {
+	case KDGKBDIACR:
+	{
+		struct kbdiacr *diacr;
+		int i;
+
+		diacr = kmalloc(MAX_DIACR * sizeof(struct kbdiacr),
+								GFP_KERNEL);
+		if (diacr == NULL)
+			return -ENOMEM;
+
+		/* Lock the diacriticals table, make a copy and then
+		   copy it after we unlock */
+		spin_lock_irqsave(&kbd_event_lock, flags);
+
+		asize = accent_table_size;
+		for (i = 0; i < asize; i++) {
+			diacr[i].diacr = conv_uni_to_8bit(
+						accent_table[i].diacr);
+			diacr[i].base = conv_uni_to_8bit(
+						accent_table[i].base);
+			diacr[i].result = conv_uni_to_8bit(
+						accent_table[i].result);
+		}
+		spin_unlock_irqrestore(&kbd_event_lock, flags);
+
+		if (put_user(asize, &a->kb_cnt))
+			ret = -EFAULT;
+		else  if (copy_to_user(a->kbdiacr, diacr,
+				asize * sizeof(struct kbdiacr)))
+			ret = -EFAULT;
+		kfree(diacr);
+		return ret;
+	}
+	case KDGKBDIACRUC:
+	{
+		struct kbdiacrsuc __user *a = up;
+		void *buf;
+
+		buf = kmalloc(MAX_DIACR * sizeof(struct kbdiacruc),
+								GFP_KERNEL);
+		if (buf == NULL)
+			return -ENOMEM;
+
+		/* Lock the diacriticals table, make a copy and then
+		   copy it after we unlock */
+		spin_lock_irqsave(&kbd_event_lock, flags);
+
+		asize = accent_table_size;
+		memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc));
+
+		spin_unlock_irqrestore(&kbd_event_lock, flags);
+
+		if (put_user(asize, &a->kb_cnt))
+			ret = -EFAULT;
+		else if (copy_to_user(a->kbdiacruc, buf,
+				asize*sizeof(struct kbdiacruc)))
+			ret = -EFAULT;
+		kfree(buf);
+		return ret;
+	}
+
+	case KDSKBDIACR:
+	{
+		struct kbdiacrs __user *a = up;
+		struct kbdiacr *diacr = NULL;
+		unsigned int ct;
+		int i;
+
+		if (!perm)
+			return -EPERM;
+		if (get_user(ct, &a->kb_cnt))
+			return -EFAULT;
+		if (ct >= MAX_DIACR)
+			return -EINVAL;
+
+		if (ct) {
+			diacr = kmalloc(sizeof(struct kbdiacr) * ct,
+								GFP_KERNEL);
+			if (diacr == NULL)
+				return -ENOMEM;
+
+			if (copy_from_user(diacr, a->kbdiacr,
+					sizeof(struct kbdiacr) * ct)) {
+				kfree(diacr);
+				return -EFAULT;
+			}
+		}
+
+		spin_lock_irqsave(&kbd_event_lock, flags);
+		accent_table_size = ct;
+		for (i = 0; i < ct; i++) {
+			accent_table[i].diacr =
+					conv_8bit_to_uni(diacr[i].diacr);
+			accent_table[i].base =
+					conv_8bit_to_uni(diacr[i].base);
+			accent_table[i].result =
+					conv_8bit_to_uni(diacr[i].result);
+		}
+		spin_unlock_irqrestore(&kbd_event_lock, flags);
+		kfree(diacr);
+		return 0;
+	}
+
+	case KDSKBDIACRUC:
+	{
+		struct kbdiacrsuc __user *a = up;
+		unsigned int ct;
+		void *buf = NULL;
+
+		if (!perm)
+			return -EPERM;
+
+		if (get_user(ct, &a->kb_cnt))
+			return -EFAULT;
+
+		if (ct >= MAX_DIACR)
+			return -EINVAL;
+
+		if (ct) {
+			buf = kmalloc(ct * sizeof(struct kbdiacruc),
+								GFP_KERNEL);
+			if (buf == NULL)
+				return -ENOMEM;
+
+			if (copy_from_user(buf, a->kbdiacruc,
+					ct * sizeof(struct kbdiacruc))) {
+				kfree(buf);
+				return -EFAULT;
+			}
+		} 
+		spin_lock_irqsave(&kbd_event_lock, flags);
+		if (ct)
+			memcpy(accent_table, buf,
+					ct * sizeof(struct kbdiacruc));
+		accent_table_size = ct;
+		spin_unlock_irqrestore(&kbd_event_lock, flags);
+		kfree(buf);
+		return 0;
+	}
+	}
+	return ret;
+}
+
+/**
+ *	vt_do_kdskbmode		-	set keyboard mode ioctl
+ *	@console: the console to use
+ *	@arg: the requested mode
+ *
+ *	Update the keyboard mode bits while holding the correct locks.
+ *	Return 0 for success or an error code.
+ */
+int vt_do_kdskbmode(int console, unsigned int arg)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	switch(arg) {
+	case K_RAW:
+		kbd->kbdmode = VC_RAW;
+		break;
+	case K_MEDIUMRAW:
+		kbd->kbdmode = VC_MEDIUMRAW;
+		break;
+	case K_XLATE:
+		kbd->kbdmode = VC_XLATE;
+		do_compute_shiftstate();
+		break;
+	case K_UNICODE:
+		kbd->kbdmode = VC_UNICODE;
+		do_compute_shiftstate();
+		break;
+	case K_OFF:
+		kbd->kbdmode = VC_OFF;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+	return ret;
+}
+
+/**
+ *	vt_do_kdskbmeta		-	set keyboard meta state
+ *	@console: the console to use
+ *	@arg: the requested meta state
+ *
+ *	Update the keyboard meta bits while holding the correct locks.
+ *	Return 0 for success or an error code.
+ */
+int vt_do_kdskbmeta(int console, unsigned int arg)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	switch(arg) {
+	case K_METABIT:
+		clr_vc_kbd_mode(kbd, VC_META);
+		break;
+	case K_ESCPREFIX:
+		set_vc_kbd_mode(kbd, VC_META);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+	return ret;
+}
+
+int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc,
+								int perm)
+{
+	struct kbkeycode tmp;
+	int kc = 0;
+
+	if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
+		return -EFAULT;
+	switch (cmd) {
+	case KDGETKEYCODE:
+		kc = getkeycode(tmp.scancode);
+		if (kc >= 0)
+			kc = put_user(kc, &user_kbkc->keycode);
+		break;
+	case KDSETKEYCODE:
+		if (!perm)
+			return -EPERM;
+		kc = setkeycode(tmp.scancode, tmp.keycode);
+		break;
+	}
+	return kc;
+}
+
+#define i (tmp.kb_index)
+#define s (tmp.kb_table)
+#define v (tmp.kb_value)
+
+int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
+						int console)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	struct kbentry tmp;
+	ushort *key_map, *new_map, val, ov;
+	unsigned long flags;
+
+	if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
+		return -EFAULT;
+
+	if (!capable(CAP_SYS_TTY_CONFIG))
+		perm = 0;
+
+	switch (cmd) {
+	case KDGKBENT:
+		/* Ensure another thread doesn't free it under us */
+		spin_lock_irqsave(&kbd_event_lock, flags);
+		key_map = key_maps[s];
+		if (key_map) {
+		    val = U(key_map[i]);
+		    if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
+			val = K_HOLE;
+		} else
+		    val = (i ? K_HOLE : K_NOSUCHMAP);
+		spin_unlock_irqrestore(&kbd_event_lock, flags);
+		return put_user(val, &user_kbe->kb_value);
+	case KDSKBENT:
+		if (!perm)
+			return -EPERM;
+		if (!i && v == K_NOSUCHMAP) {
+			spin_lock_irqsave(&kbd_event_lock, flags);
+			/* deallocate map */
+			key_map = key_maps[s];
+			if (s && key_map) {
+			    key_maps[s] = NULL;
+			    if (key_map[0] == U(K_ALLOCATED)) {
+					kfree(key_map);
+					keymap_count--;
+			    }
+			}
+			spin_unlock_irqrestore(&kbd_event_lock, flags);
+			break;
+		}
+
+		if (KTYP(v) < NR_TYPES) {
+		    if (KVAL(v) > max_vals[KTYP(v)])
+				return -EINVAL;
+		} else
+		    if (kbd->kbdmode != VC_UNICODE)
+				return -EINVAL;
+
+		/* ++Geert: non-PC keyboards may generate keycode zero */
+#if !defined(__mc68000__) && !defined(__powerpc__)
+		/* assignment to entry 0 only tests validity of args */
+		if (!i)
+			break;
+#endif
+
+		new_map = kmalloc(sizeof(plain_map), GFP_KERNEL);
+		if (!new_map)
+			return -ENOMEM;
+		spin_lock_irqsave(&kbd_event_lock, flags);
+		key_map = key_maps[s];
+		if (key_map == NULL) {
+			int j;
+
+			if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
+			    !capable(CAP_SYS_RESOURCE)) {
+				spin_unlock_irqrestore(&kbd_event_lock, flags);
+				kfree(new_map);
+				return -EPERM;
+			}
+			key_maps[s] = new_map;
+			key_map = new_map;
+			key_map[0] = U(K_ALLOCATED);
+			for (j = 1; j < NR_KEYS; j++)
+				key_map[j] = U(K_HOLE);
+			keymap_count++;
+		} else
+			kfree(new_map);
+
+		ov = U(key_map[i]);
+		if (v == ov)
+			goto out;
+		/*
+		 * Attention Key.
+		 */
+		if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) {
+			spin_unlock_irqrestore(&kbd_event_lock, flags);
+			return -EPERM;
+		}
+		key_map[i] = U(v);
+		if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
+			do_compute_shiftstate();
+out:
+		spin_unlock_irqrestore(&kbd_event_lock, flags);
+		break;
+	}
+	return 0;
+}
+#undef i
+#undef s
+#undef v
+
+/* FIXME: This one needs untangling and locking */
+int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
+{
+	struct kbsentry *kbs;
+	char *p;
+	u_char *q;
+	u_char __user *up;
+	int sz;
+	int delta;
+	char *first_free, *fj, *fnw;
+	int i, j, k;
+	int ret;
+
+	if (!capable(CAP_SYS_TTY_CONFIG))
+		perm = 0;
+
+	kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
+	if (!kbs) {
+		ret = -ENOMEM;
+		goto reterr;
+	}
+
+	/* we mostly copy too much here (512bytes), but who cares ;) */
+	if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
+		ret = -EFAULT;
+		goto reterr;
+	}
+	kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
+	i = kbs->kb_func;
+
+	switch (cmd) {
+	case KDGKBSENT:
+		sz = sizeof(kbs->kb_string) - 1; /* sz should have been
+						  a struct member */
+		up = user_kdgkb->kb_string;
+		p = func_table[i];
+		if(p)
+			for ( ; *p && sz; p++, sz--)
+				if (put_user(*p, up++)) {
+					ret = -EFAULT;
+					goto reterr;
+				}
+		if (put_user('\0', up)) {
+			ret = -EFAULT;
+			goto reterr;
+		}
+		kfree(kbs);
+		return ((p && *p) ? -EOVERFLOW : 0);
+	case KDSKBSENT:
+		if (!perm) {
+			ret = -EPERM;
+			goto reterr;
+		}
+
+		q = func_table[i];
+		first_free = funcbufptr + (funcbufsize - funcbufleft);
+		for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++)
+			;
+		if (j < MAX_NR_FUNC)
+			fj = func_table[j];
+		else
+			fj = first_free;
+
+		delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
+		if (delta <= funcbufleft) { 	/* it fits in current buf */
+		    if (j < MAX_NR_FUNC) {
+			memmove(fj + delta, fj, first_free - fj);
+			for (k = j; k < MAX_NR_FUNC; k++)
+			    if (func_table[k])
+				func_table[k] += delta;
+		    }
+		    if (!q)
+		      func_table[i] = fj;
+		    funcbufleft -= delta;
+		} else {			/* allocate a larger buffer */
+		    sz = 256;
+		    while (sz < funcbufsize - funcbufleft + delta)
+		      sz <<= 1;
+		    fnw = kmalloc(sz, GFP_KERNEL);
+		    if(!fnw) {
+		      ret = -ENOMEM;
+		      goto reterr;
+		    }
+
+		    if (!q)
+		      func_table[i] = fj;
+		    if (fj > funcbufptr)
+			memmove(fnw, funcbufptr, fj - funcbufptr);
+		    for (k = 0; k < j; k++)
+		      if (func_table[k])
+			func_table[k] = fnw + (func_table[k] - funcbufptr);
+
+		    if (first_free > fj) {
+			memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
+			for (k = j; k < MAX_NR_FUNC; k++)
+			  if (func_table[k])
+			    func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
+		    }
+		    if (funcbufptr != func_buf)
+		      kfree(funcbufptr);
+		    funcbufptr = fnw;
+		    funcbufleft = funcbufleft - delta + sz - funcbufsize;
+		    funcbufsize = sz;
+		}
+		strcpy(func_table[i], kbs->kb_string);
+		break;
+	}
+	ret = 0;
+reterr:
+	kfree(kbs);
+	return ret;
+}
+
+int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+        unsigned long flags;
+	unsigned char ucval;
+
+        switch(cmd) {
+	/* the ioctls below read/set the flags usually shown in the leds */
+	/* don't use them - they will go away without warning */
+	case KDGKBLED:
+                spin_lock_irqsave(&kbd_event_lock, flags);
+		ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
+                spin_unlock_irqrestore(&kbd_event_lock, flags);
+		return put_user(ucval, (char __user *)arg);
+
+	case KDSKBLED:
+		if (!perm)
+			return -EPERM;
+		if (arg & ~0x77)
+			return -EINVAL;
+                spin_lock_irqsave(&kbd_event_lock, flags);
+		kbd->ledflagstate = (arg & 7);
+		kbd->default_ledflagstate = ((arg >> 4) & 7);
+		set_leds();
+                spin_unlock_irqrestore(&kbd_event_lock, flags);
+		break;
+
+	/* the ioctls below only set the lights, not the functions */
+	/* for those, see KDGKBLED and KDSKBLED above */
+	case KDGETLED:
+		ucval = getledstate();
+		return put_user(ucval, (char __user *)arg);
+
+	case KDSETLED:
+		if (!perm)
+			return -EPERM;
+		setledstate(kbd, arg);
+		return 0;
+        }
+        return -ENOIOCTLCMD;
+}
+
+int vt_do_kdgkbmode(int console)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	/* This is a spot read so needs no locking */
+	switch (kbd->kbdmode) {
+	case VC_RAW:
+		return K_RAW;
+	case VC_MEDIUMRAW:
+		return K_MEDIUMRAW;
+	case VC_UNICODE:
+		return K_UNICODE;
+	case VC_OFF:
+		return K_OFF;
+	default:
+		return K_XLATE;
+	}
+}
+
+/**
+ *	vt_do_kdgkbmeta		-	report meta status
+ *	@console: console to report
+ *
+ *	Report the meta flag status of this console
+ */
+int vt_do_kdgkbmeta(int console)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+        /* Again a spot read so no locking */
+	return vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT;
+}
+
+/**
+ *	vt_reset_unicode	-	reset the unicode status
+ *	@console: console being reset
+ *
+ *	Restore the unicode console state to its default
+ */
+void vt_reset_unicode(int console)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	kbd_table[console].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+}
+
+/**
+ *	vt_get_shiftstate	-	shift bit state
+ *
+ *	Report the shift bits from the keyboard state. We have to export
+ *	this to support some oddities in the vt layer.
+ */
+int vt_get_shift_state(void)
+{
+        /* Don't lock as this is a transient report */
+        return shift_state;
+}
+
+/**
+ *	vt_reset_keyboard	-	reset keyboard state
+ *	@console: console to reset
+ *
+ *	Reset the keyboard bits for a console as part of a general console
+ *	reset event
+ */
+void vt_reset_keyboard(int console)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	unsigned long flags;
+
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	set_vc_kbd_mode(kbd, VC_REPEAT);
+	clr_vc_kbd_mode(kbd, VC_CKMODE);
+	clr_vc_kbd_mode(kbd, VC_APPLIC);
+	clr_vc_kbd_mode(kbd, VC_CRLF);
+	kbd->lockstate = 0;
+	kbd->slockstate = 0;
+	kbd->ledmode = LED_SHOW_FLAGS;
+	kbd->ledflagstate = kbd->default_ledflagstate;
+	/* do not do set_leds here because this causes an endless tasklet loop
+	   when the keyboard hasn't been initialized yet */
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+}
+
+/**
+ *	vt_get_kbd_mode_bit	-	read keyboard status bits
+ *	@console: console to read from
+ *	@bit: mode bit to read
+ *
+ *	Report back a vt mode bit. We do this without locking so the
+ *	caller must be sure that there are no synchronization needs
+ */
+
+int vt_get_kbd_mode_bit(int console, int bit)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	return vc_kbd_mode(kbd, bit);
+}
+
+/**
+ *	vt_set_kbd_mode_bit	-	read keyboard status bits
+ *	@console: console to read from
+ *	@bit: mode bit to read
+ *
+ *	Set a vt mode bit. We do this without locking so the
+ *	caller must be sure that there are no synchronization needs
+ */
+
+void vt_set_kbd_mode_bit(int console, int bit)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	unsigned long flags;
+
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	set_vc_kbd_mode(kbd, bit);
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+}
+
+/**
+ *	vt_clr_kbd_mode_bit	-	read keyboard status bits
+ *	@console: console to read from
+ *	@bit: mode bit to read
+ *
+ *	Report back a vt mode bit. We do this without locking so the
+ *	caller must be sure that there are no synchronization needs
+ */
+
+void vt_clr_kbd_mode_bit(int console, int bit)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	unsigned long flags;
+
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	clr_vc_kbd_mode(kbd, bit);
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+}
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index 7a0a12a..8e9b4be 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -30,6 +30,7 @@
 
 extern void poke_blanked_console(void);
 
+/* FIXME: all this needs locking */
 /* Variables for selection control. */
 /* Use a dynamic buffer, instead of static (Dec 1994) */
 struct vc_data *sel_cons;		/* must not be deallocated */
@@ -61,10 +62,14 @@
 				use_unicode);
 }
 
-/* remove the current selection highlight, if any,
-   from the console holding the selection. */
-void
-clear_selection(void) {
+/**
+ *	clear_selection		-	remove current selection
+ *
+ *	Remove the current selection highlight, if any from the console
+ *	holding the selection. The caller must hold the console lock.
+ */
+void clear_selection(void)
+{
 	highlight_pointer(-1); /* hide the pointer */
 	if (sel_start != -1) {
 		highlight(sel_start, sel_end);
@@ -74,7 +79,7 @@
 
 /*
  * User settable table: what characters are to be considered alphabetic?
- * 256 bits
+ * 256 bits. Locked by the console lock.
  */
 static u32 inwordLut[8]={
   0x00000000, /* control chars     */
@@ -91,10 +96,20 @@
 	return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
 }
 
-/* set inwordLut contents. Invoked by ioctl(). */
+/**
+ *	set loadlut		-	load the LUT table
+ *	@p: user table
+ *
+ *	Load the LUT table from user space. The caller must hold the console
+ *	lock. Make a temporary copy so a partial update doesn't make a mess.
+ */
 int sel_loadlut(char __user *p)
 {
-	return copy_from_user(inwordLut, (u32 __user *)(p+4), 32) ? -EFAULT : 0;
+	u32 tmplut[8];
+	if (copy_from_user(tmplut, (u32 __user *)(p+4), 32))
+		return -EFAULT;
+	memcpy(inwordLut, tmplut, 32);
+	return 0;
 }
 
 /* does screen address p correspond to character at LH/RH edge of screen? */
@@ -130,7 +145,16 @@
     	}
 }
 
-/* set the current selection. Invoked by ioctl() or by kernel code. */
+/**
+ *	set_selection		- 	set the current selection.
+ *	@sel: user selection info
+ *	@tty: the console tty
+ *
+ *	Invoked by the ioctl handle for the vt layer.
+ *
+ *	The entire selection process is managed under the console_lock. It's
+ *	 a lot under the lock but its hardly a performance path
+ */
 int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
 {
 	struct vc_data *vc = vc_cons[fg_console].d;
@@ -138,7 +162,7 @@
 	char *bp, *obp;
 	int i, ps, pe, multiplier;
 	u16 c;
-	struct kbd_struct *kbd = kbd_table + fg_console;
+	int mode;
 
 	poke_blanked_console();
 
@@ -182,7 +206,11 @@
 		clear_selection();
 		sel_cons = vc_cons[fg_console].d;
 	}
-	use_unicode = kbd && kbd->kbdmode == VC_UNICODE;
+	mode = vt_do_kdgkbmode(fg_console);
+	if (mode == K_UNICODE)
+		use_unicode = 1;
+	else
+		use_unicode = 0;
 
 	switch (sel_mode)
 	{
@@ -302,7 +330,8 @@
  * queue of the tty associated with the current console.
  * Invoked by ioctl().
  *
- * Locking: always called with BTM from vt_ioctl
+ * Locking: called without locks. Calls the ldisc wrongly with
+ * unsafe methods,
  */
 int paste_selection(struct tty_struct *tty)
 {
@@ -317,13 +346,12 @@
 	poke_blanked_console();
 	console_unlock();
 
+	/* FIXME: wtf is this supposed to achieve ? */
 	ld = tty_ldisc_ref(tty);
-	if (!ld) {
-		tty_unlock();
+	if (!ld)
 		ld = tty_ldisc_ref_wait(tty);
-		tty_lock();
-	}
 
+	/* FIXME: this is completely unsafe */
 	add_wait_queue(&vc->paste_wait, &wait);
 	while (sel_buffer && sel_buffer_lth > pasted) {
 		set_current_state(TASK_INTERRUPTIBLE);
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c
index 7a367ff..fa7268a 100644
--- a/drivers/tty/vt/vc_screen.c
+++ b/drivers/tty/vt/vc_screen.c
@@ -608,10 +608,10 @@
 	unsigned int currcons = iminor(inode) & 127;
 	int ret = 0;
 	
-	tty_lock();
+	console_lock();
 	if(currcons && !vc_cons_allocated(currcons-1))
 		ret = -ENXIO;
-	tty_unlock();
+	console_unlock();
 	return ret;
 }
 
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index e716839..84c4a7d 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -1028,9 +1028,9 @@
  *	VT102 emulator
  */
 
-#define set_kbd(vc, x)	set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
-#define clr_kbd(vc, x)	clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
-#define is_kbd(vc, x)	vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
+#define set_kbd(vc, x)	vt_set_kbd_mode_bit((vc)->vc_num, (x))
+#define clr_kbd(vc, x)	vt_clr_kbd_mode_bit((vc)->vc_num, (x))
+#define is_kbd(vc, x)	vt_get_kbd_mode_bit((vc)->vc_num, (x))
 
 #define decarm		VC_REPEAT
 #define decckm		VC_CKMODE
@@ -1652,16 +1652,7 @@
 	vc->vc_deccm		= global_cursor_default;
 	vc->vc_decim		= 0;
 
-	set_kbd(vc, decarm);
-	clr_kbd(vc, decckm);
-	clr_kbd(vc, kbdapplic);
-	clr_kbd(vc, lnm);
-	kbd_table[vc->vc_num].lockstate = 0;
-	kbd_table[vc->vc_num].slockstate = 0;
-	kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS;
-	kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate;
-	/* do not do set_leds here because this causes an endless tasklet loop
-	   when the keyboard hasn't been initialized yet */
+	vt_reset_keyboard(vc->vc_num);
 
 	vc->vc_cursor_type = cur_default;
 	vc->vc_complement_mask = vc->vc_s_complement_mask;
@@ -1979,7 +1970,7 @@
 		case 'q': /* DECLL - but only 3 leds */
 			/* map 0,1,2,3 to 0,1,2,4 */
 			if (vc->vc_par[0] < 4)
-				setledstate(kbd_table + vc->vc_num,
+				vt_set_led_state(vc->vc_num,
 					    (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
 			return;
 		case 'r':
@@ -2632,7 +2623,9 @@
 			console_unlock();
 			break;
 		case TIOCL_SELLOADLUT:
+			console_lock();
 			ret = sel_loadlut(p);
+			console_unlock();
 			break;
 		case TIOCL_GETSHIFTSTATE:
 
@@ -2642,15 +2635,19 @@
 	 * kernel-internal variable; programs not closely
 	 * related to the kernel should not use this.
 	 */
-	 		data = shift_state;
+			data = vt_get_shift_state();
 			ret = __put_user(data, p);
 			break;
 		case TIOCL_GETMOUSEREPORTING:
+			console_lock();	/* May be overkill */
 			data = mouse_reporting();
+			console_unlock();
 			ret = __put_user(data, p);
 			break;
 		case TIOCL_SETVESABLANK:
+			console_lock();
 			ret = set_vesa_blanking(p);
+			console_unlock();
 			break;
 		case TIOCL_GETKMSGREDIRECT:
 			data = vt_get_kmsg_redirect();
@@ -2667,13 +2664,21 @@
 			}
 			break;
 		case TIOCL_GETFGCONSOLE:
+			/* No locking needed as this is a transiently
+			   correct return anyway if the caller hasn't
+			   disabled switching */
 			ret = fg_console;
 			break;
 		case TIOCL_SCROLLCONSOLE:
 			if (get_user(lines, (s32 __user *)(p+4))) {
 				ret = -EFAULT;
 			} else {
+				/* Need the console lock here. Note that lots
+				   of other calls need fixing before the lock
+				   is actually useful ! */
+				console_lock();
 				scrollfront(vc_cons[fg_console].d, lines);
+				console_unlock();
 				ret = 0;
 			}
 			break;
@@ -2753,8 +2758,7 @@
 	console_num = tty->index;
 	if (!vc_cons_allocated(console_num))
 		return;
-	set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
-	set_leds();
+	vt_kbd_con_stop(console_num);
 }
 
 /*
@@ -2768,8 +2772,7 @@
 	console_num = tty->index;
 	if (!vc_cons_allocated(console_num))
 		return;
-	clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
-	set_leds();
+	vt_kbd_con_start(console_num);
 }
 
 static void con_flush_chars(struct tty_struct *tty)
@@ -2991,7 +2994,7 @@
 	console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
 	if (!console_driver)
 		panic("Couldn't allocate console driver\n");
-	console_driver->owner = THIS_MODULE;
+
 	console_driver->name = "tty";
 	console_driver->name_base = 1;
 	console_driver->major = TTY_MAJOR;
@@ -3980,9 +3983,6 @@
 	int rc = -EINVAL;
 	int c;
 
-	if (vc->vc_mode != KD_TEXT)
-		return -EINVAL;
-
 	if (op->data) {
 		font.data = kmalloc(max_font_size, GFP_KERNEL);
 		if (!font.data)
@@ -3991,7 +3991,9 @@
 		font.data = NULL;
 
 	console_lock();
-	if (vc->vc_sw->con_font_get)
+	if (vc->vc_mode != KD_TEXT)
+		rc = -EINVAL;
+	else if (vc->vc_sw->con_font_get)
 		rc = vc->vc_sw->con_font_get(vc, &font);
 	else
 		rc = -ENOSYS;
@@ -4073,7 +4075,9 @@
 	if (IS_ERR(font.data))
 		return PTR_ERR(font.data);
 	console_lock();
-	if (vc->vc_sw->con_font_set)
+	if (vc->vc_mode != KD_TEXT)
+		rc = -EINVAL;
+	else if (vc->vc_sw->con_font_set)
 		rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
 	else
 		rc = -ENOSYS;
@@ -4089,8 +4093,6 @@
 	char *s = name;
 	int rc;
 
-	if (vc->vc_mode != KD_TEXT)
-		return -EINVAL;
 
 	if (!op->data)
 		s = NULL;
@@ -4100,6 +4102,10 @@
 		name[MAX_FONT_NAME - 1] = 0;
 
 	console_lock();
+	if (vc->vc_mode != KD_TEXT) {
+		console_unlock();
+		return -EINVAL;
+	}
 	if (vc->vc_sw->con_font_default)
 		rc = vc->vc_sw->con_font_default(vc, &font, s);
 	else
@@ -4117,11 +4123,11 @@
 	int con = op->height;
 	int rc;
 
-	if (vc->vc_mode != KD_TEXT)
-		return -EINVAL;
 
 	console_lock();
-	if (!vc->vc_sw->con_font_copy)
+	if (vc->vc_mode != KD_TEXT)
+		rc = -EINVAL;
+	else if (!vc->vc_sw->con_font_copy)
 		rc = -ENOSYS;
 	else if (con < 0 || !vc_cons_allocated(con))
 		rc = -ENOTTY;
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 65447c5..ede2ef1 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -130,7 +130,7 @@
 	list_add(&vw->list, &vt_events);
 	spin_unlock_irqrestore(&vt_event_lock, flags);
 	/* Wait for it to pass */
-	wait_event_interruptible_tty(vt_event_waitqueue, vw->done);
+	wait_event_interruptible(vt_event_waitqueue, vw->done);
 	/* Dequeue it */
 	spin_lock_irqsave(&vt_event_lock, flags);
 	list_del(&vw->list);
@@ -195,232 +195,7 @@
 #define GPLAST 0x3df
 #define GPNUM (GPLAST - GPFIRST + 1)
 
-#define i (tmp.kb_index)
-#define s (tmp.kb_table)
-#define v (tmp.kb_value)
-static inline int
-do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd)
-{
-	struct kbentry tmp;
-	ushort *key_map, val, ov;
 
-	if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
-		return -EFAULT;
-
-	if (!capable(CAP_SYS_TTY_CONFIG))
-		perm = 0;
-
-	switch (cmd) {
-	case KDGKBENT:
-		key_map = key_maps[s];
-		if (key_map) {
-		    val = U(key_map[i]);
-		    if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
-			val = K_HOLE;
-		} else
-		    val = (i ? K_HOLE : K_NOSUCHMAP);
-		return put_user(val, &user_kbe->kb_value);
-	case KDSKBENT:
-		if (!perm)
-			return -EPERM;
-		if (!i && v == K_NOSUCHMAP) {
-			/* deallocate map */
-			key_map = key_maps[s];
-			if (s && key_map) {
-			    key_maps[s] = NULL;
-			    if (key_map[0] == U(K_ALLOCATED)) {
-					kfree(key_map);
-					keymap_count--;
-			    }
-			}
-			break;
-		}
-
-		if (KTYP(v) < NR_TYPES) {
-		    if (KVAL(v) > max_vals[KTYP(v)])
-				return -EINVAL;
-		} else
-		    if (kbd->kbdmode != VC_UNICODE)
-				return -EINVAL;
-
-		/* ++Geert: non-PC keyboards may generate keycode zero */
-#if !defined(__mc68000__) && !defined(__powerpc__)
-		/* assignment to entry 0 only tests validity of args */
-		if (!i)
-			break;
-#endif
-
-		if (!(key_map = key_maps[s])) {
-			int j;
-
-			if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
-			    !capable(CAP_SYS_RESOURCE))
-				return -EPERM;
-
-			key_map = kmalloc(sizeof(plain_map),
-						     GFP_KERNEL);
-			if (!key_map)
-				return -ENOMEM;
-			key_maps[s] = key_map;
-			key_map[0] = U(K_ALLOCATED);
-			for (j = 1; j < NR_KEYS; j++)
-				key_map[j] = U(K_HOLE);
-			keymap_count++;
-		}
-		ov = U(key_map[i]);
-		if (v == ov)
-			break;	/* nothing to do */
-		/*
-		 * Attention Key.
-		 */
-		if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN))
-			return -EPERM;
-		key_map[i] = U(v);
-		if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
-			compute_shiftstate();
-		break;
-	}
-	return 0;
-}
-#undef i
-#undef s
-#undef v
-
-static inline int 
-do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm)
-{
-	struct kbkeycode tmp;
-	int kc = 0;
-
-	if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
-		return -EFAULT;
-	switch (cmd) {
-	case KDGETKEYCODE:
-		kc = getkeycode(tmp.scancode);
-		if (kc >= 0)
-			kc = put_user(kc, &user_kbkc->keycode);
-		break;
-	case KDSETKEYCODE:
-		if (!perm)
-			return -EPERM;
-		kc = setkeycode(tmp.scancode, tmp.keycode);
-		break;
-	}
-	return kc;
-}
-
-static inline int
-do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
-{
-	struct kbsentry *kbs;
-	char *p;
-	u_char *q;
-	u_char __user *up;
-	int sz;
-	int delta;
-	char *first_free, *fj, *fnw;
-	int i, j, k;
-	int ret;
-
-	if (!capable(CAP_SYS_TTY_CONFIG))
-		perm = 0;
-
-	kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
-	if (!kbs) {
-		ret = -ENOMEM;
-		goto reterr;
-	}
-
-	/* we mostly copy too much here (512bytes), but who cares ;) */
-	if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
-		ret = -EFAULT;
-		goto reterr;
-	}
-	kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
-	i = kbs->kb_func;
-
-	switch (cmd) {
-	case KDGKBSENT:
-		sz = sizeof(kbs->kb_string) - 1; /* sz should have been
-						  a struct member */
-		up = user_kdgkb->kb_string;
-		p = func_table[i];
-		if(p)
-			for ( ; *p && sz; p++, sz--)
-				if (put_user(*p, up++)) {
-					ret = -EFAULT;
-					goto reterr;
-				}
-		if (put_user('\0', up)) {
-			ret = -EFAULT;
-			goto reterr;
-		}
-		kfree(kbs);
-		return ((p && *p) ? -EOVERFLOW : 0);
-	case KDSKBSENT:
-		if (!perm) {
-			ret = -EPERM;
-			goto reterr;
-		}
-
-		q = func_table[i];
-		first_free = funcbufptr + (funcbufsize - funcbufleft);
-		for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) 
-			;
-		if (j < MAX_NR_FUNC)
-			fj = func_table[j];
-		else
-			fj = first_free;
-
-		delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
-		if (delta <= funcbufleft) { 	/* it fits in current buf */
-		    if (j < MAX_NR_FUNC) {
-			memmove(fj + delta, fj, first_free - fj);
-			for (k = j; k < MAX_NR_FUNC; k++)
-			    if (func_table[k])
-				func_table[k] += delta;
-		    }
-		    if (!q)
-		      func_table[i] = fj;
-		    funcbufleft -= delta;
-		} else {			/* allocate a larger buffer */
-		    sz = 256;
-		    while (sz < funcbufsize - funcbufleft + delta)
-		      sz <<= 1;
-		    fnw = kmalloc(sz, GFP_KERNEL);
-		    if(!fnw) {
-		      ret = -ENOMEM;
-		      goto reterr;
-		    }
-
-		    if (!q)
-		      func_table[i] = fj;
-		    if (fj > funcbufptr)
-			memmove(fnw, funcbufptr, fj - funcbufptr);
-		    for (k = 0; k < j; k++)
-		      if (func_table[k])
-			func_table[k] = fnw + (func_table[k] - funcbufptr);
-
-		    if (first_free > fj) {
-			memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
-			for (k = j; k < MAX_NR_FUNC; k++)
-			  if (func_table[k])
-			    func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
-		    }
-		    if (funcbufptr != func_buf)
-		      kfree(funcbufptr);
-		    funcbufptr = fnw;
-		    funcbufleft = funcbufleft - delta + sz - funcbufsize;
-		    funcbufsize = sz;
-		}
-		strcpy(func_table[i], kbs->kb_string);
-		break;
-	}
-	ret = 0;
-reterr:
-	kfree(kbs);
-	return ret;
-}
 
 static inline int 
 do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op)
@@ -497,7 +272,6 @@
 {
 	struct vc_data *vc = tty->driver_data;
 	struct console_font_op op;	/* used in multiple places here */
-	struct kbd_struct * kbd;
 	unsigned int console;
 	unsigned char ucval;
 	unsigned int uival;
@@ -507,7 +281,6 @@
 
 	console = vc->vc_num;
 
-	tty_lock();
 
 	if (!vc_cons_allocated(console)) { 	/* impossible? */
 		ret = -ENOIOCTLCMD;
@@ -523,19 +296,18 @@
 	if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
 		perm = 1;
  
-	kbd = kbd_table + console;
 	switch (cmd) {
 	case TIOCLINUX:
 		ret = tioclinux(tty, arg);
 		break;
 	case KIOCSOUND:
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		/*
 		 * The use of PIT_TICK_RATE is historic, it used to be
 		 * the platform-dependent CLOCK_TICK_RATE between 2.6.12
 		 * and 2.6.36, which was a minor but unfortunate ABI
-		 * change.
+		 * change. kd_mksound is locked by the input layer.
 		 */
 		if (arg)
 			arg = PIT_TICK_RATE / arg;
@@ -544,7 +316,7 @@
 
 	case KDMKTONE:
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 	{
 		unsigned int ticks, count;
 		
@@ -562,10 +334,11 @@
 
 	case KDGKBTYPE:
 		/*
-		 * this is naive.
+		 * this is naïve.
 		 */
 		ucval = KB_101;
-		goto setchar;
+		ret = put_user(ucval, (char __user *)arg);
+		break;
 
 		/*
 		 * These cannot be implemented on any machine that implements
@@ -579,6 +352,8 @@
 		/*
 		 * KDADDIO and KDDELIO may be able to add ports beyond what
 		 * we reject here, but to be safe...
+		 *
+		 * These are locked internally via sys_ioperm
 		 */
 		if (arg < GPFIRST || arg > GPLAST) {
 			ret = -EINVAL;
@@ -601,7 +376,7 @@
 		struct kbd_repeat kbrep;
 		
 		if (!capable(CAP_SYS_TTY_CONFIG))
-			goto eperm;
+			return -EPERM;
 
 		if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
 			ret =  -EFAULT;
@@ -625,7 +400,7 @@
 		 * need to restore their engine state. --BenH
 		 */
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		switch (arg) {
 		case KD_GRAPHICS:
 			break;
@@ -638,6 +413,7 @@
 			ret = -EINVAL;
 			goto out;
 		}
+		/* FIXME: this needs the console lock extending */
 		if (vc->vc_mode == (unsigned char) arg)
 			break;
 		vc->vc_mode = (unsigned char) arg;
@@ -669,69 +445,26 @@
 
 	case KDSKBMODE:
 		if (!perm)
-			goto eperm;
-		switch(arg) {
-		  case K_RAW:
-			kbd->kbdmode = VC_RAW;
-			break;
-		  case K_MEDIUMRAW:
-			kbd->kbdmode = VC_MEDIUMRAW;
-			break;
-		  case K_XLATE:
-			kbd->kbdmode = VC_XLATE;
-			compute_shiftstate();
-			break;
-		  case K_UNICODE:
-			kbd->kbdmode = VC_UNICODE;
-			compute_shiftstate();
-			break;
-		  case K_OFF:
-			kbd->kbdmode = VC_OFF;
-			break;
-		  default:
-			ret = -EINVAL;
-			goto out;
-		}
-		tty_ldisc_flush(tty);
+			return -EPERM;
+		ret = vt_do_kdskbmode(console, arg);
+		if (ret == 0)
+			tty_ldisc_flush(tty);
 		break;
 
 	case KDGKBMODE:
-		switch (kbd->kbdmode) {
-		case VC_RAW:
-			uival = K_RAW;
-			break;
-		case VC_MEDIUMRAW:
-			uival = K_MEDIUMRAW;
-			break;
-		case VC_UNICODE:
-			uival = K_UNICODE;
-			break;
-		case VC_OFF:
-			uival = K_OFF;
-			break;
-		default:
-			uival = K_XLATE;
-			break;
-		}
-		goto setint;
+		uival = vt_do_kdgkbmode(console);
+		ret = put_user(uival, (int __user *)arg);
+		break;
 
 	/* this could be folded into KDSKBMODE, but for compatibility
 	   reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
 	case KDSKBMETA:
-		switch(arg) {
-		  case K_METABIT:
-			clr_vc_kbd_mode(kbd, VC_META);
-			break;
-		  case K_ESCPREFIX:
-			set_vc_kbd_mode(kbd, VC_META);
-			break;
-		  default:
-			ret = -EINVAL;
-		}
+		ret = vt_do_kdskbmeta(console, arg);
 		break;
 
 	case KDGKBMETA:
-		uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
+		/* FIXME: should review whether this is worth locking */
+		uival = vt_do_kdgkbmeta(console);
 	setint:
 		ret = put_user(uival, (int __user *)arg);
 		break;
@@ -740,133 +473,35 @@
 	case KDSETKEYCODE:
 		if(!capable(CAP_SYS_TTY_CONFIG))
 			perm = 0;
-		ret = do_kbkeycode_ioctl(cmd, up, perm);
+		ret = vt_do_kbkeycode_ioctl(cmd, up, perm);
 		break;
 
 	case KDGKBENT:
 	case KDSKBENT:
-		ret = do_kdsk_ioctl(cmd, up, perm, kbd);
+		ret = vt_do_kdsk_ioctl(cmd, up, perm, console);
 		break;
 
 	case KDGKBSENT:
 	case KDSKBSENT:
-		ret = do_kdgkb_ioctl(cmd, up, perm);
+		ret = vt_do_kdgkb_ioctl(cmd, up, perm);
 		break;
 
+	/* Diacritical processing. Handled in keyboard.c as it has
+	   to operate on the keyboard locks and structures */
 	case KDGKBDIACR:
-	{
-		struct kbdiacrs __user *a = up;
-		struct kbdiacr diacr;
-		int i;
-
-		if (put_user(accent_table_size, &a->kb_cnt)) {
-			ret = -EFAULT;
-			break;
-		}
-		for (i = 0; i < accent_table_size; i++) {
-			diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
-			diacr.base = conv_uni_to_8bit(accent_table[i].base);
-			diacr.result = conv_uni_to_8bit(accent_table[i].result);
-			if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
-				ret = -EFAULT;
-				break;
-			}
-		}
-		break;
-	}
 	case KDGKBDIACRUC:
-	{
-		struct kbdiacrsuc __user *a = up;
-
-		if (put_user(accent_table_size, &a->kb_cnt))
-			ret = -EFAULT;
-		else if (copy_to_user(a->kbdiacruc, accent_table,
-				accent_table_size*sizeof(struct kbdiacruc)))
-			ret = -EFAULT;
-		break;
-	}
-
 	case KDSKBDIACR:
-	{
-		struct kbdiacrs __user *a = up;
-		struct kbdiacr diacr;
-		unsigned int ct;
-		int i;
-
-		if (!perm)
-			goto eperm;
-		if (get_user(ct,&a->kb_cnt)) {
-			ret = -EFAULT;
-			break;
-		}
-		if (ct >= MAX_DIACR) {
-			ret = -EINVAL;
-			break;
-		}
-		accent_table_size = ct;
-		for (i = 0; i < ct; i++) {
-			if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
-				ret = -EFAULT;
-				break;
-			}
-			accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
-			accent_table[i].base = conv_8bit_to_uni(diacr.base);
-			accent_table[i].result = conv_8bit_to_uni(diacr.result);
-		}
-		break;
-	}
-
 	case KDSKBDIACRUC:
-	{
-		struct kbdiacrsuc __user *a = up;
-		unsigned int ct;
-
-		if (!perm)
-			goto eperm;
-		if (get_user(ct,&a->kb_cnt)) {
-			ret = -EFAULT;
-			break;
-		}
-		if (ct >= MAX_DIACR) {
-			ret = -EINVAL;
-			break;
-		}
-		accent_table_size = ct;
-		if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
-			ret = -EFAULT;
+		ret = vt_do_diacrit(cmd, up, perm);
 		break;
-	}
 
 	/* the ioctls below read/set the flags usually shown in the leds */
 	/* don't use them - they will go away without warning */
 	case KDGKBLED:
-		ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
-		goto setchar;
-
 	case KDSKBLED:
-		if (!perm)
-			goto eperm;
-		if (arg & ~0x77) {
-			ret = -EINVAL;
-			break;
-		}
-		kbd->ledflagstate = (arg & 7);
-		kbd->default_ledflagstate = ((arg >> 4) & 7);
-		set_leds();
-		break;
-
-	/* the ioctls below only set the lights, not the functions */
-	/* for those, see KDGKBLED and KDSKBLED above */
 	case KDGETLED:
-		ucval = getledstate();
-	setchar:
-		ret = put_user(ucval, (char __user *)arg);
-		break;
-
 	case KDSETLED:
-		if (!perm)
-			goto eperm;
-		setledstate(kbd, arg);
+		ret = vt_do_kdskled(console, cmd, arg, perm);
 		break;
 
 	/*
@@ -879,7 +514,7 @@
 	case KDSIGACCEPT:
 	{
 		if (!perm || !capable(CAP_KILL))
-			goto eperm;
+			return -EPERM;
 		if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
 			ret = -EINVAL;
 		else {
@@ -897,7 +532,7 @@
 		struct vt_mode tmp;
 
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
 			ret = -EFAULT;
 			goto out;
@@ -943,6 +578,7 @@
 		struct vt_stat __user *vtstat = up;
 		unsigned short state, mask;
 
+		/* Review: FIXME: Console lock ? */
 		if (put_user(fg_console + 1, &vtstat->v_active))
 			ret = -EFAULT;
 		else {
@@ -960,6 +596,7 @@
 	 * Returns the first available (non-opened) console.
 	 */
 	case VT_OPENQRY:
+		/* FIXME: locking ? - but then this is a stupid API */
 		for (i = 0; i < MAX_NR_CONSOLES; ++i)
 			if (! VT_IS_IN_USE(i))
 				break;
@@ -973,7 +610,7 @@
 	 */
 	case VT_ACTIVATE:
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		if (arg == 0 || arg > MAX_NR_CONSOLES)
 			ret =  -ENXIO;
 		else {
@@ -992,7 +629,7 @@
 		struct vt_setactivate vsa;
 
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 
 		if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg,
 					sizeof(struct vt_setactivate))) {
@@ -1020,6 +657,7 @@
 			if (ret)
 				break;
 			/* Commence switch and lock */
+			/* Review set_console locks */
 			set_console(vsa.console);
 		}
 		break;
@@ -1030,7 +668,7 @@
 	 */
 	case VT_WAITACTIVE:
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		if (arg == 0 || arg > MAX_NR_CONSOLES)
 			ret = -ENXIO;
 		else
@@ -1049,16 +687,17 @@
 	 */
 	case VT_RELDISP:
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 
+		console_lock();
 		if (vc->vt_mode.mode != VT_PROCESS) {
+			console_unlock();
 			ret = -EINVAL;
 			break;
 		}
 		/*
 		 * Switching-from response
 		 */
-		console_lock();
 		if (vc->vt_newvt >= 0) {
 			if (arg == 0)
 				/*
@@ -1135,7 +774,7 @@
 
 		ushort ll,cc;
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		if (get_user(ll, &vtsizes->v_rows) ||
 		    get_user(cc, &vtsizes->v_cols))
 			ret = -EFAULT;
@@ -1146,6 +785,7 @@
 
 				if (vc) {
 					vc->vc_resize_user = 1;
+					/* FIXME: review v tty lock */
 					vc_resize(vc_cons[i].d, cc, ll);
 				}
 			}
@@ -1159,7 +799,7 @@
 		struct vt_consize __user *vtconsize = up;
 		ushort ll,cc,vlin,clin,vcol,ccol;
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		if (!access_ok(VERIFY_READ, vtconsize,
 				sizeof(struct vt_consize))) {
 			ret = -EFAULT;
@@ -1215,7 +855,7 @@
 
 	case PIO_FONT: {
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		op.op = KD_FONT_OP_SET;
 		op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC;	/* Compatibility */
 		op.width = 8;
@@ -1256,7 +896,7 @@
 	case PIO_FONTRESET:
 	{
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 
 #ifdef BROKEN_GRAPHICS_PROGRAMS
 		/* With BROKEN_GRAPHICS_PROGRAMS defined, the default
@@ -1282,7 +922,7 @@
 			break;
 		}
 		if (!perm && op.op != KD_FONT_OP_GET)
-			goto eperm;
+			return -EPERM;
 		ret = con_font_op(vc, &op);
 		if (ret)
 			break;
@@ -1294,50 +934,65 @@
 	case PIO_SCRNMAP:
 		if (!perm)
 			ret = -EPERM;
-		else
+		else {
+			tty_lock();
 			ret = con_set_trans_old(up);
+			tty_unlock();
+		}
 		break;
 
 	case GIO_SCRNMAP:
+		tty_lock();
 		ret = con_get_trans_old(up);
+		tty_unlock();
 		break;
 
 	case PIO_UNISCRNMAP:
 		if (!perm)
 			ret = -EPERM;
-		else
+		else {
+			tty_lock();
 			ret = con_set_trans_new(up);
+			tty_unlock();
+		}
 		break;
 
 	case GIO_UNISCRNMAP:
+		tty_lock();
 		ret = con_get_trans_new(up);
+		tty_unlock();
 		break;
 
 	case PIO_UNIMAPCLR:
 	      { struct unimapinit ui;
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
 		if (ret)
 			ret = -EFAULT;
-		else
+		else {
+			tty_lock();
 			con_clear_unimap(vc, &ui);
+			tty_unlock();
+		}
 		break;
 	      }
 
 	case PIO_UNIMAP:
 	case GIO_UNIMAP:
+		tty_lock();
 		ret = do_unimap_ioctl(cmd, up, perm, vc);
+		tty_unlock();
 		break;
 
 	case VT_LOCKSWITCH:
 		if (!capable(CAP_SYS_TTY_CONFIG))
-			goto eperm;
+			return -EPERM;
 		vt_dont_switch = 1;
 		break;
 	case VT_UNLOCKSWITCH:
 		if (!capable(CAP_SYS_TTY_CONFIG))
-			goto eperm;
+			return -EPERM;
 		vt_dont_switch = 0;
 		break;
 	case VT_GETHIFONTMASK:
@@ -1351,17 +1006,13 @@
 		ret = -ENOIOCTLCMD;
 	}
 out:
-	tty_unlock();
 	return ret;
-eperm:
-	ret = -EPERM;
-	goto out;
 }
 
 void reset_vc(struct vc_data *vc)
 {
 	vc->vc_mode = KD_TEXT;
-	kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
+	vt_reset_unicode(vc->vc_num);
 	vc->vt_mode.mode = VT_AUTO;
 	vc->vt_mode.waitv = 0;
 	vc->vt_mode.relsig = 0;
@@ -1384,6 +1035,7 @@
 	console_lock();
 	vc = vc_con->d;
 	if (vc) {
+		/* FIXME: review tty ref counting */
 		tty = vc->port.tty;
 		/*
 		 * SAK should also work in all raw modes and reset
@@ -1516,8 +1168,6 @@
 
 	console = vc->vc_num;
 
-	tty_lock();
-
 	if (!vc_cons_allocated(console)) { 	/* impossible? */
 		ret = -ENOIOCTLCMD;
 		goto out;
@@ -1546,7 +1196,9 @@
 
 	case PIO_UNIMAP:
 	case GIO_UNIMAP:
+		tty_lock();
 		ret = compat_unimap_ioctl(cmd, up, perm, vc);
+		tty_unlock();
 		break;
 
 	/*
@@ -1583,11 +1235,9 @@
 		goto fallback;
 	}
 out:
-	tty_unlock();
 	return ret;
 
 fallback:
-	tty_unlock();
 	return vt_ioctl(tty, cmd, arg);
 }
 
@@ -1773,13 +1423,10 @@
 		return -EIO;
 	}
 	console_unlock();
-	tty_lock();
 	if (vt_waitactive(vt + 1)) {
 		pr_debug("Suspend: Can't switch VCs.");
-		tty_unlock();
 		return -EINTR;
 	}
-	tty_unlock();
 	return prev;
 }
 
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 75823a1..e4405e0 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -10,27 +10,6 @@
 	  This option adds core support for Universal Serial Bus (USB).
 	  You will also need drivers from the following menu to make use of it.
 
-if USB_SUPPORT
-
-config USB_COMMON
-	tristate
-	default y
-	depends on USB || USB_GADGET
-
-# Host-side USB depends on having a host controller
-# NOTE:  dummy_hcd is always an option, but it's ignored here ...
-# NOTE:  SL-811 option should be board-specific ...
-config USB_ARCH_HAS_HCD
-	boolean
-	default y if USB_ARCH_HAS_OHCI
-	default y if USB_ARCH_HAS_EHCI
-	default y if USB_ARCH_HAS_XHCI
-	default y if PCMCIA && !M32R			# sl811_cs
-	default y if ARM				# SL-811
-	default y if BLACKFIN				# SL-811
-	default y if SUPERH				# r8a66597-hcd
-	default PCI
-
 # many non-PCI SOC chips embed OHCI
 config USB_ARCH_HAS_OHCI
 	boolean
@@ -76,6 +55,7 @@
 	default y if MICROBLAZE
 	default y if SPARC_LEON
 	default y if ARCH_MMP
+	default y if MACH_LOONGSON1
 	default PCI
 
 # some non-PCI HCDs implement xHCI
@@ -83,6 +63,27 @@
 	boolean
 	default PCI
 
+if USB_SUPPORT
+
+config USB_COMMON
+	tristate
+	default y
+	depends on USB || USB_GADGET
+
+# Host-side USB depends on having a host controller
+# NOTE:  dummy_hcd is always an option, but it's ignored here ...
+# NOTE:  SL-811 option should be board-specific ...
+config USB_ARCH_HAS_HCD
+	boolean
+	default y if USB_ARCH_HAS_OHCI
+	default y if USB_ARCH_HAS_EHCI
+	default y if USB_ARCH_HAS_XHCI
+	default y if PCMCIA && !M32R			# sl811_cs
+	default y if ARM				# SL-811
+	default y if BLACKFIN				# SL-811
+	default y if SUPERH				# r8a66597-hcd
+	default PCI
+
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
 config USB
 	tristate "Support for Host-side USB"
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 9543b19..b32ccb4 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -39,6 +39,7 @@
 #include <linux/serial.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
+#include <linux/serial.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
@@ -508,17 +509,12 @@
 	if (!acm)
 		return -ENODEV;
 
-	retval = tty_init_termios(tty);
+	retval = tty_standard_install(driver, tty);
 	if (retval)
 		goto error_init_termios;
 
 	tty->driver_data = acm;
 
-	/* Final install (we use the default method) */
-	tty_driver_kref_get(driver);
-	tty->count++;
-	driver->ttys[tty->index] = tty;
-
 	return 0;
 
 error_init_termios:
@@ -773,10 +769,37 @@
 	return acm_set_control(acm, acm->ctrlout = newctrl);
 }
 
+static int get_serial_info(struct acm *acm, struct serial_struct __user *info)
+{
+	struct serial_struct tmp;
+
+	if (!info)
+		return -EINVAL;
+
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.flags = ASYNC_LOW_LATENCY;
+	tmp.xmit_fifo_size = acm->writesize;
+	tmp.baud_base = le32_to_cpu(acm->line.dwDTERate);
+
+	if (copy_to_user(info, &tmp, sizeof(tmp)))
+		return -EFAULT;
+	else
+		return 0;
+}
+
 static int acm_tty_ioctl(struct tty_struct *tty,
 					unsigned int cmd, unsigned long arg)
 {
-	return -ENOIOCTLCMD;
+	struct acm *acm = tty->driver_data;
+	int rv = -ENOIOCTLCMD;
+
+	switch (cmd) {
+	case TIOCGSERIAL: /* gets serial port data */
+		rv = get_serial_info(acm, (struct serial_struct __user *) arg);
+		break;
+	}
+
+	return rv;
 }
 
 static const __u32 acm_tty_speed[] = {
@@ -1675,7 +1698,6 @@
 	acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
 	if (!acm_tty_driver)
 		return -ENOMEM;
-	acm_tty_driver->owner = THIS_MODULE,
 	acm_tty_driver->driver_name = "acm",
 	acm_tty_driver->name = "ttyACM",
 	acm_tty_driver->major = ACM_TTY_MAJOR,
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index d2b3cff..c6f6560 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -23,6 +23,7 @@
 #include <linux/usb/cdc.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
+#include <linux/usb/cdc-wdm.h>
 
 /*
  * Version Information
@@ -31,6 +32,8 @@
 #define DRIVER_AUTHOR "Oliver Neukum"
 #define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
 
+#define HUAWEI_VENDOR_ID	0x12D1
+
 static const struct usb_device_id wdm_ids[] = {
 	{
 		.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
@@ -38,6 +41,20 @@
 		.bInterfaceClass = USB_CLASS_COMM,
 		.bInterfaceSubClass = USB_CDC_SUBCLASS_DMM
 	},
+	{
+		/* 
+		 * Huawei E392, E398 and possibly other Qualcomm based modems
+		 * embed the Qualcomm QMI protocol inside CDC on CDC ECM like
+		 * control interfaces.  Userspace access to this is required
+		 * to configure the accompanying data interface
+		 */
+		.match_flags        = USB_DEVICE_ID_MATCH_VENDOR |
+					USB_DEVICE_ID_MATCH_INT_INFO,
+		.idVendor           = HUAWEI_VENDOR_ID,
+		.bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
+		.bInterfaceSubClass = 1,
+		.bInterfaceProtocol = 9, /* NOTE: CDC ECM control interface! */
+	},
 	{ }
 };
 
@@ -54,6 +71,7 @@
 #define WDM_POLL_RUNNING	6
 #define WDM_RESPONDING		7
 #define WDM_SUSPENDING		8
+#define WDM_RESETTING		9
 
 #define WDM_MAX			16
 
@@ -61,6 +79,8 @@
 #define WDM_DEFAULT_BUFSIZE	256
 
 static DEFINE_MUTEX(wdm_mutex);
+static DEFINE_SPINLOCK(wdm_device_list_lock);
+static LIST_HEAD(wdm_device_list);
 
 /* --- method tables --- */
 
@@ -82,7 +102,6 @@
 	u16			bufsize;
 	u16			wMaxCommand;
 	u16			wMaxPacketSize;
-	u16			bMaxPacketSize0;
 	__le16			inum;
 	int			reslength;
 	int			length;
@@ -96,10 +115,40 @@
 	struct work_struct	rxwork;
 	int			werr;
 	int			rerr;
+
+	struct list_head	device_list;
+	int			(*manage_power)(struct usb_interface *, int);
 };
 
 static struct usb_driver wdm_driver;
 
+/* return intfdata if we own the interface, else look up intf in the list */
+static struct wdm_device *wdm_find_device(struct usb_interface *intf)
+{
+	struct wdm_device *desc = NULL;
+
+	spin_lock(&wdm_device_list_lock);
+	list_for_each_entry(desc, &wdm_device_list, device_list)
+		if (desc->intf == intf)
+			break;
+	spin_unlock(&wdm_device_list_lock);
+
+	return desc;
+}
+
+static struct wdm_device *wdm_find_device_by_minor(int minor)
+{
+	struct wdm_device *desc = NULL;
+
+	spin_lock(&wdm_device_list_lock);
+	list_for_each_entry(desc, &wdm_device_list, device_list)
+		if (desc->intf->minor == minor)
+			break;
+	spin_unlock(&wdm_device_list_lock);
+
+	return desc;
+}
+
 /* --- callbacks --- */
 static void wdm_out_callback(struct urb *urb)
 {
@@ -162,11 +211,9 @@
 	int rv = 0;
 	int status = urb->status;
 	struct wdm_device *desc;
-	struct usb_ctrlrequest *req;
 	struct usb_cdc_notification *dr;
 
 	desc = urb->context;
-	req = desc->irq;
 	dr = (struct usb_cdc_notification *)desc->sbuf;
 
 	if (status) {
@@ -213,24 +260,6 @@
 		goto exit;
 	}
 
-	req->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
-	req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
-	req->wValue = 0;
-	req->wIndex = desc->inum;
-	req->wLength = cpu_to_le16(desc->wMaxCommand);
-
-	usb_fill_control_urb(
-		desc->response,
-		interface_to_usbdev(desc->intf),
-		/* using common endpoint 0 */
-		usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
-		(unsigned char *)req,
-		desc->inbuf,
-		desc->wMaxCommand,
-		wdm_in_callback,
-		desc
-	);
-	desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 	spin_lock(&desc->iuspin);
 	clear_bit(WDM_READ, &desc->flags);
 	set_bit(WDM_RESPONDING, &desc->flags);
@@ -279,14 +308,11 @@
 
 static void cleanup(struct wdm_device *desc)
 {
-	usb_free_coherent(interface_to_usbdev(desc->intf),
-			  desc->wMaxPacketSize,
-			  desc->sbuf,
-			  desc->validity->transfer_dma);
-	usb_free_coherent(interface_to_usbdev(desc->intf),
-			  desc->bMaxPacketSize0,
-			  desc->inbuf,
-			  desc->response->transfer_dma);
+	spin_lock(&wdm_device_list_lock);
+	list_del(&desc->device_list);
+	spin_unlock(&wdm_device_list_lock);
+	kfree(desc->sbuf);
+	kfree(desc->inbuf);
 	kfree(desc->orq);
 	kfree(desc->irq);
 	kfree(desc->ubuf);
@@ -351,6 +377,10 @@
 	else
 		if (test_bit(WDM_IN_USE, &desc->flags))
 			r = -EAGAIN;
+
+	if (test_bit(WDM_RESETTING, &desc->flags))
+		r = -EIO;
+
 	if (r < 0) {
 		kfree(buf);
 		goto out;
@@ -397,7 +427,7 @@
 static ssize_t wdm_read
 (struct file *file, char __user *buffer, size_t count, loff_t *ppos)
 {
-	int rv, cntr = 0;
+	int rv, cntr;
 	int i = 0;
 	struct wdm_device *desc = file->private_data;
 
@@ -406,7 +436,8 @@
 	if (rv < 0)
 		return -ERESTARTSYS;
 
-	if (desc->length == 0) {
+	cntr = ACCESS_ONCE(desc->length);
+	if (cntr == 0) {
 		desc->read = 0;
 retry:
 		if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
@@ -430,6 +461,10 @@
 			rv = -ENODEV;
 			goto err;
 		}
+		if (test_bit(WDM_RESETTING, &desc->flags)) {
+			rv = -EIO;
+			goto err;
+		}
 		usb_mark_last_busy(interface_to_usbdev(desc->intf));
 		if (rv < 0) {
 			rv = -ERESTARTSYS;
@@ -456,26 +491,30 @@
 			spin_unlock_irq(&desc->iuspin);
 			goto retry;
 		}
-		clear_bit(WDM_READ, &desc->flags);
+		cntr = desc->length;
 		spin_unlock_irq(&desc->iuspin);
 	}
 
-	cntr = count > desc->length ? desc->length : count;
+	if (cntr > count)
+		cntr = count;
 	rv = copy_to_user(buffer, desc->ubuf, cntr);
 	if (rv > 0) {
 		rv = -EFAULT;
 		goto err;
 	}
 
+	spin_lock_irq(&desc->iuspin);
+
 	for (i = 0; i < desc->length - cntr; i++)
 		desc->ubuf[i] = desc->ubuf[i + cntr];
 
-	spin_lock_irq(&desc->iuspin);
 	desc->length -= cntr;
-	spin_unlock_irq(&desc->iuspin);
 	/* in case we had outstanding data */
 	if (!desc->length)
 		clear_bit(WDM_READ, &desc->flags);
+
+	spin_unlock_irq(&desc->iuspin);
+
 	rv = cntr;
 
 err:
@@ -529,11 +568,11 @@
 	struct wdm_device *desc;
 
 	mutex_lock(&wdm_mutex);
-	intf = usb_find_interface(&wdm_driver, minor);
-	if (!intf)
+	desc = wdm_find_device_by_minor(minor);
+	if (!desc)
 		goto out;
 
-	desc = usb_get_intfdata(intf);
+	intf = desc->intf;
 	if (test_bit(WDM_DISCONNECTING, &desc->flags))
 		goto out;
 	file->private_data = desc;
@@ -543,7 +582,6 @@
 		dev_err(&desc->intf->dev, "Error autopm - %d\n", rv);
 		goto out;
 	}
-	intf->needs_remote_wakeup = 1;
 
 	/* using write lock to protect desc->count */
 	mutex_lock(&desc->wlock);
@@ -560,6 +598,8 @@
 		rv = 0;
 	}
 	mutex_unlock(&desc->wlock);
+	if (desc->count == 1)
+		desc->manage_power(intf, 1);
 	usb_autopm_put_interface(desc->intf);
 out:
 	mutex_unlock(&wdm_mutex);
@@ -581,7 +621,7 @@
 		dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
 		kill_urbs(desc);
 		if (!test_bit(WDM_DISCONNECTING, &desc->flags))
-			desc->intf->needs_remote_wakeup = 0;
+			desc->manage_power(desc->intf, 0);
 	}
 	mutex_unlock(&wdm_mutex);
 	return 0;
@@ -628,71 +668,31 @@
 
 /* --- hotplug --- */
 
-static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
+static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep,
+		u16 bufsize, int (*manage_power)(struct usb_interface *, int))
 {
-	int rv = -EINVAL;
-	struct usb_device *udev = interface_to_usbdev(intf);
+	int rv = -ENOMEM;
 	struct wdm_device *desc;
-	struct usb_host_interface *iface;
-	struct usb_endpoint_descriptor *ep;
-	struct usb_cdc_dmm_desc *dmhd;
-	u8 *buffer = intf->altsetting->extra;
-	int buflen = intf->altsetting->extralen;
-	u16 maxcom = WDM_DEFAULT_BUFSIZE;
 
-	if (!buffer)
-		goto out;
-
-	while (buflen > 2) {
-		if (buffer [1] != USB_DT_CS_INTERFACE) {
-			dev_err(&intf->dev, "skipping garbage\n");
-			goto next_desc;
-		}
-
-		switch (buffer [2]) {
-		case USB_CDC_HEADER_TYPE:
-			break;
-		case USB_CDC_DMM_TYPE:
-			dmhd = (struct usb_cdc_dmm_desc *)buffer;
-			maxcom = le16_to_cpu(dmhd->wMaxCommand);
-			dev_dbg(&intf->dev,
-				"Finding maximum buffer length: %d", maxcom);
-			break;
-		default:
-			dev_err(&intf->dev,
-				"Ignoring extra header, type %d, length %d\n",
-				buffer[2], buffer[0]);
-			break;
-		}
-next_desc:
-		buflen -= buffer[0];
-		buffer += buffer[0];
-	}
-
-	rv = -ENOMEM;
 	desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL);
 	if (!desc)
 		goto out;
+	INIT_LIST_HEAD(&desc->device_list);
 	mutex_init(&desc->rlock);
 	mutex_init(&desc->wlock);
 	spin_lock_init(&desc->iuspin);
 	init_waitqueue_head(&desc->wait);
-	desc->wMaxCommand = maxcom;
+	desc->wMaxCommand = bufsize;
 	/* this will be expanded and needed in hardware endianness */
 	desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber);
 	desc->intf = intf;
 	INIT_WORK(&desc->rxwork, wdm_rxwork);
 
 	rv = -EINVAL;
-	iface = intf->cur_altsetting;
-	if (iface->desc.bNumEndpoints != 1)
-		goto err;
-	ep = &iface->endpoint[0].desc;
-	if (!ep || !usb_endpoint_is_int_in(ep))
+	if (!usb_endpoint_is_int_in(ep))
 		goto err;
 
 	desc->wMaxPacketSize = usb_endpoint_maxp(ep);
-	desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0;
 
 	desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
 	if (!desc->orq)
@@ -717,19 +717,13 @@
 	if (!desc->ubuf)
 		goto err;
 
-	desc->sbuf = usb_alloc_coherent(interface_to_usbdev(intf),
-					desc->wMaxPacketSize,
-					GFP_KERNEL,
-					&desc->validity->transfer_dma);
+	desc->sbuf = kmalloc(desc->wMaxPacketSize, GFP_KERNEL);
 	if (!desc->sbuf)
 		goto err;
 
-	desc->inbuf = usb_alloc_coherent(interface_to_usbdev(intf),
-					 desc->wMaxCommand,
-					 GFP_KERNEL,
-					 &desc->response->transfer_dma);
+	desc->inbuf = kmalloc(desc->wMaxCommand, GFP_KERNEL);
 	if (!desc->inbuf)
-		goto err2;
+		goto err;
 
 	usb_fill_int_urb(
 		desc->validity,
@@ -741,45 +735,149 @@
 		desc,
 		ep->bInterval
 	);
-	desc->validity->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
-	usb_set_intfdata(intf, desc);
+	desc->irq->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
+	desc->irq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
+	desc->irq->wValue = 0;
+	desc->irq->wIndex = desc->inum;
+	desc->irq->wLength = cpu_to_le16(desc->wMaxCommand);
+
+	usb_fill_control_urb(
+		desc->response,
+		interface_to_usbdev(intf),
+		/* using common endpoint 0 */
+		usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
+		(unsigned char *)desc->irq,
+		desc->inbuf,
+		desc->wMaxCommand,
+		wdm_in_callback,
+		desc
+	);
+
+	desc->manage_power = manage_power;
+
+	spin_lock(&wdm_device_list_lock);
+	list_add(&desc->device_list, &wdm_device_list);
+	spin_unlock(&wdm_device_list_lock);
+
 	rv = usb_register_dev(intf, &wdm_class);
 	if (rv < 0)
-		goto err3;
+		goto err;
 	else
-		dev_info(&intf->dev, "cdc-wdm%d: USB WDM device\n",
-			intf->minor - WDM_MINOR_BASE);
+		dev_info(&intf->dev, "%s: USB WDM device\n", dev_name(intf->usb_dev));
 out:
 	return rv;
-err3:
-	usb_set_intfdata(intf, NULL);
-	usb_free_coherent(interface_to_usbdev(desc->intf),
-			  desc->bMaxPacketSize0,
-			desc->inbuf,
-			desc->response->transfer_dma);
-err2:
-	usb_free_coherent(interface_to_usbdev(desc->intf),
-			  desc->wMaxPacketSize,
-			  desc->sbuf,
-			  desc->validity->transfer_dma);
 err:
-	free_urbs(desc);
-	kfree(desc->ubuf);
-	kfree(desc->orq);
-	kfree(desc->irq);
-	kfree(desc);
+	cleanup(desc);
 	return rv;
 }
 
+static int wdm_manage_power(struct usb_interface *intf, int on)
+{
+	/* need autopm_get/put here to ensure the usbcore sees the new value */
+	int rv = usb_autopm_get_interface(intf);
+	if (rv < 0)
+		goto err;
+
+	intf->needs_remote_wakeup = on;
+	usb_autopm_put_interface(intf);
+err:
+	return rv;
+}
+
+static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	int rv = -EINVAL;
+	struct usb_host_interface *iface;
+	struct usb_endpoint_descriptor *ep;
+	struct usb_cdc_dmm_desc *dmhd;
+	u8 *buffer = intf->altsetting->extra;
+	int buflen = intf->altsetting->extralen;
+	u16 maxcom = WDM_DEFAULT_BUFSIZE;
+
+	if (!buffer)
+		goto err;
+	while (buflen > 2) {
+		if (buffer[1] != USB_DT_CS_INTERFACE) {
+			dev_err(&intf->dev, "skipping garbage\n");
+			goto next_desc;
+		}
+
+		switch (buffer[2]) {
+		case USB_CDC_HEADER_TYPE:
+			break;
+		case USB_CDC_DMM_TYPE:
+			dmhd = (struct usb_cdc_dmm_desc *)buffer;
+			maxcom = le16_to_cpu(dmhd->wMaxCommand);
+			dev_dbg(&intf->dev,
+				"Finding maximum buffer length: %d", maxcom);
+			break;
+		default:
+			dev_err(&intf->dev,
+				"Ignoring extra header, type %d, length %d\n",
+				buffer[2], buffer[0]);
+			break;
+		}
+next_desc:
+		buflen -= buffer[0];
+		buffer += buffer[0];
+	}
+
+	iface = intf->cur_altsetting;
+	if (iface->desc.bNumEndpoints != 1)
+		goto err;
+	ep = &iface->endpoint[0].desc;
+
+	rv = wdm_create(intf, ep, maxcom, &wdm_manage_power);
+
+err:
+	return rv;
+}
+
+/**
+ * usb_cdc_wdm_register - register a WDM subdriver
+ * @intf: usb interface the subdriver will associate with
+ * @ep: interrupt endpoint to monitor for notifications
+ * @bufsize: maximum message size to support for read/write
+ *
+ * Create WDM usb class character device and associate it with intf
+ * without binding, allowing another driver to manage the interface.
+ *
+ * The subdriver will manage the given interrupt endpoint exclusively
+ * and will issue control requests referring to the given intf. It
+ * will otherwise avoid interferring, and in particular not do
+ * usb_set_intfdata/usb_get_intfdata on intf.
+ *
+ * The return value is a pointer to the subdriver's struct usb_driver.
+ * The registering driver is responsible for calling this subdriver's
+ * disconnect, suspend, resume, pre_reset and post_reset methods from
+ * its own.
+ */
+struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
+					struct usb_endpoint_descriptor *ep,
+					int bufsize,
+					int (*manage_power)(struct usb_interface *, int))
+{
+	int rv = -EINVAL;
+
+	rv = wdm_create(intf, ep, bufsize, manage_power);
+	if (rv < 0)
+		goto err;
+
+	return &wdm_driver;
+err:
+	return ERR_PTR(rv);
+}
+EXPORT_SYMBOL(usb_cdc_wdm_register);
+
 static void wdm_disconnect(struct usb_interface *intf)
 {
 	struct wdm_device *desc;
 	unsigned long flags;
 
 	usb_deregister_dev(intf, &wdm_class);
+	desc = wdm_find_device(intf);
 	mutex_lock(&wdm_mutex);
-	desc = usb_get_intfdata(intf);
 
 	/* the spinlock makes sure no new urbs are generated in the callbacks */
 	spin_lock_irqsave(&desc->iuspin, flags);
@@ -803,7 +901,7 @@
 #ifdef CONFIG_PM
 static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
 {
-	struct wdm_device *desc = usb_get_intfdata(intf);
+	struct wdm_device *desc = wdm_find_device(intf);
 	int rv = 0;
 
 	dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
@@ -853,7 +951,7 @@
 #ifdef CONFIG_PM
 static int wdm_resume(struct usb_interface *intf)
 {
-	struct wdm_device *desc = usb_get_intfdata(intf);
+	struct wdm_device *desc = wdm_find_device(intf);
 	int rv;
 
 	dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor);
@@ -867,11 +965,7 @@
 
 static int wdm_pre_reset(struct usb_interface *intf)
 {
-	struct wdm_device *desc = usb_get_intfdata(intf);
-
-	mutex_lock(&desc->rlock);
-	mutex_lock(&desc->wlock);
-	kill_urbs(desc);
+	struct wdm_device *desc = wdm_find_device(intf);
 
 	/*
 	 * we notify everybody using poll of
@@ -880,17 +974,25 @@
 	 * message from the device is lost
 	 */
 	spin_lock_irq(&desc->iuspin);
+	set_bit(WDM_RESETTING, &desc->flags);	/* inform read/write */
+	set_bit(WDM_READ, &desc->flags);	/* unblock read */
+	clear_bit(WDM_IN_USE, &desc->flags);	/* unblock write */
 	desc->rerr = -EINTR;
 	spin_unlock_irq(&desc->iuspin);
 	wake_up_all(&desc->wait);
+	mutex_lock(&desc->rlock);
+	mutex_lock(&desc->wlock);
+	kill_urbs(desc);
+	cancel_work_sync(&desc->rxwork);
 	return 0;
 }
 
 static int wdm_post_reset(struct usb_interface *intf)
 {
-	struct wdm_device *desc = usb_get_intfdata(intf);
+	struct wdm_device *desc = wdm_find_device(intf);
 	int rv;
 
+	clear_bit(WDM_RESETTING, &desc->flags);
 	rv = recover_from_urb_loss(desc);
 	mutex_unlock(&desc->wlock);
 	mutex_unlock(&desc->rlock);
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index d40ff95..f8e2d6d 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -71,10 +71,7 @@
 	list_add_tail(&dynid->node, &dynids->list);
 	spin_unlock(&dynids->lock);
 
-	if (get_driver(driver)) {
-		retval = driver_attach(driver);
-		put_driver(driver);
-	}
+	retval = driver_attach(driver);
 
 	if (retval)
 		return retval;
@@ -132,43 +129,39 @@
 }
 static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);
 
-static int usb_create_newid_file(struct usb_driver *usb_drv)
+static int usb_create_newid_files(struct usb_driver *usb_drv)
 {
 	int error = 0;
 
 	if (usb_drv->no_dynamic_id)
 		goto exit;
 
-	if (usb_drv->probe != NULL)
+	if (usb_drv->probe != NULL) {
 		error = driver_create_file(&usb_drv->drvwrap.driver,
 					   &driver_attr_new_id);
+		if (error == 0) {
+			error = driver_create_file(&usb_drv->drvwrap.driver,
+					&driver_attr_remove_id);
+			if (error)
+				driver_remove_file(&usb_drv->drvwrap.driver,
+						&driver_attr_new_id);
+		}
+	}
 exit:
 	return error;
 }
 
-static void usb_remove_newid_file(struct usb_driver *usb_drv)
+static void usb_remove_newid_files(struct usb_driver *usb_drv)
 {
 	if (usb_drv->no_dynamic_id)
 		return;
 
-	if (usb_drv->probe != NULL)
+	if (usb_drv->probe != NULL) {
+		driver_remove_file(&usb_drv->drvwrap.driver,
+				&driver_attr_remove_id);
 		driver_remove_file(&usb_drv->drvwrap.driver,
 				   &driver_attr_new_id);
-}
-
-static int
-usb_create_removeid_file(struct usb_driver *drv)
-{
-	int error = 0;
-	if (drv->probe != NULL)
-		error = driver_create_file(&drv->drvwrap.driver,
-				&driver_attr_remove_id);
-	return error;
-}
-
-static void usb_remove_removeid_file(struct usb_driver *drv)
-{
-	driver_remove_file(&drv->drvwrap.driver, &driver_attr_remove_id);
+	}
 }
 
 static void usb_free_dynids(struct usb_driver *usb_drv)
@@ -183,22 +176,12 @@
 	spin_unlock(&usb_drv->dynids.lock);
 }
 #else
-static inline int usb_create_newid_file(struct usb_driver *usb_drv)
+static inline int usb_create_newid_files(struct usb_driver *usb_drv)
 {
 	return 0;
 }
 
-static void usb_remove_newid_file(struct usb_driver *usb_drv)
-{
-}
-
-static int
-usb_create_removeid_file(struct usb_driver *drv)
-{
-	return 0;
-}
-
-static void usb_remove_removeid_file(struct usb_driver *drv)
+static void usb_remove_newid_files(struct usb_driver *usb_drv)
 {
 }
 
@@ -875,22 +858,16 @@
 
 	usbfs_update_special();
 
-	retval = usb_create_newid_file(new_driver);
+	retval = usb_create_newid_files(new_driver);
 	if (retval)
 		goto out_newid;
 
-	retval = usb_create_removeid_file(new_driver);
-	if (retval)
-		goto out_removeid;
-
 	pr_info("%s: registered new interface driver %s\n",
 			usbcore_name, new_driver->name);
 
 out:
 	return retval;
 
-out_removeid:
-	usb_remove_newid_file(new_driver);
 out_newid:
 	driver_unregister(&new_driver->drvwrap.driver);
 
@@ -917,10 +894,9 @@
 	pr_info("%s: deregistering interface driver %s\n",
 			usbcore_name, driver->name);
 
-	usb_remove_removeid_file(driver);
-	usb_remove_newid_file(driver);
-	usb_free_dynids(driver);
+	usb_remove_newid_files(driver);
 	driver_unregister(&driver->drvwrap.driver);
+	usb_free_dynids(driver);
 
 	usbfs_update_special();
 }
@@ -958,13 +934,8 @@
 	int rc;
 
 	/* Delayed unbind of an existing driver */
-	if (intf->dev.driver) {
-		struct usb_driver *driver =
-				to_usb_driver(intf->dev.driver);
-
-		dev_dbg(&intf->dev, "forced unbind\n");
-		usb_driver_release_interface(driver, intf);
-	}
+	if (intf->dev.driver)
+		usb_forced_unbind_intf(intf);
 
 	/* Try to rebind the interface */
 	if (!intf->dev.power.is_prepared) {
@@ -977,15 +948,13 @@
 
 #ifdef CONFIG_PM
 
-#define DO_UNBIND	0
-#define DO_REBIND	1
-
-/* Unbind drivers for @udev's interfaces that don't support suspend/resume,
- * or rebind interfaces that have been unbound, according to @action.
+/* Unbind drivers for @udev's interfaces that don't support suspend/resume
+ * There is no check for reset_resume here because it can be determined
+ * only during resume whether reset_resume is needed.
  *
  * The caller must hold @udev's device lock.
  */
-static void do_unbind_rebind(struct usb_device *udev, int action)
+static void unbind_no_pm_drivers_interfaces(struct usb_device *udev)
 {
 	struct usb_host_config	*config;
 	int			i;
@@ -996,23 +965,53 @@
 	if (config) {
 		for (i = 0; i < config->desc.bNumInterfaces; ++i) {
 			intf = config->interface[i];
-			switch (action) {
-			case DO_UNBIND:
-				if (intf->dev.driver) {
-					drv = to_usb_driver(intf->dev.driver);
-					if (!drv->suspend || !drv->resume)
-						usb_forced_unbind_intf(intf);
-				}
-				break;
-			case DO_REBIND:
-				if (intf->needs_binding)
-					usb_rebind_intf(intf);
-				break;
+
+			if (intf->dev.driver) {
+				drv = to_usb_driver(intf->dev.driver);
+				if (!drv->suspend || !drv->resume)
+					usb_forced_unbind_intf(intf);
 			}
 		}
 	}
 }
 
+/* Unbind drivers for @udev's interfaces that failed to support reset-resume.
+ * These interfaces have the needs_binding flag set by usb_resume_interface().
+ *
+ * The caller must hold @udev's device lock.
+ */
+static void unbind_no_reset_resume_drivers_interfaces(struct usb_device *udev)
+{
+	struct usb_host_config	*config;
+	int			i;
+	struct usb_interface	*intf;
+
+	config = udev->actconfig;
+	if (config) {
+		for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+			intf = config->interface[i];
+			if (intf->dev.driver && intf->needs_binding)
+				usb_forced_unbind_intf(intf);
+		}
+	}
+}
+
+static void do_rebind_interfaces(struct usb_device *udev)
+{
+	struct usb_host_config	*config;
+	int			i;
+	struct usb_interface	*intf;
+
+	config = udev->actconfig;
+	if (config) {
+		for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+			intf = config->interface[i];
+			if (intf->needs_binding)
+				usb_rebind_intf(intf);
+		}
+	}
+}
+
 static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
 {
 	struct usb_device_driver	*udriver;
@@ -1302,35 +1301,48 @@
 {
 	struct usb_device	*udev = to_usb_device(dev);
 
-	do_unbind_rebind(udev, DO_UNBIND);
+	unbind_no_pm_drivers_interfaces(udev);
+
+	/* From now on we are sure all drivers support suspend/resume
+	 * but not necessarily reset_resume()
+	 * so we may still need to unbind and rebind upon resume
+	 */
 	choose_wakeup(udev, msg);
 	return usb_suspend_both(udev, msg);
 }
 
 /* The device lock is held by the PM core */
+int usb_resume_complete(struct device *dev)
+{
+	struct usb_device *udev = to_usb_device(dev);
+
+	/* For PM complete calls, all we do is rebind interfaces
+	 * whose needs_binding flag is set
+	 */
+	if (udev->state != USB_STATE_NOTATTACHED)
+		do_rebind_interfaces(udev);
+	return 0;
+}
+
+/* The device lock is held by the PM core */
 int usb_resume(struct device *dev, pm_message_t msg)
 {
 	struct usb_device	*udev = to_usb_device(dev);
 	int			status;
 
-	/* For PM complete calls, all we do is rebind interfaces */
-	if (msg.event == PM_EVENT_ON) {
-		if (udev->state != USB_STATE_NOTATTACHED)
-			do_unbind_rebind(udev, DO_REBIND);
-		status = 0;
-
-	/* For all other calls, take the device back to full power and
+	/* For all calls, take the device back to full power and
 	 * tell the PM core in case it was autosuspended previously.
-	 * Unbind the interfaces that will need rebinding later.
+	 * Unbind the interfaces that will need rebinding later,
+	 * because they fail to support reset_resume.
+	 * (This can't be done in usb_resume_interface()
+	 * above because it doesn't own the right set of locks.)
 	 */
-	} else {
-		status = usb_resume_both(udev, msg);
-		if (status == 0) {
-			pm_runtime_disable(dev);
-			pm_runtime_set_active(dev);
-			pm_runtime_enable(dev);
-			do_unbind_rebind(udev, DO_REBIND);
-		}
+	status = usb_resume_both(udev, msg);
+	if (status == 0) {
+		pm_runtime_disable(dev);
+		pm_runtime_set_active(dev);
+		pm_runtime_enable(dev);
+		unbind_no_reset_resume_drivers_interfaces(udev);
 	}
 
 	/* Avoid PM error messages for devices disconnected while suspended
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 81e2c0d..622b4a4 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -380,6 +380,7 @@
 	return 0;
 }
 
+#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
 static int suspend_common(struct device *dev, bool do_wakeup)
 {
 	struct pci_dev		*pci_dev = to_pci_dev(dev);
@@ -471,6 +472,7 @@
 	}
 	return retval;
 }
+#endif	/* SLEEP || RUNTIME */
 
 #ifdef	CONFIG_PM_SLEEP
 
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index e128232..9d7fc9a 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2352,7 +2352,7 @@
 					"io mem" : "io base",
 					(unsigned long long)hcd->rsrc_start);
 	} else {
-		hcd->irq = -1;
+		hcd->irq = 0;
 		if (hcd->rsrc_start)
 			dev_info(hcd->self.controller, "%s 0x%08llx\n",
 					(hcd->driver->flags & HCD_MEMORY) ?
@@ -2508,7 +2508,7 @@
 	clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
 	del_timer_sync(&hcd->rh_timer);
 err_hcd_driver_start:
-	if (usb_hcd_is_primary_hcd(hcd) && hcd->irq >= 0)
+	if (usb_hcd_is_primary_hcd(hcd) && hcd->irq > 0)
 		free_irq(irqnum, hcd);
 err_request_irq:
 err_hcd_driver_setup:
@@ -2573,7 +2573,7 @@
 	del_timer_sync(&hcd->rh_timer);
 
 	if (usb_hcd_is_primary_hcd(hcd)) {
-		if (hcd->irq >= 0)
+		if (hcd->irq > 0)
 			free_irq(hcd->irq, hcd);
 	}
 
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 265c2f6..28664eb 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -62,6 +62,8 @@
 							resumed */
 	unsigned long		removed_bits[1]; /* ports with a "removed"
 							device present */
+	unsigned long		wakeup_bits[1];	/* ports that have signaled
+							remote wakeup */
 #if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
 #error event_bits[] is too short!
 #endif
@@ -411,6 +413,29 @@
 		kick_khubd(hub);
 }
 
+/*
+ * Let the USB core know that a USB 3.0 device has sent a Function Wake Device
+ * Notification, which indicates it had initiated remote wakeup.
+ *
+ * USB 3.0 hubs do not report the port link state change from U3 to U0 when the
+ * device initiates resume, so the USB core will not receive notice of the
+ * resume through the normal hub interrupt URB.
+ */
+void usb_wakeup_notification(struct usb_device *hdev,
+		unsigned int portnum)
+{
+	struct usb_hub *hub;
+
+	if (!hdev)
+		return;
+
+	hub = hdev_to_hub(hdev);
+	if (hub) {
+		set_bit(portnum, hub->wakeup_bits);
+		kick_khubd(hub);
+	}
+}
+EXPORT_SYMBOL_GPL(usb_wakeup_notification);
 
 /* completion function, fires on port status changes and various faults */
 static void hub_irq(struct urb *urb)
@@ -823,12 +848,6 @@
 			clear_port_feature(hub->hdev, port1,
 					USB_PORT_FEAT_C_ENABLE);
 		}
-		if (portchange & USB_PORT_STAT_C_LINK_STATE) {
-			need_debounce_delay = true;
-			clear_port_feature(hub->hdev, port1,
-					USB_PORT_FEAT_C_PORT_LINK_STATE);
-		}
-
 		if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
 				hub_is_superspeed(hub->hdev)) {
 			need_debounce_delay = true;
@@ -850,12 +869,19 @@
 				set_bit(port1, hub->change_bits);
 
 		} else if (portstatus & USB_PORT_STAT_ENABLE) {
+			bool port_resumed = (portstatus &
+					USB_PORT_STAT_LINK_STATE) ==
+				USB_SS_PORT_LS_U0;
 			/* The power session apparently survived the resume.
 			 * If there was an overcurrent or suspend change
 			 * (i.e., remote wakeup request), have khubd
-			 * take care of it.
+			 * take care of it.  Look at the port link state
+			 * for USB 3.0 hubs, since they don't have a suspend
+			 * change bit, and they don't set the port link change
+			 * bit on device-initiated resume.
 			 */
-			if (portchange)
+			if (portchange || (hub_is_superspeed(hub->hdev) &&
+						port_resumed))
 				set_bit(port1, hub->change_bits);
 
 		} else if (udev->persist_enabled) {
@@ -1021,8 +1047,10 @@
 	dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
 		(hdev->maxchild == 1) ? "" : "s");
 
+	hdev->children = kzalloc(hdev->maxchild *
+				sizeof(struct usb_device *), GFP_KERNEL);
 	hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL);
-	if (!hub->port_owners) {
+	if (!hdev->children || !hub->port_owners) {
 		ret = -ENOMEM;
 		goto fail;
 	}
@@ -1253,7 +1281,8 @@
 
 static void hub_disconnect(struct usb_interface *intf)
 {
-	struct usb_hub *hub = usb_get_intfdata (intf);
+	struct usb_hub *hub = usb_get_intfdata(intf);
+	struct usb_device *hdev = interface_to_usbdev(intf);
 
 	/* Take the hub off the event list and don't let it be added again */
 	spin_lock_irq(&hub_event_lock);
@@ -1275,6 +1304,7 @@
 		highspeed_hubs--;
 
 	usb_free_urb(hub->urb);
+	kfree(hdev->children);
 	kfree(hub->port_owners);
 	kfree(hub->descriptor);
 	kfree(hub->status);
@@ -1293,14 +1323,8 @@
 	desc = intf->cur_altsetting;
 	hdev = interface_to_usbdev(intf);
 
-	/* Hubs have proper suspend/resume support.  USB 3.0 device suspend is
-	 * different from USB 2.0/1.1 device suspend, and unfortunately we
-	 * don't support it yet.  So leave autosuspend disabled for USB 3.0
-	 * external hubs for now.  Enable autosuspend for USB 3.0 roothubs,
-	 * since that isn't a "real" hub.
-	 */
-	if (!hub_is_superspeed(hdev) || !hdev->parent)
-		usb_enable_autosuspend(hdev);
+	/* Hubs have proper suspend/resume support. */
+	usb_enable_autosuspend(hdev);
 
 	if (hdev->level == MAX_TOPO_LEVEL) {
 		dev_err(&intf->dev,
@@ -1656,7 +1680,7 @@
 	usb_lock_device(udev);
 
 	/* Free up all the children before we remove this device */
-	for (i = 0; i < USB_MAXCHILDREN; i++) {
+	for (i = 0; i < udev->maxchild; i++) {
 		if (udev->children[i])
 			usb_disconnect(&udev->children[i]);
 	}
@@ -1842,6 +1866,37 @@
 	return err;
 }
 
+static void set_usb_port_removable(struct usb_device *udev)
+{
+	struct usb_device *hdev = udev->parent;
+	struct usb_hub *hub;
+	u8 port = udev->portnum;
+	u16 wHubCharacteristics;
+	bool removable = true;
+
+	if (!hdev)
+		return;
+
+	hub = hdev_to_hub(udev->parent);
+
+	wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
+
+	if (!(wHubCharacteristics & HUB_CHAR_COMPOUND))
+		return;
+
+	if (hub_is_superspeed(hdev)) {
+		if (hub->descriptor->u.ss.DeviceRemovable & (1 << port))
+			removable = false;
+	} else {
+		if (hub->descriptor->u.hs.DeviceRemovable[port / 8] & (1 << (port % 8)))
+			removable = false;
+	}
+
+	if (removable)
+		udev->removable = USB_DEVICE_REMOVABLE;
+	else
+		udev->removable = USB_DEVICE_FIXED;
+}
 
 /**
  * usb_new_device - perform initial device setup (usbcore-internal)
@@ -1900,6 +1955,15 @@
 	announce_device(udev);
 
 	device_enable_async_suspend(&udev->dev);
+
+	/*
+	 * check whether the hub marks this port as non-removable. Do it
+	 * now so that platform-specific data can override it in
+	 * device_add()
+	 */
+	if (udev->parent)
+		set_usb_port_removable(udev);
+
 	/* Register the device.  The device driver is responsible
 	 * for configuring the device and invoking the add-device
 	 * notifier chain (used by usbfs and possibly others).
@@ -2385,11 +2449,27 @@
 	 * we don't explicitly enable it here.
 	 */
 	if (udev->do_remote_wakeup) {
-		status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-				USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
-				USB_DEVICE_REMOTE_WAKEUP, 0,
-				NULL, 0,
-				USB_CTRL_SET_TIMEOUT);
+		if (!hub_is_superspeed(hub->hdev)) {
+			status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+					USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
+					USB_DEVICE_REMOTE_WAKEUP, 0,
+					NULL, 0,
+					USB_CTRL_SET_TIMEOUT);
+		} else {
+			/* Assume there's only one function on the USB 3.0
+			 * device and enable remote wake for the first
+			 * interface. FIXME if the interface association
+			 * descriptor shows there's more than one function.
+			 */
+			status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+					USB_REQ_SET_FEATURE,
+					USB_RECIP_INTERFACE,
+					USB_INTRF_FUNC_SUSPEND,
+					USB_INTRF_FUNC_SUSPEND_RW |
+					USB_INTRF_FUNC_SUSPEND_LP,
+					NULL, 0,
+					USB_CTRL_SET_TIMEOUT);
+		}
 		if (status) {
 			dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
 					status);
@@ -2679,6 +2759,7 @@
 	struct usb_hub		*hub = usb_get_intfdata (intf);
 	struct usb_device	*hdev = hub->hdev;
 	unsigned		port1;
+	int			status;
 
 	/* Warn if children aren't already suspended */
 	for (port1 = 1; port1 <= hdev->maxchild; port1++) {
@@ -2691,6 +2772,17 @@
 				return -EBUSY;
 		}
 	}
+	if (hub_is_superspeed(hdev) && hdev->do_remote_wakeup) {
+		/* Enable hub to send remote wakeup for all ports. */
+		for (port1 = 1; port1 <= hdev->maxchild; port1++) {
+			status = set_port_feature(hdev,
+					port1 |
+					USB_PORT_FEAT_REMOTE_WAKE_CONNECT |
+					USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT |
+					USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT,
+					USB_PORT_FEAT_REMOTE_WAKE_MASK);
+		}
+	}
 
 	dev_dbg(&intf->dev, "%s\n", __func__);
 
@@ -3424,6 +3516,46 @@
 		hcd->driver->relinquish_port(hcd, port1);
 }
 
+/* Returns 1 if there was a remote wakeup and a connect status change. */
+static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
+		u16 portstatus, u16 portchange)
+{
+	struct usb_device *hdev;
+	struct usb_device *udev;
+	int connect_change = 0;
+	int ret;
+
+	hdev = hub->hdev;
+	udev = hdev->children[port-1];
+	if (!hub_is_superspeed(hdev)) {
+		if (!(portchange & USB_PORT_STAT_C_SUSPEND))
+			return 0;
+		clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
+	} else {
+		if (!udev || udev->state != USB_STATE_SUSPENDED ||
+				 (portstatus & USB_PORT_STAT_LINK_STATE) !=
+				 USB_SS_PORT_LS_U0)
+			return 0;
+	}
+
+	if (udev) {
+		/* TRSMRCY = 10 msec */
+		msleep(10);
+
+		usb_lock_device(udev);
+		ret = usb_remote_wakeup(udev);
+		usb_unlock_device(udev);
+		if (ret < 0)
+			connect_change = 1;
+	} else {
+		ret = -ENODEV;
+		hub_port_disable(hub, port, 1);
+	}
+	dev_dbg(hub->intfdev, "resume on port %d, status %d\n",
+			port, ret);
+	return connect_change;
+}
+
 static void hub_events(void)
 {
 	struct list_head *tmp;
@@ -3436,7 +3568,7 @@
 	u16 portstatus;
 	u16 portchange;
 	int i, ret;
-	int connect_change;
+	int connect_change, wakeup_change;
 
 	/*
 	 *  We restart the list every time to avoid a deadlock with
@@ -3515,8 +3647,9 @@
 			if (test_bit(i, hub->busy_bits))
 				continue;
 			connect_change = test_bit(i, hub->change_bits);
+			wakeup_change = test_and_clear_bit(i, hub->wakeup_bits);
 			if (!test_and_clear_bit(i, hub->event_bits) &&
-					!connect_change)
+					!connect_change && !wakeup_change)
 				continue;
 
 			ret = hub_port_status(hub, i,
@@ -3557,31 +3690,10 @@
 				}
 			}
 
-			if (portchange & USB_PORT_STAT_C_SUSPEND) {
-				struct usb_device *udev;
+			if (hub_handle_remote_wakeup(hub, i,
+						portstatus, portchange))
+				connect_change = 1;
 
-				clear_port_feature(hdev, i,
-					USB_PORT_FEAT_C_SUSPEND);
-				udev = hdev->children[i-1];
-				if (udev) {
-					/* TRSMRCY = 10 msec */
-					msleep(10);
-
-					usb_lock_device(udev);
-					ret = usb_remote_wakeup(hdev->
-							children[i-1]);
-					usb_unlock_device(udev);
-					if (ret < 0)
-						connect_change = 1;
-				} else {
-					ret = -ENODEV;
-					hub_port_disable(hub, i, 1);
-				}
-				dev_dbg (hub_dev,
-					"resume on port %d, status %d\n",
-					i, ret);
-			}
-			
 			if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
 				u16 status = 0;
 				u16 unused;
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 9e491ca..566d9f9 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -230,6 +230,28 @@
 }
 static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
 
+static ssize_t
+show_removable(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct usb_device *udev;
+	char *state;
+
+	udev = to_usb_device(dev);
+
+	switch (udev->removable) {
+	case USB_DEVICE_REMOVABLE:
+		state = "removable";
+		break;
+	case USB_DEVICE_FIXED:
+		state = "fixed";
+		break;
+	default:
+		state = "unknown";
+	}
+
+	return sprintf(buf, "%s\n", state);
+}
+static DEVICE_ATTR(removable, S_IRUGO, show_removable, NULL);
 
 #ifdef	CONFIG_PM
 
@@ -626,6 +648,7 @@
 	&dev_attr_avoid_reset_quirk.attr,
 	&dev_attr_authorized.attr,
 	&dev_attr_remove.attr,
+	&dev_attr_removable.attr,
 	NULL,
 };
 static struct attribute_group dev_attr_grp = {
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 909625b..7239a73 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -403,20 +403,17 @@
 	 * cause problems in HCDs if they get it wrong.
 	 */
 	{
-	unsigned int	orig_flags = urb->transfer_flags;
 	unsigned int	allowed;
 	static int pipetypes[4] = {
 		PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
 	};
 
 	/* Check that the pipe's type matches the endpoint's type */
-	if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) {
-		dev_err(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
+	if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
+		dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
 			usb_pipetype(urb->pipe), pipetypes[xfertype]);
-		return -EPIPE;		/* The most suitable error code :-) */
-	}
 
-	/* enforce simple/standard policy */
+	/* Check against a simple/standard policy */
 	allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK |
 			URB_FREE_BUFFER);
 	switch (xfertype) {
@@ -435,14 +432,12 @@
 		allowed |= URB_ISO_ASAP;
 		break;
 	}
-	urb->transfer_flags &= allowed;
+	allowed &= urb->transfer_flags;
 
-	/* fail if submitter gave bogus flags */
-	if (urb->transfer_flags != orig_flags) {
-		dev_err(&dev->dev, "BOGUS urb flags, %x --> %x\n",
-			orig_flags, urb->transfer_flags);
-		return -EINVAL;
-	}
+	/* warn if submitter gave bogus flags */
+	if (allowed != urb->transfer_flags)
+		dev_WARN(&dev->dev, "BOGUS urb flags, %x --> %x\n",
+			urb->transfer_flags, allowed);
 	}
 #endif
 	/*
@@ -532,10 +527,13 @@
  * a driver's I/O routines to insure that all URB-related activity has
  * completed before it returns.
  *
- * This request is always asynchronous.  Success is indicated by
- * returning -EINPROGRESS, at which time the URB will probably not yet
- * have been given back to the device driver.  When it is eventually
- * called, the completion function will see @urb->status == -ECONNRESET.
+ * This request is asynchronous, however the HCD might call the ->complete()
+ * callback during unlink. Therefore when drivers call usb_unlink_urb(), they
+ * must not hold any locks that may be taken by the completion function.
+ * Success is indicated by returning -EINPROGRESS, at which time the URB will
+ * probably not yet have been given back to the device driver. When it is
+ * eventually called, the completion function will see @urb->status ==
+ * -ECONNRESET.
  * Failure is indicated by usb_unlink_urb() returning any other value.
  * Unlinking will fail when @urb is not currently "linked" (i.e., it was
  * never submitted, or it was unlinked before, or the hardware is already
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 8ca9f99..c74ba7b 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -274,7 +274,7 @@
 static void usb_dev_complete(struct device *dev)
 {
 	/* Currently used only for rebinding interfaces */
-	usb_resume(dev, PMSG_ON);	/* FIXME: change to PMSG_COMPLETE */
+	usb_resume_complete(dev);
 }
 
 static int usb_dev_suspend(struct device *dev)
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 45e8479..71648dc 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -56,6 +56,7 @@
 
 extern int usb_suspend(struct device *dev, pm_message_t msg);
 extern int usb_resume(struct device *dev, pm_message_t msg);
+extern int usb_resume_complete(struct device *dev);
 
 extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg);
 extern int usb_port_resume(struct usb_device *dev, pm_message_t msg);
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 900ae74..d441fe4 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -28,6 +28,19 @@
 
 obj-$(CONFIG_USB_DWC3)		+= dwc3-omap.o
 
+##
+# REVISIT Samsung Exynos platform needs the clk API which isn't
+# defined on all architectures. If we allow dwc3-exynos.c compile
+# always we will fail the linking phase on those architectures
+# which don't provide clk api implementation and that's unnaceptable.
+#
+# When Samsung's platform start supporting pm_runtime, this check
+# for HAVE_CLK should be removed.
+##
+ifneq ($(CONFIG_HAVE_CLK),)
+	obj-$(CONFIG_USB_DWC3)		+= dwc3-exynos.o
+endif
+
 ifneq ($(CONFIG_PCI),)
 	obj-$(CONFIG_USB_DWC3)		+= dwc3-pci.o
 endif
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 7c9df63..7bd815a 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -48,10 +48,10 @@
 #include <linux/list.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
+#include <linux/of.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
-#include <linux/module.h>
 
 #include "core.h"
 #include "gadget.h"
@@ -86,7 +86,7 @@
 		id = -ENOMEM;
 	}
 
-	return 0;
+	return id;
 }
 EXPORT_SYMBOL_GPL(dwc3_get_device_id);
 
@@ -167,11 +167,11 @@
 }
 
 /**
- * dwc3_alloc_one_event_buffer - Allocated one event buffer structure
+ * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
  * @dwc: Pointer to our controller context structure
  * @length: size of the event buffer
  *
- * Returns a pointer to the allocated event buffer structure on succes
+ * Returns a pointer to the allocated event buffer structure on success
  * otherwise ERR_PTR(errno).
  */
 static struct dwc3_event_buffer *__devinit
@@ -215,10 +215,10 @@
 
 /**
  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
- * @dwc: Pointer to out controller context structure
+ * @dwc: pointer to our controller context structure
  * @length: size of event buffer
  *
- * Returns 0 on success otherwise negative errno. In error the case, dwc
+ * Returns 0 on success otherwise negative errno. In the error case, dwc
  * may contain some buffers allocated but not all which were requested.
  */
 static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
@@ -251,7 +251,7 @@
 
 /**
  * dwc3_event_buffers_setup - setup our allocated event buffers
- * @dwc: Pointer to out controller context structure
+ * @dwc: pointer to our controller context structure
  *
  * Returns 0 on success otherwise negative errno.
  */
@@ -350,7 +350,7 @@
 	dwc3_cache_hwparams(dwc);
 
 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
-	reg &= ~DWC3_GCTL_SCALEDOWN(3);
+	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
 	reg &= ~DWC3_GCTL_DISSCRAMBLE;
 
 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
@@ -363,9 +363,9 @@
 
 	/*
 	 * WORKAROUND: DWC3 revisions <1.90a have a bug
-	 * when The device fails to connect at SuperSpeed
+	 * where the device can fail to connect at SuperSpeed
 	 * and falls back to high-speed mode which causes
-	 * the device to enter in a Connect/Disconnect loop
+	 * the device to enter a Connect/Disconnect loop
 	 */
 	if (dwc->revision < DWC3_REVISION_190A)
 		reg |= DWC3_GCTL_U2RSTECN;
@@ -404,8 +404,10 @@
 
 static int __devinit dwc3_probe(struct platform_device *pdev)
 {
+	struct device_node	*node = pdev->dev.of_node;
 	struct resource		*res;
 	struct dwc3		*dwc;
+	struct device		*dev = &pdev->dev;
 
 	int			ret = -ENOMEM;
 	int			irq;
@@ -415,39 +417,39 @@
 
 	u8			mode;
 
-	mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
+	mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
 	if (!mem) {
-		dev_err(&pdev->dev, "not enough memory\n");
-		goto err0;
+		dev_err(dev, "not enough memory\n");
+		return -ENOMEM;
 	}
 	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
 	dwc->mem = mem;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
-		dev_err(&pdev->dev, "missing resource\n");
-		goto err1;
+		dev_err(dev, "missing resource\n");
+		return -ENODEV;
 	}
 
 	dwc->res = res;
 
-	res = request_mem_region(res->start, resource_size(res),
-			dev_name(&pdev->dev));
+	res = devm_request_mem_region(dev, res->start, resource_size(res),
+			dev_name(dev));
 	if (!res) {
-		dev_err(&pdev->dev, "can't request mem region\n");
-		goto err1;
+		dev_err(dev, "can't request mem region\n");
+		return -ENOMEM;
 	}
 
-	regs = ioremap(res->start, resource_size(res));
+	regs = devm_ioremap(dev, res->start, resource_size(res));
 	if (!regs) {
-		dev_err(&pdev->dev, "ioremap failed\n");
-		goto err2;
+		dev_err(dev, "ioremap failed\n");
+		return -ENOMEM;
 	}
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		dev_err(&pdev->dev, "missing IRQ\n");
-		goto err3;
+		dev_err(dev, "missing IRQ\n");
+		return -ENODEV;
 	}
 
 	spin_lock_init(&dwc->lock);
@@ -455,7 +457,7 @@
 
 	dwc->regs	= regs;
 	dwc->regs_size	= resource_size(res);
-	dwc->dev	= &pdev->dev;
+	dwc->dev	= dev;
 	dwc->irq	= irq;
 
 	if (!strncmp("super", maximum_speed, 5))
@@ -469,14 +471,17 @@
 	else
 		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
 
-	pm_runtime_enable(&pdev->dev);
-	pm_runtime_get_sync(&pdev->dev);
-	pm_runtime_forbid(&pdev->dev);
+	if (of_get_property(node, "tx-fifo-resize", NULL))
+		dwc->needs_fifo_resize = true;
+
+	pm_runtime_enable(dev);
+	pm_runtime_get_sync(dev);
+	pm_runtime_forbid(dev);
 
 	ret = dwc3_core_init(dwc);
 	if (ret) {
-		dev_err(&pdev->dev, "failed to initialize core\n");
-		goto err3;
+		dev_err(dev, "failed to initialize core\n");
+		return ret;
 	}
 
 	mode = DWC3_MODE(dwc->hwparams.hwparams0);
@@ -486,49 +491,49 @@
 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
 		ret = dwc3_gadget_init(dwc);
 		if (ret) {
-			dev_err(&pdev->dev, "failed to initialize gadget\n");
-			goto err4;
+			dev_err(dev, "failed to initialize gadget\n");
+			goto err1;
 		}
 		break;
 	case DWC3_MODE_HOST:
 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
 		ret = dwc3_host_init(dwc);
 		if (ret) {
-			dev_err(&pdev->dev, "failed to initialize host\n");
-			goto err4;
+			dev_err(dev, "failed to initialize host\n");
+			goto err1;
 		}
 		break;
 	case DWC3_MODE_DRD:
 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
 		ret = dwc3_host_init(dwc);
 		if (ret) {
-			dev_err(&pdev->dev, "failed to initialize host\n");
-			goto err4;
+			dev_err(dev, "failed to initialize host\n");
+			goto err1;
 		}
 
 		ret = dwc3_gadget_init(dwc);
 		if (ret) {
-			dev_err(&pdev->dev, "failed to initialize gadget\n");
-			goto err4;
+			dev_err(dev, "failed to initialize gadget\n");
+			goto err1;
 		}
 		break;
 	default:
-		dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode);
-		goto err4;
+		dev_err(dev, "Unsupported mode of operation %d\n", mode);
+		goto err1;
 	}
 	dwc->mode = mode;
 
 	ret = dwc3_debugfs_init(dwc);
 	if (ret) {
-		dev_err(&pdev->dev, "failed to initialize debugfs\n");
-		goto err5;
+		dev_err(dev, "failed to initialize debugfs\n");
+		goto err2;
 	}
 
-	pm_runtime_allow(&pdev->dev);
+	pm_runtime_allow(dev);
 
 	return 0;
 
-err5:
+err2:
 	switch (mode) {
 	case DWC3_MODE_DEVICE:
 		dwc3_gadget_exit(dwc);
@@ -545,19 +550,9 @@
 		break;
 	}
 
-err4:
+err1:
 	dwc3_core_exit(dwc);
 
-err3:
-	iounmap(regs);
-
-err2:
-	release_mem_region(res->start, resource_size(res));
-
-err1:
-	kfree(dwc->mem);
-
-err0:
 	return ret;
 }
 
@@ -590,9 +585,6 @@
 	}
 
 	dwc3_core_exit(dwc);
-	release_mem_region(res->start, resource_size(res));
-	iounmap(dwc->regs);
-	kfree(dwc->mem);
 
 	return 0;
 }
@@ -605,19 +597,9 @@
 	},
 };
 
+module_platform_driver(dwc3_driver);
+
 MODULE_ALIAS("platform:dwc3");
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
-
-static int __devinit dwc3_init(void)
-{
-	return platform_driver_register(&dwc3_driver);
-}
-module_init(dwc3_init);
-
-static void __exit dwc3_exit(void)
-{
-	platform_driver_unregister(&dwc3_driver);
-}
-module_exit(dwc3_exit);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 9e57f8e..6c7945b 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -145,22 +145,23 @@
 /* Bit fields */
 
 /* Global Configuration Register */
-#define DWC3_GCTL_PWRDNSCALE(n)	(n << 19)
+#define DWC3_GCTL_PWRDNSCALE(n)	((n) << 19)
 #define DWC3_GCTL_U2RSTECN	(1 << 16)
-#define DWC3_GCTL_RAMCLKSEL(x)	((x & DWC3_GCTL_CLK_MASK) << 6)
+#define DWC3_GCTL_RAMCLKSEL(x)	(((x) & DWC3_GCTL_CLK_MASK) << 6)
 #define DWC3_GCTL_CLK_BUS	(0)
 #define DWC3_GCTL_CLK_PIPE	(1)
 #define DWC3_GCTL_CLK_PIPEHALF	(2)
 #define DWC3_GCTL_CLK_MASK	(3)
 
 #define DWC3_GCTL_PRTCAP(n)	(((n) & (3 << 12)) >> 12)
-#define DWC3_GCTL_PRTCAPDIR(n)	(n << 12)
+#define DWC3_GCTL_PRTCAPDIR(n)	((n) << 12)
 #define DWC3_GCTL_PRTCAP_HOST	1
 #define DWC3_GCTL_PRTCAP_DEVICE	2
 #define DWC3_GCTL_PRTCAP_OTG	3
 
 #define DWC3_GCTL_CORESOFTRESET	(1 << 11)
-#define DWC3_GCTL_SCALEDOWN(n)	(n << 4)
+#define DWC3_GCTL_SCALEDOWN(n)	((n) << 4)
+#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
 #define DWC3_GCTL_DISSCRAMBLE	(1 << 3)
 #define DWC3_GCTL_DSBLCLKGTNG	(1 << 0)
 
@@ -172,8 +173,12 @@
 #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
 #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
 
+/* Global TX Fifo Size Register */
+#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
+#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
+
 /* Global HWPARAMS1 Register */
-#define DWC3_GHWPARAMS1_EN_PWROPT(n)	((n & (3 << 24)) >> 24)
+#define DWC3_GHWPARAMS1_EN_PWROPT(n)	(((n) & (3 << 24)) >> 24)
 #define DWC3_GHWPARAMS1_EN_PWROPT_NO	0
 #define DWC3_GHWPARAMS1_EN_PWROPT_CLK	1
 
@@ -198,6 +203,15 @@
 
 #define DWC3_DCTL_APPL1RES	(1 << 23)
 
+#define DWC3_DCTL_TRGTULST_MASK	(0x0f << 17)
+#define DWC3_DCTL_TRGTULST(n)	((n) << 17)
+
+#define DWC3_DCTL_TRGTULST_U2	(DWC3_DCTL_TRGTULST(2))
+#define DWC3_DCTL_TRGTULST_U3	(DWC3_DCTL_TRGTULST(3))
+#define DWC3_DCTL_TRGTULST_SS_DIS (DWC3_DCTL_TRGTULST(4))
+#define DWC3_DCTL_TRGTULST_RX_DET (DWC3_DCTL_TRGTULST(5))
+#define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6))
+
 #define DWC3_DCTL_INITU2ENA	(1 << 12)
 #define DWC3_DCTL_ACCEPTU2ENA	(1 << 11)
 #define DWC3_DCTL_INITU1ENA	(1 << 10)
@@ -260,10 +274,10 @@
 
 /* Device Endpoint Command Register */
 #define DWC3_DEPCMD_PARAM_SHIFT		16
-#define DWC3_DEPCMD_PARAM(x)		(x << DWC3_DEPCMD_PARAM_SHIFT)
-#define DWC3_DEPCMD_GET_RSC_IDX(x)	((x >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
+#define DWC3_DEPCMD_PARAM(x)		((x) << DWC3_DEPCMD_PARAM_SHIFT)
+#define DWC3_DEPCMD_GET_RSC_IDX(x)     (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
 #define DWC3_DEPCMD_STATUS_MASK		(0x0f << 12)
-#define DWC3_DEPCMD_STATUS(x)		((x & DWC3_DEPCMD_STATUS_MASK) >> 12)
+#define DWC3_DEPCMD_STATUS(x)		(((x) & DWC3_DEPCMD_STATUS_MASK) >> 12)
 #define DWC3_DEPCMD_HIPRI_FORCERM	(1 << 11)
 #define DWC3_DEPCMD_CMDACT		(1 << 10)
 #define DWC3_DEPCMD_CMDIOC		(1 << 8)
@@ -288,7 +302,7 @@
 
 /* Structures */
 
-struct dwc3_trb_hw;
+struct dwc3_trb;
 
 /**
  * struct dwc3_event_buffer - Software event buffer representation
@@ -343,7 +357,7 @@
 	struct list_head	request_list;
 	struct list_head	req_queued;
 
-	struct dwc3_trb_hw	*trb_pool;
+	struct dwc3_trb		*trb_pool;
 	dma_addr_t		trb_pool_dma;
 	u32			free_slot;
 	u32			busy_slot;
@@ -418,102 +432,49 @@
 	DWC3_CONFIGURED_STATE,
 };
 
-/**
- * struct dwc3_trb - transfer request block
- * @bpl: lower 32bit of the buffer
- * @bph: higher 32bit of the buffer
- * @length: buffer size (up to 16mb - 1)
- * @pcm1: packet count m1
- * @trbsts: trb status
- *	0 = ok
- *	1 = missed isoc
- *	2 = setup pending
- * @hwo: hardware owner of descriptor
- * @lst: last trb
- * @chn: chain buffers
- * @csp: continue on short packets (only supported on isoc eps)
- * @trbctl: trb control
- *	1 = normal
- *	2 = control-setup
- *	3 = control-status-2
- *	4 = control-status-3
- *	5 = control-data (first trb of data stage)
- *	6 = isochronous-first (first trb of service interval)
- *	7 = isochronous
- *	8 = link trb
- *	others = reserved
- * @isp_imi: interrupt on short packet / interrupt on missed isoc
- * @ioc: interrupt on complete
- * @sid_sofn: Stream ID / SOF Number
- */
-struct dwc3_trb {
-	u64             bplh;
+/* TRB Length, PCM and Status */
+#define DWC3_TRB_SIZE_MASK	(0x00ffffff)
+#define DWC3_TRB_SIZE_LENGTH(n)	((n) & DWC3_TRB_SIZE_MASK)
+#define DWC3_TRB_SIZE_PCM1(n)	(((n) & 0x03) << 24)
+#define DWC3_TRB_SIZE_TRBSTS(n)	(((n) & (0x0f << 28) >> 28))
 
-	union {
-		struct {
-			u32             length:24;
-			u32             pcm1:2;
-			u32             reserved27_26:2;
-			u32             trbsts:4;
-#define DWC3_TRB_STS_OKAY                       0
-#define DWC3_TRB_STS_MISSED_ISOC                1
-#define DWC3_TRB_STS_SETUP_PENDING              2
-		};
-		u32 len_pcm;
-	};
+#define DWC3_TRBSTS_OK			0
+#define DWC3_TRBSTS_MISSED_ISOC		1
+#define DWC3_TRBSTS_SETUP_PENDING	2
 
-	union {
-		struct {
-			u32             hwo:1;
-			u32             lst:1;
-			u32             chn:1;
-			u32             csp:1;
-			u32             trbctl:6;
-			u32             isp_imi:1;
-			u32             ioc:1;
-			u32             reserved13_12:2;
-			u32             sid_sofn:16;
-			u32             reserved31_30:2;
-		};
-		u32 control;
-	};
-} __packed;
+/* TRB Control */
+#define DWC3_TRB_CTRL_HWO		(1 << 0)
+#define DWC3_TRB_CTRL_LST		(1 << 1)
+#define DWC3_TRB_CTRL_CHN		(1 << 2)
+#define DWC3_TRB_CTRL_CSP		(1 << 3)
+#define DWC3_TRB_CTRL_TRBCTL(n)		(((n) & 0x3f) << 4)
+#define DWC3_TRB_CTRL_ISP_IMI		(1 << 10)
+#define DWC3_TRB_CTRL_IOC		(1 << 11)
+#define DWC3_TRB_CTRL_SID_SOFN(n)	(((n) & 0xffff) << 14)
+
+#define DWC3_TRBCTL_NORMAL		DWC3_TRB_CTRL_TRBCTL(1)
+#define DWC3_TRBCTL_CONTROL_SETUP	DWC3_TRB_CTRL_TRBCTL(2)
+#define DWC3_TRBCTL_CONTROL_STATUS2	DWC3_TRB_CTRL_TRBCTL(3)
+#define DWC3_TRBCTL_CONTROL_STATUS3	DWC3_TRB_CTRL_TRBCTL(4)
+#define DWC3_TRBCTL_CONTROL_DATA	DWC3_TRB_CTRL_TRBCTL(5)
+#define DWC3_TRBCTL_ISOCHRONOUS_FIRST	DWC3_TRB_CTRL_TRBCTL(6)
+#define DWC3_TRBCTL_ISOCHRONOUS		DWC3_TRB_CTRL_TRBCTL(7)
+#define DWC3_TRBCTL_LINK_TRB		DWC3_TRB_CTRL_TRBCTL(8)
 
 /**
- * struct dwc3_trb_hw - transfer request block (hw format)
+ * struct dwc3_trb - transfer request block (hw format)
  * @bpl: DW0-3
  * @bph: DW4-7
  * @size: DW8-B
  * @trl: DWC-F
  */
-struct dwc3_trb_hw {
-	__le32		bpl;
-	__le32		bph;
-	__le32		size;
-	__le32		ctrl;
+struct dwc3_trb {
+	u32		bpl;
+	u32		bph;
+	u32		size;
+	u32		ctrl;
 } __packed;
 
-static inline void dwc3_trb_to_hw(struct dwc3_trb *nat, struct dwc3_trb_hw *hw)
-{
-	hw->bpl = cpu_to_le32(lower_32_bits(nat->bplh));
-	hw->bph = cpu_to_le32(upper_32_bits(nat->bplh));
-	hw->size = cpu_to_le32p(&nat->len_pcm);
-	/* HWO is written last */
-	hw->ctrl = cpu_to_le32p(&nat->control);
-}
-
-static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat)
-{
-	u64 bplh;
-
-	bplh = le32_to_cpup(&hw->bpl);
-	bplh |= (u64) le32_to_cpup(&hw->bph) << 32;
-	nat->bplh = bplh;
-
-	nat->len_pcm = le32_to_cpup(&hw->size);
-	nat->control = le32_to_cpup(&hw->ctrl);
-}
-
 /**
  * dwc3_hwparams - copy of HWPARAMS registers
  * @hwparams0 - GHWPARAMS0
@@ -546,8 +507,13 @@
 #define DWC3_MODE_DRD		2
 #define DWC3_MODE_HUB		3
 
+#define DWC3_MDWIDTH(n)		(((n) & 0xff00) >> 8)
+
 /* HWPARAMS1 */
-#define DWC3_NUM_INT(n)	(((n) & (0x3f << 15)) >> 15)
+#define DWC3_NUM_INT(n)		(((n) & (0x3f << 15)) >> 15)
+
+/* HWPARAMS7 */
+#define DWC3_RAM1_DEPTH(n)	((n) & 0xffff)
 
 struct dwc3_request {
 	struct usb_request	request;
@@ -555,7 +521,7 @@
 	struct dwc3_ep		*dep;
 
 	u8			epnum;
-	struct dwc3_trb_hw	*trb;
+	struct dwc3_trb		*trb;
 	dma_addr_t		trb_dma;
 
 	unsigned		direction:1;
@@ -572,7 +538,6 @@
  * @ctrl_req_addr: dma address of ctrl_req
  * @ep0_trb: dma address of ep0_trb
  * @ep0_usb_req: dummy req used while handling STD USB requests
- * @setup_buf_addr: dma address of setup_buf
  * @ep0_bounce_addr: dma address of ep0_bounce
  * @lock: for synchronizing
  * @dev: pointer to our struct device
@@ -594,6 +559,8 @@
  * @ep0_expect_in: true when we expect a DATA IN transfer
  * @start_config_issued: true when StartConfig command has been issued
  * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
+ * @needs_fifo_resize: not all users might want fifo resizing, flag it
+ * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
  * @ep0_next_event: hold the next expected event
  * @ep0state: state of endpoint zero
  * @link_state: link state
@@ -604,12 +571,11 @@
  */
 struct dwc3 {
 	struct usb_ctrlrequest	*ctrl_req;
-	struct dwc3_trb_hw	*ep0_trb;
+	struct dwc3_trb		*ep0_trb;
 	void			*ep0_bounce;
 	u8			*setup_buf;
 	dma_addr_t		ctrl_req_addr;
 	dma_addr_t		ep0_trb_addr;
-	dma_addr_t		setup_buf_addr;
 	dma_addr_t		ep0_bounce_addr;
 	struct dwc3_request	ep0_usb_req;
 	/* device lock */
@@ -651,6 +617,8 @@
 	unsigned		start_config_issued:1;
 	unsigned		setup_packet_pending:1;
 	unsigned		delayed_status:1;
+	unsigned		needs_fifo_resize:1;
+	unsigned		resize_fifos:1;
 
 	enum dwc3_ep0_next	ep0_next_event;
 	enum dwc3_ep0_state	ep0state;
@@ -662,23 +630,13 @@
 
 	struct dwc3_hwparams	hwparams;
 	struct dentry		*root;
+
+	u8			test_mode;
+	u8			test_mode_nr;
 };
 
 /* -------------------------------------------------------------------------- */
 
-#define DWC3_TRBSTS_OK			0
-#define DWC3_TRBSTS_MISSED_ISOC		1
-#define DWC3_TRBSTS_SETUP_PENDING	2
-
-#define DWC3_TRBCTL_NORMAL		1
-#define DWC3_TRBCTL_CONTROL_SETUP	2
-#define DWC3_TRBCTL_CONTROL_STATUS2	3
-#define DWC3_TRBCTL_CONTROL_STATUS3	4
-#define DWC3_TRBCTL_CONTROL_DATA	5
-#define DWC3_TRBCTL_ISOCHRONOUS_FIRST	6
-#define DWC3_TRBCTL_ISOCHRONOUS		7
-#define DWC3_TRBCTL_LINK_TRB		8
-
 /* -------------------------------------------------------------------------- */
 
 struct dwc3_event_type {
@@ -719,9 +677,14 @@
 	u32	endpoint_event:4;
 	u32	reserved11_10:2;
 	u32	status:4;
-#define DEPEVT_STATUS_BUSERR    (1 << 0)
-#define DEPEVT_STATUS_SHORT     (1 << 1)
-#define DEPEVT_STATUS_IOC       (1 << 2)
+
+/* Within XferNotReady */
+#define DEPEVT_STATUS_TRANSFER_ACTIVE	(1 << 3)
+
+/* Within XferComplete */
+#define DEPEVT_STATUS_BUSERR	(1 << 0)
+#define DEPEVT_STATUS_SHORT	(1 << 1)
+#define DEPEVT_STATUS_IOC	(1 << 2)
 #define DEPEVT_STATUS_LST	(1 << 3)
 
 /* Stream event only */
@@ -807,6 +770,7 @@
 
 /* prototypes */
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
+int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
 
 int dwc3_host_init(struct dwc3 *dwc);
 void dwc3_host_exit(struct dwc3 *dwc);
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index 433c97c..d4a30f1 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -46,6 +46,8 @@
 #include <linux/delay.h>
 #include <linux/uaccess.h>
 
+#include <linux/usb/ch9.h>
+
 #include "core.h"
 #include "gadget.h"
 #include "io.h"
@@ -464,6 +466,192 @@
 	.release		= single_release,
 };
 
+static int dwc3_testmode_show(struct seq_file *s, void *unused)
+{
+	struct dwc3		*dwc = s->private;
+	unsigned long		flags;
+	u32			reg;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg &= DWC3_DCTL_TSTCTRL_MASK;
+	reg >>= 1;
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	switch (reg) {
+	case 0:
+		seq_printf(s, "no test\n");
+		break;
+	case TEST_J:
+		seq_printf(s, "test_j\n");
+		break;
+	case TEST_K:
+		seq_printf(s, "test_k\n");
+		break;
+	case TEST_SE0_NAK:
+		seq_printf(s, "test_se0_nak\n");
+		break;
+	case TEST_PACKET:
+		seq_printf(s, "test_packet\n");
+		break;
+	case TEST_FORCE_EN:
+		seq_printf(s, "test_force_enable\n");
+		break;
+	default:
+		seq_printf(s, "UNKNOWN %d\n", reg);
+	}
+
+	return 0;
+}
+
+static int dwc3_testmode_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dwc3_testmode_show, inode->i_private);
+}
+
+static ssize_t dwc3_testmode_write(struct file *file,
+		const char __user *ubuf, size_t count, loff_t *ppos)
+{
+	struct seq_file		*s = file->private_data;
+	struct dwc3		*dwc = s->private;
+	unsigned long		flags;
+	u32			testmode = 0;
+	char			buf[32];
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+		return -EFAULT;
+
+	if (!strncmp(buf, "test_j", 6))
+		testmode = TEST_J;
+	else if (!strncmp(buf, "test_k", 6))
+		testmode = TEST_K;
+	else if (!strncmp(buf, "test_se0_nak", 12))
+		testmode = TEST_SE0_NAK;
+	else if (!strncmp(buf, "test_packet", 11))
+		testmode = TEST_PACKET;
+	else if (!strncmp(buf, "test_force_enable", 17))
+		testmode = TEST_FORCE_EN;
+	else
+		testmode = 0;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	dwc3_gadget_set_test_mode(dwc, testmode);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return count;
+}
+
+static const struct file_operations dwc3_testmode_fops = {
+	.open			= dwc3_testmode_open,
+	.write			= dwc3_testmode_write,
+	.read			= seq_read,
+	.llseek			= seq_lseek,
+	.release		= single_release,
+};
+
+static int dwc3_link_state_show(struct seq_file *s, void *unused)
+{
+	struct dwc3		*dwc = s->private;
+	unsigned long		flags;
+	enum dwc3_link_state	state;
+	u32			reg;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+	state = DWC3_DSTS_USBLNKST(reg);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	switch (state) {
+	case DWC3_LINK_STATE_U0:
+		seq_printf(s, "U0\n");
+		break;
+	case DWC3_LINK_STATE_U1:
+		seq_printf(s, "U1\n");
+		break;
+	case DWC3_LINK_STATE_U2:
+		seq_printf(s, "U2\n");
+		break;
+	case DWC3_LINK_STATE_U3:
+		seq_printf(s, "U3\n");
+		break;
+	case DWC3_LINK_STATE_SS_DIS:
+		seq_printf(s, "SS.Disabled\n");
+		break;
+	case DWC3_LINK_STATE_RX_DET:
+		seq_printf(s, "Rx.Detect\n");
+		break;
+	case DWC3_LINK_STATE_SS_INACT:
+		seq_printf(s, "SS.Inactive\n");
+		break;
+	case DWC3_LINK_STATE_POLL:
+		seq_printf(s, "Poll\n");
+		break;
+	case DWC3_LINK_STATE_RECOV:
+		seq_printf(s, "Recovery\n");
+		break;
+	case DWC3_LINK_STATE_HRESET:
+		seq_printf(s, "HRESET\n");
+		break;
+	case DWC3_LINK_STATE_CMPLY:
+		seq_printf(s, "Compliance\n");
+		break;
+	case DWC3_LINK_STATE_LPBK:
+		seq_printf(s, "Loopback\n");
+		break;
+	default:
+		seq_printf(s, "UNKNOWN %d\n", reg);
+	}
+
+	return 0;
+}
+
+static int dwc3_link_state_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dwc3_link_state_show, inode->i_private);
+}
+
+static ssize_t dwc3_link_state_write(struct file *file,
+		const char __user *ubuf, size_t count, loff_t *ppos)
+{
+	struct seq_file		*s = file->private_data;
+	struct dwc3		*dwc = s->private;
+	unsigned long		flags;
+	enum dwc3_link_state	state = 0;
+	char			buf[32];
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+		return -EFAULT;
+
+	if (!strncmp(buf, "SS.Disabled", 11))
+		state = DWC3_LINK_STATE_SS_DIS;
+	else if (!strncmp(buf, "Rx.Detect", 9))
+		state = DWC3_LINK_STATE_RX_DET;
+	else if (!strncmp(buf, "SS.Inactive", 11))
+		state = DWC3_LINK_STATE_SS_INACT;
+	else if (!strncmp(buf, "Recovery", 8))
+		state = DWC3_LINK_STATE_RECOV;
+	else if (!strncmp(buf, "Compliance", 10))
+		state = DWC3_LINK_STATE_CMPLY;
+	else if (!strncmp(buf, "Loopback", 8))
+		state = DWC3_LINK_STATE_LPBK;
+	else
+		return -EINVAL;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	dwc3_gadget_set_link_state(dwc, state);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return count;
+}
+
+static const struct file_operations dwc3_link_state_fops = {
+	.open			= dwc3_link_state_open,
+	.write			= dwc3_link_state_write,
+	.read			= seq_read,
+	.llseek			= seq_lseek,
+	.release		= single_release,
+};
+
 int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
 {
 	struct dentry		*root;
@@ -471,8 +659,8 @@
 	int			ret;
 
 	root = debugfs_create_dir(dev_name(dwc->dev), NULL);
-	if (IS_ERR(root)) {
-		ret = PTR_ERR(root);
+	if (!root) {
+		ret = -ENOMEM;
 		goto err0;
 	}
 
@@ -480,15 +668,29 @@
 
 	file = debugfs_create_file("regdump", S_IRUGO, root, dwc,
 			&dwc3_regdump_fops);
-	if (IS_ERR(file)) {
-		ret = PTR_ERR(file);
+	if (!file) {
+		ret = -ENOMEM;
 		goto err1;
 	}
 
 	file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
 			dwc, &dwc3_mode_fops);
-	if (IS_ERR(file)) {
-		ret = PTR_ERR(file);
+	if (!file) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
+			dwc, &dwc3_testmode_fops);
+	if (!file) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
+			dwc, &dwc3_link_state_fops);
+	if (!file) {
+		ret = -ENOMEM;
 		goto err1;
 	}
 
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
new file mode 100644
index 0000000..d190301
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -0,0 +1,151 @@
+/**
+ * dwc3-exynos.c - Samsung EXYNOS DWC3 Specific Glue layer
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Author: Anton Tikhomirov <av.tikhomirov@samsung.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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/dwc3-exynos.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+
+#include "core.h"
+
+struct dwc3_exynos {
+	struct platform_device	*dwc3;
+	struct device		*dev;
+
+	struct clk		*clk;
+};
+
+static int __devinit dwc3_exynos_probe(struct platform_device *pdev)
+{
+	struct dwc3_exynos_data	*pdata = pdev->dev.platform_data;
+	struct platform_device	*dwc3;
+	struct dwc3_exynos	*exynos;
+	struct clk		*clk;
+
+	int			devid;
+	int			ret = -ENOMEM;
+
+	exynos = kzalloc(sizeof(*exynos), GFP_KERNEL);
+	if (!exynos) {
+		dev_err(&pdev->dev, "not enough memory\n");
+		goto err0;
+	}
+
+	platform_set_drvdata(pdev, exynos);
+
+	devid = dwc3_get_device_id();
+	if (devid < 0)
+		goto err1;
+
+	dwc3 = platform_device_alloc("dwc3", devid);
+	if (!dwc3) {
+		dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
+		goto err2;
+	}
+
+	clk = clk_get(&pdev->dev, "usbdrd30");
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "couldn't get clock\n");
+		ret = -EINVAL;
+		goto err3;
+	}
+
+	dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
+
+	dwc3->dev.parent = &pdev->dev;
+	dwc3->dev.dma_mask = pdev->dev.dma_mask;
+	dwc3->dev.dma_parms = pdev->dev.dma_parms;
+	exynos->dwc3	= dwc3;
+	exynos->dev	= &pdev->dev;
+	exynos->clk	= clk;
+
+	clk_enable(exynos->clk);
+
+	/* PHY initialization */
+	if (!pdata) {
+		dev_dbg(&pdev->dev, "missing platform data\n");
+	} else {
+		if (pdata->phy_init)
+			pdata->phy_init(pdev, pdata->phy_type);
+	}
+
+	ret = platform_device_add_resources(dwc3, pdev->resource,
+			pdev->num_resources);
+	if (ret) {
+		dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
+		goto err4;
+	}
+
+	ret = platform_device_add(dwc3);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register dwc3 device\n");
+		goto err4;
+	}
+
+	return 0;
+
+err4:
+	if (pdata && pdata->phy_exit)
+		pdata->phy_exit(pdev, pdata->phy_type);
+
+	clk_disable(clk);
+	clk_put(clk);
+err3:
+	platform_device_put(dwc3);
+err2:
+	dwc3_put_device_id(devid);
+err1:
+	kfree(exynos);
+err0:
+	return ret;
+}
+
+static int __devexit dwc3_exynos_remove(struct platform_device *pdev)
+{
+	struct dwc3_exynos	*exynos = platform_get_drvdata(pdev);
+	struct dwc3_exynos_data *pdata = pdev->dev.platform_data;
+
+	platform_device_unregister(exynos->dwc3);
+
+	dwc3_put_device_id(exynos->dwc3->id);
+
+	if (pdata && pdata->phy_exit)
+		pdata->phy_exit(pdev, pdata->phy_type);
+
+	clk_disable(exynos->clk);
+	clk_put(exynos->clk);
+
+	kfree(exynos);
+
+	return 0;
+}
+
+static struct platform_driver dwc3_exynos_driver = {
+	.probe		= dwc3_exynos_probe,
+	.remove		= __devexit_p(dwc3_exynos_remove),
+	.driver		= {
+		.name	= "exynos-dwc3",
+	},
+};
+
+module_platform_driver(dwc3_exynos_driver);
+
+MODULE_ALIAS("platform:exynos-dwc3");
+MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer");
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index 3274ac8..d7d9c0e 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -46,7 +46,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/ioport.h>
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/of.h>
 
 #include "core.h"
 #include "io.h"
@@ -197,91 +197,99 @@
 static int __devinit dwc3_omap_probe(struct platform_device *pdev)
 {
 	struct dwc3_omap_data	*pdata = pdev->dev.platform_data;
+	struct device_node	*node = pdev->dev.of_node;
+
 	struct platform_device	*dwc3;
 	struct dwc3_omap	*omap;
 	struct resource		*res;
+	struct device		*dev = &pdev->dev;
 
 	int			devid;
+	int			size;
 	int			ret = -ENOMEM;
 	int			irq;
 
+	const u32		*utmi_mode;
 	u32			reg;
 
 	void __iomem		*base;
 	void			*context;
 
-	omap = kzalloc(sizeof(*omap), GFP_KERNEL);
+	omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
 	if (!omap) {
-		dev_err(&pdev->dev, "not enough memory\n");
-		goto err0;
+		dev_err(dev, "not enough memory\n");
+		return -ENOMEM;
 	}
 
 	platform_set_drvdata(pdev, omap);
 
 	irq = platform_get_irq(pdev, 1);
 	if (irq < 0) {
-		dev_err(&pdev->dev, "missing IRQ resource\n");
-		ret = -EINVAL;
-		goto err1;
+		dev_err(dev, "missing IRQ resource\n");
+		return -EINVAL;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	if (!res) {
-		dev_err(&pdev->dev, "missing memory base resource\n");
-		ret = -EINVAL;
-		goto err1;
+		dev_err(dev, "missing memory base resource\n");
+		return -EINVAL;
 	}
 
-	base = ioremap_nocache(res->start, resource_size(res));
+	base = devm_ioremap_nocache(dev, res->start, resource_size(res));
 	if (!base) {
-		dev_err(&pdev->dev, "ioremap failed\n");
-		goto err1;
+		dev_err(dev, "ioremap failed\n");
+		return -ENOMEM;
 	}
 
 	devid = dwc3_get_device_id();
 	if (devid < 0)
-		goto err2;
+		return -ENODEV;
 
 	dwc3 = platform_device_alloc("dwc3", devid);
 	if (!dwc3) {
-		dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
-		goto err3;
+		dev_err(dev, "couldn't allocate dwc3 device\n");
+		goto err1;
 	}
 
-	context = kzalloc(resource_size(res), GFP_KERNEL);
+	context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL);
 	if (!context) {
-		dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n");
-		goto err4;
+		dev_err(dev, "couldn't allocate dwc3 context memory\n");
+		goto err2;
 	}
 
 	spin_lock_init(&omap->lock);
-	dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
+	dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
 
-	dwc3->dev.parent = &pdev->dev;
-	dwc3->dev.dma_mask = pdev->dev.dma_mask;
-	dwc3->dev.dma_parms = pdev->dev.dma_parms;
+	dwc3->dev.parent = dev;
+	dwc3->dev.dma_mask = dev->dma_mask;
+	dwc3->dev.dma_parms = dev->dma_parms;
 	omap->resource_size = resource_size(res);
 	omap->context	= context;
-	omap->dev	= &pdev->dev;
+	omap->dev	= dev;
 	omap->irq	= irq;
 	omap->base	= base;
 	omap->dwc3	= dwc3;
 
 	reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
 
-	if (!pdata) {
-		dev_dbg(&pdev->dev, "missing platform data\n");
+	utmi_mode = of_get_property(node, "utmi-mode", &size);
+	if (utmi_mode && size == sizeof(*utmi_mode)) {
+		reg |= *utmi_mode;
 	} else {
-		switch (pdata->utmi_mode) {
-		case DWC3_OMAP_UTMI_MODE_SW:
-			reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
-			break;
-		case DWC3_OMAP_UTMI_MODE_HW:
-			reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
-			break;
-		default:
-			dev_dbg(&pdev->dev, "UNKNOWN utmi mode %d\n",
-					pdata->utmi_mode);
+		if (!pdata) {
+			dev_dbg(dev, "missing platform data\n");
+		} else {
+			switch (pdata->utmi_mode) {
+			case DWC3_OMAP_UTMI_MODE_SW:
+				reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+				break;
+			case DWC3_OMAP_UTMI_MODE_HW:
+				reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+				break;
+			default:
+				dev_dbg(dev, "UNKNOWN utmi mode %d\n",
+						pdata->utmi_mode);
+			}
 		}
 	}
 
@@ -300,12 +308,12 @@
 
 	dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
 
-	ret = request_irq(omap->irq, dwc3_omap_interrupt, 0,
+	ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
 			"dwc3-omap", omap);
 	if (ret) {
-		dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",
+		dev_err(dev, "failed to request IRQ #%d --> %d\n",
 				omap->irq, ret);
-		goto err5;
+		goto err2;
 	}
 
 	/* enable all IRQs */
@@ -327,37 +335,24 @@
 	ret = platform_device_add_resources(dwc3, pdev->resource,
 			pdev->num_resources);
 	if (ret) {
-		dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
-		goto err6;
+		dev_err(dev, "couldn't add resources to dwc3 device\n");
+		goto err2;
 	}
 
 	ret = platform_device_add(dwc3);
 	if (ret) {
-		dev_err(&pdev->dev, "failed to register dwc3 device\n");
-		goto err6;
+		dev_err(dev, "failed to register dwc3 device\n");
+		goto err2;
 	}
 
 	return 0;
 
-err6:
-	free_irq(omap->irq, omap);
-
-err5:
-	kfree(omap->context);
-
-err4:
+err2:
 	platform_device_put(dwc3);
 
-err3:
+err1:
 	dwc3_put_device_id(devid);
 
-err2:
-	iounmap(base);
-
-err1:
-	kfree(omap);
-
-err0:
 	return ret;
 }
 
@@ -368,11 +363,6 @@
 	platform_device_unregister(omap->dwc3);
 
 	dwc3_put_device_id(omap->dwc3->id);
-	free_irq(omap->irq, omap);
-	iounmap(omap->base);
-
-	kfree(omap->context);
-	kfree(omap);
 
 	return 0;
 }
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 64e1f7c..a9ca9ad 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -61,32 +61,36 @@
 	struct dwc3_pci		*glue;
 	int			ret = -ENOMEM;
 	int			devid;
+	struct device		*dev = &pci->dev;
 
-	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+	glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
 	if (!glue) {
-		dev_err(&pci->dev, "not enough memory\n");
-		goto err0;
+		dev_err(dev, "not enough memory\n");
+		return -ENOMEM;
 	}
 
-	glue->dev	= &pci->dev;
+	glue->dev = dev;
 
 	ret = pci_enable_device(pci);
 	if (ret) {
-		dev_err(&pci->dev, "failed to enable pci device\n");
-		goto err1;
+		dev_err(dev, "failed to enable pci device\n");
+		return -ENODEV;
 	}
 
 	pci_set_power_state(pci, PCI_D0);
 	pci_set_master(pci);
 
 	devid = dwc3_get_device_id();
-	if (devid < 0)
-		goto err2;
+	if (devid < 0) {
+		ret = -ENOMEM;
+		goto err1;
+	}
 
 	dwc3 = platform_device_alloc("dwc3", devid);
 	if (!dwc3) {
-		dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
-		goto err3;
+		dev_err(dev, "couldn't allocate dwc3 device\n");
+		ret = -ENOMEM;
+		goto err1;
 	}
 
 	memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
@@ -102,41 +106,37 @@
 
 	ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
 	if (ret) {
-		dev_err(&pci->dev, "couldn't add resources to dwc3 device\n");
-		goto err4;
+		dev_err(dev, "couldn't add resources to dwc3 device\n");
+		goto err2;
 	}
 
 	pci_set_drvdata(pci, glue);
 
-	dma_set_coherent_mask(&dwc3->dev, pci->dev.coherent_dma_mask);
+	dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
 
-	dwc3->dev.dma_mask = pci->dev.dma_mask;
-	dwc3->dev.dma_parms = pci->dev.dma_parms;
-	dwc3->dev.parent = &pci->dev;
-	glue->dwc3	= dwc3;
+	dwc3->dev.dma_mask = dev->dma_mask;
+	dwc3->dev.dma_parms = dev->dma_parms;
+	dwc3->dev.parent = dev;
+	glue->dwc3 = dwc3;
 
 	ret = platform_device_add(dwc3);
 	if (ret) {
-		dev_err(&pci->dev, "failed to register dwc3 device\n");
-		goto err4;
+		dev_err(dev, "failed to register dwc3 device\n");
+		goto err3;
 	}
 
 	return 0;
 
-err4:
+err3:
 	pci_set_drvdata(pci, NULL);
 	platform_device_put(dwc3);
 
-err3:
+err2:
 	dwc3_put_device_id(devid);
 
-err2:
+err1:
 	pci_disable_device(pci);
 
-err1:
-	kfree(glue);
-
-err0:
 	return ret;
 }
 
@@ -148,7 +148,6 @@
 	platform_device_unregister(glue->dwc3);
 	pci_set_drvdata(pci, NULL);
 	pci_disable_device(pci);
-	kfree(glue);
 }
 
 static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
@@ -171,14 +170,4 @@
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
 
-static int __devinit dwc3_pci_init(void)
-{
-	return pci_register_driver(&dwc3_pci_driver);
-}
-module_init(dwc3_pci_init);
-
-static void __exit dwc3_pci_exit(void)
-{
-	pci_unregister_driver(&dwc3_pci_driver);
-}
-module_exit(dwc3_pci_exit);
+module_pci_driver(dwc3_pci_driver);
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index c8df1dd..25910e2 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -76,8 +76,7 @@
 		u32 len, u32 type)
 {
 	struct dwc3_gadget_ep_cmd_params params;
-	struct dwc3_trb_hw		*trb_hw;
-	struct dwc3_trb			trb;
+	struct dwc3_trb			*trb;
 	struct dwc3_ep			*dep;
 
 	int				ret;
@@ -88,19 +87,17 @@
 		return 0;
 	}
 
-	trb_hw = dwc->ep0_trb;
-	memset(&trb, 0, sizeof(trb));
+	trb = dwc->ep0_trb;
 
-	trb.trbctl = type;
-	trb.bplh = buf_dma;
-	trb.length = len;
+	trb->bpl = lower_32_bits(buf_dma);
+	trb->bph = upper_32_bits(buf_dma);
+	trb->size = len;
+	trb->ctrl = type;
 
-	trb.hwo	= 1;
-	trb.lst	= 1;
-	trb.ioc	= 1;
-	trb.isp_imi = 1;
-
-	dwc3_trb_to_hw(&trb, trb_hw);
+	trb->ctrl |= (DWC3_TRB_CTRL_HWO
+			| DWC3_TRB_CTRL_LST
+			| DWC3_TRB_CTRL_IOC
+			| DWC3_TRB_CTRL_ISP_IMI);
 
 	memset(&params, 0, sizeof(params));
 	params.param0 = upper_32_bits(dwc->ep0_trb_addr);
@@ -302,7 +299,7 @@
 	dep = dwc->eps[0];
 	dwc->ep0_usb_req.dep = dep;
 	dwc->ep0_usb_req.request.length = sizeof(*response_pkt);
-	dwc->ep0_usb_req.request.dma = dwc->setup_buf_addr;
+	dwc->ep0_usb_req.request.buf = dwc->setup_buf;
 	dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl;
 
 	return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
@@ -315,9 +312,7 @@
 	u32			recip;
 	u32			wValue;
 	u32			wIndex;
-	u32			reg;
 	int			ret;
-	u32			mode;
 
 	wValue = le16_to_cpu(ctrl->wValue);
 	wIndex = le16_to_cpu(ctrl->wIndex);
@@ -356,25 +351,8 @@
 			if (!set)
 				return -EINVAL;
 
-			mode = wIndex >> 8;
-			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
-			reg &= ~DWC3_DCTL_TSTCTRL_MASK;
-
-			switch (mode) {
-			case TEST_J:
-			case TEST_K:
-			case TEST_SE0_NAK:
-			case TEST_PACKET:
-			case TEST_FORCE_EN:
-				reg |= mode << 1;
-				break;
-			default:
-				return -EINVAL;
-			}
-			dwc3_writel(dwc->regs, DWC3_DCTL, reg);
-			break;
-		default:
-			return -EINVAL;
+			dwc->test_mode_nr = wIndex >> 8;
+			dwc->test_mode = true;
 		}
 		break;
 
@@ -396,7 +374,7 @@
 	case USB_RECIP_ENDPOINT:
 		switch (wValue) {
 		case USB_ENDPOINT_HALT:
-			dep =  dwc3_wIndex_to_dep(dwc, wIndex);
+			dep = dwc3_wIndex_to_dep(dwc, wIndex);
 			if (!dep)
 				return -EINVAL;
 			ret = __dwc3_gadget_ep_set_halt(dep, set);
@@ -470,8 +448,11 @@
 	case DWC3_ADDRESS_STATE:
 		ret = dwc3_ep0_delegate_req(dwc, ctrl);
 		/* if the cfg matches and the cfg is non zero */
-		if (!ret && cfg)
+		if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
 			dwc->dev_state = DWC3_CONFIGURED_STATE;
+			dwc->resize_fifos = true;
+			dev_dbg(dwc->dev, "resize fifos flag SET\n");
+		}
 		break;
 
 	case DWC3_CONFIGURED_STATE:
@@ -560,9 +541,10 @@
 {
 	struct dwc3_request	*r = NULL;
 	struct usb_request	*ur;
-	struct dwc3_trb		trb;
+	struct dwc3_trb		*trb;
 	struct dwc3_ep		*ep0;
 	u32			transferred;
+	u32			length;
 	u8			epnum;
 
 	epnum = event->endpoint_number;
@@ -573,16 +555,16 @@
 	r = next_request(&ep0->request_list);
 	ur = &r->request;
 
-	dwc3_trb_to_nat(dwc->ep0_trb, &trb);
+	trb = dwc->ep0_trb;
+	length = trb->size & DWC3_TRB_SIZE_MASK;
 
 	if (dwc->ep0_bounced) {
-
 		transferred = min_t(u32, ur->length,
-				ep0->endpoint.maxpacket - trb.length);
+				ep0->endpoint.maxpacket - length);
 		memcpy(ur->buf, dwc->ep0_bounce, transferred);
 		dwc->ep0_bounced = false;
 	} else {
-		transferred = ur->length - trb.length;
+		transferred = ur->length - length;
 		ur->actual += transferred;
 	}
 
@@ -614,6 +596,17 @@
 		dwc3_gadget_giveback(dep, r, 0);
 	}
 
+	if (dwc->test_mode) {
+		int ret;
+
+		ret = dwc3_gadget_set_test_mode(dwc, dwc->test_mode_nr);
+		if (ret < 0) {
+			dev_dbg(dwc->dev, "Invalid Test #%d\n",
+					dwc->test_mode_nr);
+			dwc3_ep0_stall_and_restart(dwc);
+		}
+	}
+
 	dwc->ep0state = EP0_SETUP_PHASE;
 	dwc3_ep0_out_start(dwc);
 }
@@ -624,6 +617,7 @@
 	struct dwc3_ep		*dep = dwc->eps[event->endpoint_number];
 
 	dep->flags &= ~DWC3_EP_BUSY;
+	dep->res_trans_idx = 0;
 	dwc->setup_packet_pending = false;
 
 	switch (dwc->ep0state) {
@@ -679,7 +673,12 @@
 				DWC3_TRBCTL_CONTROL_DATA);
 	} else if ((req->request.length % dep->endpoint.maxpacket)
 			&& (event->endpoint_number == 0)) {
-		dwc3_map_buffer_to_dma(req);
+		ret = usb_gadget_map_request(&dwc->gadget, &req->request,
+				event->endpoint_number);
+		if (ret) {
+			dev_dbg(dwc->dev, "failed to map request\n");
+			return;
+		}
 
 		WARN_ON(req->request.length > dep->endpoint.maxpacket);
 
@@ -694,7 +693,12 @@
 				dwc->ep0_bounce_addr, dep->endpoint.maxpacket,
 				DWC3_TRBCTL_CONTROL_DATA);
 	} else {
-		dwc3_map_buffer_to_dma(req);
+		ret = usb_gadget_map_request(&dwc->gadget, &req->request,
+				event->endpoint_number);
+		if (ret) {
+			dev_dbg(dwc->dev, "failed to map request\n");
+			return;
+		}
 
 		ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
 				req->request.dma, req->request.length,
@@ -720,6 +724,12 @@
 {
 	struct dwc3_ep		*dep = dwc->eps[epnum];
 
+	if (dwc->resize_fifos) {
+		dev_dbg(dwc->dev, "starting to resize fifos\n");
+		dwc3_gadget_resize_tx_fifos(dwc);
+		dwc->resize_fifos = 0;
+	}
+
 	WARN_ON(dwc3_ep0_start_control_status(dep));
 }
 
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 064b6e2..5255fe9 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -54,68 +54,162 @@
 #include "gadget.h"
 #include "io.h"
 
-#define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
-
-void dwc3_map_buffer_to_dma(struct dwc3_request *req)
+/**
+ * dwc3_gadget_set_test_mode - Enables USB2 Test Modes
+ * @dwc: pointer to our context structure
+ * @mode: the mode to set (J, K SE0 NAK, Force Enable)
+ *
+ * Caller should take care of locking. This function will
+ * return 0 on success or -EINVAL if wrong Test Selector
+ * is passed
+ */
+int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
 {
-	struct dwc3			*dwc = req->dep->dwc;
+	u32		reg;
 
-	if (req->request.length == 0) {
-		/* req->request.dma = dwc->setup_buf_addr; */
-		return;
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+
+	switch (mode) {
+	case TEST_J:
+	case TEST_K:
+	case TEST_SE0_NAK:
+	case TEST_PACKET:
+	case TEST_FORCE_EN:
+		reg |= mode << 1;
+		break;
+	default:
+		return -EINVAL;
 	}
 
-	if (req->request.num_sgs) {
-		int	mapped;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
-		mapped = dma_map_sg(dwc->dev, req->request.sg,
-				req->request.num_sgs,
-				req->direction ? DMA_TO_DEVICE
-				: DMA_FROM_DEVICE);
-		if (mapped < 0) {
-			dev_err(dwc->dev, "failed to map SGs\n");
-			return;
-		}
-
-		req->request.num_mapped_sgs = mapped;
-		return;
-	}
-
-	if (req->request.dma == DMA_ADDR_INVALID) {
-		req->request.dma = dma_map_single(dwc->dev, req->request.buf,
-				req->request.length, req->direction
-				? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-		req->mapped = true;
-	}
+	return 0;
 }
 
-void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)
+/**
+ * dwc3_gadget_set_link_state - Sets USB Link to a particular State
+ * @dwc: pointer to our context structure
+ * @state: the state to put link into
+ *
+ * Caller should take care of locking. This function will
+ * return 0 on success or -ETIMEDOUT.
+ */
+int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
 {
-	struct dwc3			*dwc = req->dep->dwc;
+	int		retries = 10000;
+	u32		reg;
 
-	if (req->request.length == 0) {
-		req->request.dma = DMA_ADDR_INVALID;
-		return;
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
+
+	/* set requested state */
+	reg |= DWC3_DCTL_ULSTCHNGREQ(state);
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	/* wait for a change in DSTS */
+	while (--retries) {
+		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+		if (DWC3_DSTS_USBLNKST(reg) == state)
+			return 0;
+
+		udelay(5);
 	}
 
-	if (req->request.num_mapped_sgs) {
-		req->request.dma = DMA_ADDR_INVALID;
-		dma_unmap_sg(dwc->dev, req->request.sg,
-				req->request.num_mapped_sgs,
-				req->direction ? DMA_TO_DEVICE
-				: DMA_FROM_DEVICE);
+	dev_vdbg(dwc->dev, "link state change request timed out\n");
 
-		req->request.num_mapped_sgs = 0;
-		return;
+	return -ETIMEDOUT;
+}
+
+/**
+ * dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case
+ * @dwc: pointer to our context structure
+ *
+ * This function will a best effort FIFO allocation in order
+ * to improve FIFO usage and throughput, while still allowing
+ * us to enable as many endpoints as possible.
+ *
+ * Keep in mind that this operation will be highly dependent
+ * on the configured size for RAM1 - which contains TxFifo -,
+ * the amount of endpoints enabled on coreConsultant tool, and
+ * the width of the Master Bus.
+ *
+ * In the ideal world, we would always be able to satisfy the
+ * following equation:
+ *
+ * ((512 + 2 * MDWIDTH-Bytes) + (Number of IN Endpoints - 1) * \
+ * (3 * (1024 + MDWIDTH-Bytes) + MDWIDTH-Bytes)) / MDWIDTH-Bytes
+ *
+ * Unfortunately, due to many variables that's not always the case.
+ */
+int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
+{
+	int		last_fifo_depth = 0;
+	int		ram1_depth;
+	int		fifo_size;
+	int		mdwidth;
+	int		num;
+
+	if (!dwc->needs_fifo_resize)
+		return 0;
+
+	ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
+	mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
+
+	/* MDWIDTH is represented in bits, we need it in bytes */
+	mdwidth >>= 3;
+
+	/*
+	 * FIXME For now we will only allocate 1 wMaxPacketSize space
+	 * for each enabled endpoint, later patches will come to
+	 * improve this algorithm so that we better use the internal
+	 * FIFO space
+	 */
+	for (num = 0; num < DWC3_ENDPOINTS_NUM; num++) {
+		struct dwc3_ep	*dep = dwc->eps[num];
+		int		fifo_number = dep->number >> 1;
+		int		mult = 1;
+		int		tmp;
+
+		if (!(dep->number & 1))
+			continue;
+
+		if (!(dep->flags & DWC3_EP_ENABLED))
+			continue;
+
+		if (usb_endpoint_xfer_bulk(dep->desc)
+				|| usb_endpoint_xfer_isoc(dep->desc))
+			mult = 3;
+
+		/*
+		 * REVISIT: the following assumes we will always have enough
+		 * space available on the FIFO RAM for all possible use cases.
+		 * Make sure that's true somehow and change FIFO allocation
+		 * accordingly.
+		 *
+		 * If we have Bulk or Isochronous endpoints, we want
+		 * them to be able to be very, very fast. So we're giving
+		 * those endpoints a fifo_size which is enough for 3 full
+		 * packets
+		 */
+		tmp = mult * (dep->endpoint.maxpacket + mdwidth);
+		tmp += mdwidth;
+
+		fifo_size = DIV_ROUND_UP(tmp, mdwidth);
+
+		fifo_size |= (last_fifo_depth << 16);
+
+		dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",
+				dep->name, last_fifo_depth, fifo_size & 0xffff);
+
+		dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(fifo_number),
+				fifo_size);
+
+		last_fifo_depth += (fifo_size & 0xffff);
 	}
 
-	if (req->mapped) {
-		dma_unmap_single(dwc->dev, req->request.dma,
-				req->request.length, req->direction
-				? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-		req->mapped = 0;
-		req->request.dma = DMA_ADDR_INVALID;
-	}
+	return 0;
 }
 
 void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
@@ -144,14 +238,15 @@
 	if (req->request.status == -EINPROGRESS)
 		req->request.status = status;
 
-	dwc3_unmap_buffer_from_dma(req);
+	usb_gadget_unmap_request(&dwc->gadget, &req->request,
+			req->direction);
 
 	dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
 			req, dep->name, req->request.actual,
 			req->request.length, status);
 
 	spin_unlock(&dwc->lock);
-	req->request.complete(&req->dep->endpoint, &req->request);
+	req->request.complete(&dep->endpoint, &req->request);
 	spin_lock(&dwc->lock);
 }
 
@@ -219,7 +314,7 @@
 }
 
 static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
-		struct dwc3_trb_hw *trb)
+		struct dwc3_trb *trb)
 {
 	u32		offset = (char *) trb - (char *) dep->trb_pool;
 
@@ -368,9 +463,8 @@
 		return ret;
 
 	if (!(dep->flags & DWC3_EP_ENABLED)) {
-		struct dwc3_trb_hw	*trb_st_hw;
-		struct dwc3_trb_hw	*trb_link_hw;
-		struct dwc3_trb		trb_link;
+		struct dwc3_trb	*trb_st_hw;
+		struct dwc3_trb	*trb_link;
 
 		ret = dwc3_gadget_set_xfer_resource(dwc, dep);
 		if (ret)
@@ -390,15 +484,15 @@
 
 		memset(&trb_link, 0, sizeof(trb_link));
 
-		/* Link TRB for ISOC. The HWO but is never reset */
+		/* Link TRB for ISOC. The HWO bit is never reset */
 		trb_st_hw = &dep->trb_pool[0];
 
-		trb_link.bplh = dwc3_trb_dma_offset(dep, trb_st_hw);
-		trb_link.trbctl = DWC3_TRBCTL_LINK_TRB;
-		trb_link.hwo = true;
+		trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1];
 
-		trb_link_hw = &dep->trb_pool[DWC3_TRB_NUM - 1];
-		dwc3_trb_to_hw(&trb_link, trb_link_hw);
+		trb_link->bpl = lower_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
+		trb_link->bph = upper_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
+		trb_link->ctrl |= DWC3_TRBCTL_LINK_TRB;
+		trb_link->ctrl |= DWC3_TRB_CTRL_HWO;
 	}
 
 	return 0;
@@ -440,6 +534,7 @@
 
 	dep->stream_capable = false;
 	dep->desc = NULL;
+	dep->endpoint.desc = NULL;
 	dep->comp_desc = NULL;
 	dep->type = 0;
 	dep->flags = 0;
@@ -485,16 +580,16 @@
 
 	switch (usb_endpoint_type(desc)) {
 	case USB_ENDPOINT_XFER_CONTROL:
-		strncat(dep->name, "-control", sizeof(dep->name));
+		strlcat(dep->name, "-control", sizeof(dep->name));
 		break;
 	case USB_ENDPOINT_XFER_ISOC:
-		strncat(dep->name, "-isoc", sizeof(dep->name));
+		strlcat(dep->name, "-isoc", sizeof(dep->name));
 		break;
 	case USB_ENDPOINT_XFER_BULK:
-		strncat(dep->name, "-bulk", sizeof(dep->name));
+		strlcat(dep->name, "-bulk", sizeof(dep->name));
 		break;
 	case USB_ENDPOINT_XFER_INT:
-		strncat(dep->name, "-int", sizeof(dep->name));
+		strlcat(dep->name, "-int", sizeof(dep->name));
 		break;
 	default:
 		dev_err(dwc->dev, "invalid endpoint transfer type\n");
@@ -562,7 +657,6 @@
 
 	req->epnum	= dep->number;
 	req->dep	= dep;
-	req->request.dma = DMA_ADDR_INVALID;
 
 	return &req->request;
 }
@@ -585,8 +679,7 @@
 		unsigned length, unsigned last, unsigned chain)
 {
 	struct dwc3		*dwc = dep->dwc;
-	struct dwc3_trb_hw	*trb_hw;
-	struct dwc3_trb		trb;
+	struct dwc3_trb		*trb;
 
 	unsigned int		cur_slot;
 
@@ -595,7 +688,7 @@
 			length, last ? " last" : "",
 			chain ? " chain" : "");
 
-	trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+	trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
 	cur_slot = dep->free_slot;
 	dep->free_slot++;
 
@@ -604,40 +697,32 @@
 			usb_endpoint_xfer_isoc(dep->desc))
 		return;
 
-	memset(&trb, 0, sizeof(trb));
 	if (!req->trb) {
 		dwc3_gadget_move_request_queued(req);
-		req->trb = trb_hw;
-		req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
+		req->trb = trb;
+		req->trb_dma = dwc3_trb_dma_offset(dep, trb);
 	}
 
-	if (usb_endpoint_xfer_isoc(dep->desc)) {
-		trb.isp_imi = true;
-		trb.csp = true;
-	} else {
-		trb.chn = chain;
-		trb.lst = last;
-	}
-
-	if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
-		trb.sid_sofn = req->request.stream_id;
+	trb->size = DWC3_TRB_SIZE_LENGTH(length);
+	trb->bpl = lower_32_bits(dma);
+	trb->bph = upper_32_bits(dma);
 
 	switch (usb_endpoint_type(dep->desc)) {
 	case USB_ENDPOINT_XFER_CONTROL:
-		trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
+		trb->ctrl = DWC3_TRBCTL_CONTROL_SETUP;
 		break;
 
 	case USB_ENDPOINT_XFER_ISOC:
-		trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
+		trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
 
 		/* IOC every DWC3_TRB_NUM / 4 so we can refill */
 		if (!(cur_slot % (DWC3_TRB_NUM / 4)))
-			trb.ioc = last;
+			trb->ctrl |= DWC3_TRB_CTRL_IOC;
 		break;
 
 	case USB_ENDPOINT_XFER_BULK:
 	case USB_ENDPOINT_XFER_INT:
-		trb.trbctl = DWC3_TRBCTL_NORMAL;
+		trb->ctrl = DWC3_TRBCTL_NORMAL;
 		break;
 	default:
 		/*
@@ -647,11 +732,21 @@
 		BUG();
 	}
 
-	trb.length	= length;
-	trb.bplh	= dma;
-	trb.hwo		= true;
+	if (usb_endpoint_xfer_isoc(dep->desc)) {
+		trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
+		trb->ctrl |= DWC3_TRB_CTRL_CSP;
+	} else {
+		if (chain)
+			trb->ctrl |= DWC3_TRB_CTRL_CHN;
 
-	dwc3_trb_to_hw(&trb, trb_hw);
+		if (last)
+			trb->ctrl |= DWC3_TRB_CTRL_LST;
+	}
+
+	if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
+		trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
+
+	trb->ctrl |= DWC3_TRB_CTRL_HWO;
 }
 
 /*
@@ -659,14 +754,15 @@
  * @dep: endpoint for which requests are being prepared
  * @starting: true if the endpoint is idle and no requests are queued.
  *
- * The functions goes through the requests list and setups TRBs for the
- * transfers. The functions returns once there are not more TRBs available or
- * it run out of requests.
+ * The function goes through the requests list and sets up TRBs for the
+ * transfers. The function returns once there are no more TRBs available or
+ * it runs out of requests.
  */
 static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 {
 	struct dwc3_request	*req, *n;
 	u32			trbs_left;
+	u32			max;
 	unsigned int		last_one = 0;
 
 	BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
@@ -674,9 +770,16 @@
 	/* the first request must not be queued */
 	trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
 
+	/* Can't wrap around on a non-isoc EP since there's no link TRB */
+	if (!usb_endpoint_xfer_isoc(dep->desc)) {
+		max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK);
+		if (trbs_left > max)
+			trbs_left = max;
+	}
+
 	/*
-	 * if busy & slot are equal than it is either full or empty. If we are
-	 * starting to proceed requests then we are empty. Otherwise we ar
+	 * If busy & slot are equal than it is either full or empty. If we are
+	 * starting to process requests then we are empty. Otherwise we are
 	 * full and don't do anything
 	 */
 	if (!trbs_left) {
@@ -687,7 +790,7 @@
 		 * In case we start from scratch, we queue the ISOC requests
 		 * starting from slot 1. This is done because we use ring
 		 * buffer and have no LST bit to stop us. Instead, we place
-		 * IOC bit TRB_NUM/4. We try to avoid to having an interrupt
+		 * IOC bit every TRB_NUM/4. We try to avoid having an interrupt
 		 * after the first request so we start at slot 1 and have
 		 * 7 requests proceed before we hit the first IOC.
 		 * Other transfer types don't use the ring buffer and are
@@ -723,8 +826,8 @@
 				length = sg_dma_len(s);
 				dma = sg_dma_address(s);
 
-				if (i == (request->num_mapped_sgs - 1)
-						|| sg_is_last(s)) {
+				if (i == (request->num_mapped_sgs - 1) ||
+						sg_is_last(s)) {
 					last_one = true;
 					chain = false;
 				}
@@ -792,8 +895,7 @@
 		dwc3_prepare_trbs(dep, start_new);
 
 		/*
-		 * req points to the first request where HWO changed
-		 * from 0 to 1
+		 * req points to the first request where HWO changed from 0 to 1
 		 */
 		req = next_request(&dep->req_queued);
 	}
@@ -819,9 +921,10 @@
 		/*
 		 * FIXME we need to iterate over the list of requests
 		 * here and stop, unmap, free and del each of the linked
-		 * requests instead of we do now.
+		 * requests instead of what we do now.
 		 */
-		dwc3_unmap_buffer_from_dma(req);
+		usb_gadget_unmap_request(&dwc->gadget, &req->request,
+				req->direction);
 		list_del(&req->list);
 		return ret;
 	}
@@ -837,6 +940,9 @@
 
 static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 {
+	struct dwc3		*dwc = dep->dwc;
+	int			ret;
+
 	req->request.actual	= 0;
 	req->request.status	= -EINPROGRESS;
 	req->direction		= dep->direction;
@@ -852,9 +958,13 @@
 	 * particular token from the Host side.
 	 *
 	 * This will also avoid Host cancelling URBs due to too
-	 * many NACKs.
+	 * many NAKs.
 	 */
-	dwc3_map_buffer_to_dma(req);
+	ret = usb_gadget_map_request(&dwc->gadget, &req->request,
+			dep->direction);
+	if (ret)
+		return ret;
+
 	list_add_tail(&req->list, &dep->request_list);
 
 	/*
@@ -874,11 +984,11 @@
 		int start_trans;
 
 		start_trans = 1;
-		if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
-				dep->flags & DWC3_EP_BUSY)
+		if (usb_endpoint_xfer_isoc(dep->desc) &&
+				(dep->flags & DWC3_EP_BUSY))
 			start_trans = 0;
 
-		ret =  __dwc3_gadget_kick_transfer(dep, 0, start_trans);
+		ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans);
 		if (ret && ret != -EBUSY) {
 			struct dwc3	*dwc = dep->dwc;
 
@@ -1031,8 +1141,12 @@
 static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
 {
 	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+	unsigned long			flags;
 
+	spin_lock_irqsave(&dwc->lock, flags);
 	dep->flags |= DWC3_EP_WEDGE;
+	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return dwc3_gadget_ep_set_halt(ep, 1);
 }
@@ -1122,26 +1236,20 @@
 		goto out;
 	}
 
-	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
-
-	/*
-	 * Switch link state to Recovery. In HS/FS/LS this means
-	 * RemoteWakeup Request
-	 */
-	reg |= DWC3_DCTL_ULSTCHNG_RECOVERY;
-	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
-
-	/* wait for at least 2000us */
-	usleep_range(2000, 2500);
+	ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV);
+	if (ret < 0) {
+		dev_err(dwc->dev, "failed to put link in Recovery\n");
+		goto out;
+	}
 
 	/* write zeroes to Link Change Request */
 	reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
-	/* pool until Link State change to ON */
+	/* poll until Link State changes to ON */
 	timeout = jiffies + msecs_to_jiffies(100);
 
-	while (!(time_after(jiffies, timeout))) {
+	while (!time_after(jiffies, timeout)) {
 		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
 
 		/* in HS, means ON */
@@ -1164,8 +1272,11 @@
 		int is_selfpowered)
 {
 	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
 
+	spin_lock_irqsave(&dwc->lock, flags);
 	dwc->is_selfpowered = !!is_selfpowered;
+	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return 0;
 }
@@ -1176,10 +1287,13 @@
 	u32			timeout = 500;
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
-	if (is_on)
-		reg |= DWC3_DCTL_RUN_STOP;
-	else
+	if (is_on) {
+		reg &= ~DWC3_DCTL_TRGTULST_MASK;
+		reg |= (DWC3_DCTL_RUN_STOP
+				| DWC3_DCTL_TRGTULST_RX_DET);
+	} else {
 		reg &= ~DWC3_DCTL_RUN_STOP;
+	}
 
 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
@@ -1386,7 +1500,7 @@
 		const struct dwc3_event_depevt *event, int status)
 {
 	struct dwc3_request	*req;
-	struct dwc3_trb         trb;
+	struct dwc3_trb		*trb;
 	unsigned int		count;
 	unsigned int		s_pkt = 0;
 
@@ -1397,20 +1511,20 @@
 			return 1;
 		}
 
-		dwc3_trb_to_nat(req->trb, &trb);
+		trb = req->trb;
 
-		if (trb.hwo && status != -ESHUTDOWN)
+		if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
 			/*
 			 * We continue despite the error. There is not much we
-			 * can do. If we don't clean in up we loop for ever. If
-			 * we skip the TRB than it gets overwritten reused after
-			 * a while since we use them in a ring buffer. a BUG()
-			 * would help. Lets hope that if this occures, someone
+			 * can do. If we don't clean it up we loop forever. If
+			 * we skip the TRB then it gets overwritten after a
+			 * while since we use them in a ring buffer. A BUG()
+			 * would help. Lets hope that if this occurs, someone
 			 * fixes the root cause instead of looking away :)
 			 */
 			dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
 					dep->name, req->trb);
-		count = trb.length;
+		count = trb->size & DWC3_TRB_SIZE_MASK;
 
 		if (dep->direction) {
 			if (count) {
@@ -1434,13 +1548,16 @@
 		dwc3_gadget_giveback(dep, req, status);
 		if (s_pkt)
 			break;
-		if ((event->status & DEPEVT_STATUS_LST) && trb.lst)
+		if ((event->status & DEPEVT_STATUS_LST) &&
+				(trb->ctrl & DWC3_TRB_CTRL_LST))
 			break;
-		if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+		if ((event->status & DEPEVT_STATUS_IOC) &&
+				(trb->ctrl & DWC3_TRB_CTRL_IOC))
 			break;
 	} while (1);
 
-	if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+	if ((event->status & DEPEVT_STATUS_IOC) &&
+			(trb->ctrl & DWC3_TRB_CTRL_IOC))
 		return 0;
 	return 1;
 }
@@ -1455,11 +1572,9 @@
 	if (event->status & DEPEVT_STATUS_BUSERR)
 		status = -ECONNRESET;
 
-	clean_busy =  dwc3_cleanup_done_reqs(dwc, dep, event, status);
-	if (clean_busy) {
+	clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
+	if (clean_busy)
 		dep->flags &= ~DWC3_EP_BUSY;
-		dep->res_trans_idx = 0;
-	}
 
 	/*
 	 * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
@@ -1490,7 +1605,7 @@
 static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
 		struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
 {
-	u32 uf;
+	u32 uf, mask;
 
 	if (list_empty(&dep->request_list)) {
 		dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
@@ -1498,16 +1613,10 @@
 		return;
 	}
 
-	if (event->parameters) {
-		u32 mask;
-
-		mask = ~(dep->interval - 1);
-		uf = event->parameters & mask;
-		/* 4 micro frames in the future */
-		uf += dep->interval * 4;
-	} else {
-		uf = 0;
-	}
+	mask = ~(dep->interval - 1);
+	uf = event->parameters & mask;
+	/* 4 micro frames in the future */
+	uf += dep->interval * 4;
 
 	__dwc3_gadget_kick_transfer(dep, uf, 1);
 }
@@ -1519,8 +1628,8 @@
 	struct dwc3_event_depevt mod_ev = *event;
 
 	/*
-	 * We were asked to remove one requests. It is possible that this
-	 * request and a few other were started together and have the same
+	 * We were asked to remove one request. It is possible that this
+	 * request and a few others were started together and have the same
 	 * transfer index. Since we stopped the complete endpoint we don't
 	 * know how many requests were already completed (and not yet)
 	 * reported and how could be done (later). We purge them all until
@@ -1529,7 +1638,7 @@
 	mod_ev.status = DEPEVT_STATUS_LST;
 	dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN);
 	dep->flags &= ~DWC3_EP_BUSY;
-	/* pending requets are ignored and are queued on XferNotReady */
+	/* pending requests are ignored and are queued on XferNotReady */
 }
 
 static void dwc3_ep_cmd_compl(struct dwc3_ep *dep,
@@ -1570,6 +1679,8 @@
 
 	switch (event->endpoint_event) {
 	case DWC3_DEPEVT_XFERCOMPLETE:
+		dep->res_trans_idx = 0;
+
 		if (usb_endpoint_xfer_isoc(dep->desc)) {
 			dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
 					dep->name);
@@ -1594,7 +1705,8 @@
 			int ret;
 
 			dev_vdbg(dwc->dev, "%s: reason %s\n",
-					dep->name, event->status
+					dep->name, event->status &
+					DEPEVT_STATUS_TRANSFER_ACTIVE
 					? "Transfer Active"
 					: "Transfer Not Active");
 
@@ -1805,6 +1917,7 @@
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	reg &= ~DWC3_DCTL_TSTCTRL_MASK;
 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+	dwc->test_mode = false;
 
 	dwc3_stop_active_transfers(dwc);
 	dwc3_clear_stall_all_ep(dwc);
@@ -2082,7 +2195,8 @@
 	while (left > 0) {
 		union dwc3_event event;
 
-		memcpy(&event.raw, (evt->buf + evt->lpos), sizeof(event.raw));
+		event.raw = *(u32 *) (evt->buf + evt->lpos);
+
 		dwc3_process_event_entry(dwc, &event);
 		/*
 		 * XXX we wrap around correctly to the next entry as almost all
@@ -2123,7 +2237,7 @@
 
 /**
  * dwc3_gadget_init - Initializes gadget related registers
- * @dwc: Pointer to out controller context structure
+ * @dwc: pointer to our controller context structure
  *
  * Returns 0 on success otherwise negative errno.
  */
@@ -2149,9 +2263,8 @@
 		goto err1;
 	}
 
-	dwc->setup_buf = dma_alloc_coherent(dwc->dev,
-			sizeof(*dwc->setup_buf) * 2,
-			&dwc->setup_buf_addr, GFP_KERNEL);
+	dwc->setup_buf = kzalloc(sizeof(*dwc->setup_buf) * 2,
+			GFP_KERNEL);
 	if (!dwc->setup_buf) {
 		dev_err(dwc->dev, "failed to allocate setup buffer\n");
 		ret = -ENOMEM;
@@ -2242,8 +2355,7 @@
 			dwc->ep0_bounce_addr);
 
 err3:
-	dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
-			dwc->setup_buf, dwc->setup_buf_addr);
+	kfree(dwc->setup_buf);
 
 err2:
 	dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
@@ -2272,8 +2384,7 @@
 	dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
 			dwc->ep0_bounce_addr);
 
-	dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
-			dwc->setup_buf, dwc->setup_buf_addr);
+	kfree(dwc->setup_buf);
 
 	dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
 			dwc->ep0_trb, dwc->ep0_trb_addr);
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index d97f467..a860008 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -100,6 +100,9 @@
 void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
 		int status);
 
+int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
+int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
+
 void dwc3_ep0_interrupt(struct dwc3 *dwc,
 		const struct dwc3_event_depevt *event);
 void dwc3_ep0_out_start(struct dwc3 *dwc);
@@ -108,8 +111,6 @@
 int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
 int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
 		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
-void dwc3_map_buffer_to_dma(struct dwc3_request *req);
-void dwc3_unmap_buffer_from_dma(struct dwc3_request *req);
 
 /**
  * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index 7cfe211..b108d18 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -53,7 +53,7 @@
 	struct platform_device	*xhci;
 	int			ret;
 
-	xhci = platform_device_alloc("xhci", -1);
+	xhci = platform_device_alloc("xhci-hcd", -1);
 	if (!xhci) {
 		dev_err(dwc->dev, "couldn't allocate xHCI device\n");
 		ret = -ENOMEM;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 7ecb68a..c14a397 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -599,16 +599,29 @@
 	depends on SND
 	select SND_PCM
 	help
-	  Gadget Audio is compatible with USB Audio Class specification 1.0.
-	  It will include at least one AudioControl interface, zero or more
-	  AudioStream interface and zero or more MIDIStream interface.
-
-	  Gadget Audio will use on-board ALSA (CONFIG_SND) audio card to
-	  playback or capture audio stream.
+	  This Gadget Audio driver is compatible with USB Audio Class
+	  specification 2.0. It implements 1 AudioControl interface,
+	  1 AudioStreaming Interface each for USB-OUT and USB-IN.
+	  Number of channels, sample rate and sample size can be
+	  specified as module parameters.
+	  This driver doesn't expect any real Audio codec to be present
+	  on the device - the audio streams are simply sinked to and
+	  sourced from a virtual ALSA sound card created. The user-space
+	  application may choose to do whatever it wants with the data
+	  received from the USB Host and choose to provide whatever it
+	  wants as audio data to the USB Host.
 
 	  Say "y" to link the driver statically, or "m" to build a
 	  dynamically linked module called "g_audio".
 
+config GADGET_UAC1
+	bool "UAC 1.0 (Legacy)"
+	depends on USB_AUDIO
+	help
+	  If you instead want older UAC Spec-1.0 driver that also has audio
+	  paths hardwired to the Audio codec chip on-board and doesn't work
+	  without one.
+
 config USB_ETH
 	tristate "Ethernet Gadget (with CDC Ethernet support)"
 	depends on NET
@@ -685,7 +698,7 @@
 	help
 	  This driver implements USB CDC NCM subclass standard. NCM is
 	  an advanced protocol for Ethernet encapsulation, allows grouping
-	  of several ethernet frames into one USB transfer and diffferent
+	  of several ethernet frames into one USB transfer and different
 	  alignment possibilities.
 
 	  Say "y" to link the driver statically, or "m" to build a
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index c16ff55..2204a4c 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -29,7 +29,7 @@
 
 /* Driver strings */
 #define UDC_MOD_DESCRIPTION		"AMD 5536 UDC - USB Device Controller"
-#define UDC_DRIVER_VERSION_STRING	"01.00.0206 - $Revision: #3 $"
+#define UDC_DRIVER_VERSION_STRING	"01.00.0206"
 
 /* system */
 #include <linux/module.h>
@@ -140,7 +140,7 @@
 
 /* endpoint names used for print */
 static const char ep0_string[] = "ep0in";
-static const char *ep_string[] = {
+static const char *const ep_string[] = {
 	ep0_string,
 	"ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk",
 	"ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk",
@@ -204,9 +204,8 @@
 		DBG(dev, "DMA mode       = BF (buffer fill mode)\n");
 		dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF");
 	}
-	if (!use_dma) {
+	if (!use_dma)
 		dev_info(&dev->pdev->dev, "FIFO mode\n");
-	}
 	DBG(dev, "-------------------------------------------------------\n");
 }
 
@@ -445,6 +444,7 @@
 
 	VDBG(ep->dev, "ep-%d reset\n", ep->num);
 	ep->desc = NULL;
+	ep->ep.desc = NULL;
 	ep->ep.ops = &udc_ep_ops;
 	INIT_LIST_HEAD(&ep->queue);
 
@@ -569,9 +569,8 @@
 		VDBG(ep->dev, "req->td_data=%p\n", req->td_data);
 
 		/* free dma chain if created */
-		if (req->chain_len > 1) {
+		if (req->chain_len > 1)
 			udc_free_dma_chain(ep->dev, req);
-		}
 
 		pci_pool_free(ep->dev->data_requests, req->td_data,
 							req->td_phys);
@@ -639,9 +638,8 @@
 		bytes = remaining;
 
 	/* dwords first */
-	for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+	for (i = 0; i < bytes / UDC_DWORD_BYTES; i++)
 		writel(*(buf + i), ep->txfifo);
-	}
 
 	/* remaining bytes must be written by byte access */
 	for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
@@ -660,9 +658,8 @@
 
 	VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords);
 
-	for (i = 0; i < dwords; i++) {
+	for (i = 0; i < dwords; i++)
 		*(buf + i) = readl(dev->rxfifo);
-	}
 	return 0;
 }
 
@@ -675,9 +672,8 @@
 	VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes);
 
 	/* dwords first */
-	for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+	for (i = 0; i < bytes / UDC_DWORD_BYTES; i++)
 		*((u32 *)(buf + (i<<2))) = readl(dev->rxfifo);
-	}
 
 	/* remaining bytes must be read by byte access */
 	if (bytes % UDC_DWORD_BYTES) {
@@ -831,20 +827,8 @@
 
 	dev = ep->dev;
 	/* unmap DMA */
-	if (req->dma_mapping) {
-		if (ep->in)
-			pci_unmap_single(dev->pdev,
-					req->req.dma,
-					req->req.length,
-					PCI_DMA_TODEVICE);
-		else
-			pci_unmap_single(dev->pdev,
-					req->req.dma,
-					req->req.length,
-					PCI_DMA_FROMDEVICE);
-		req->dma_mapping = 0;
-		req->req.dma = DMA_DONT_USE;
-	}
+	if (ep->dma)
+		usb_gadget_unmap_request(&dev->gadget, &req->req, ep->in);
 
 	halted = ep->halted;
 	ep->halted = 1;
@@ -897,9 +881,8 @@
 	struct udc_data_dma	*td;
 
 	td = req->td_data;
-	while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+	while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L)))
 		td = phys_to_virt(td->next);
-	}
 
 	return td;
 
@@ -949,21 +932,18 @@
 	dma_addr = DMA_DONT_USE;
 
 	/* unset L bit in first desc for OUT */
-	if (!ep->in) {
+	if (!ep->in)
 		req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
-	}
 
 	/* alloc only new desc's if not already available */
 	len = req->req.length / ep->ep.maxpacket;
-	if (req->req.length % ep->ep.maxpacket) {
+	if (req->req.length % ep->ep.maxpacket)
 		len++;
-	}
 
 	if (len > req->chain_len) {
 		/* shorter chain already allocated before */
-		if (req->chain_len > 1) {
+		if (req->chain_len > 1)
 			udc_free_dma_chain(ep->dev, req);
-		}
 		req->chain_len = len;
 		create_new_chain = 1;
 	}
@@ -1006,11 +986,12 @@
 
 		/* link td and assign tx bytes */
 		if (i == buf_len) {
-			if (create_new_chain) {
+			if (create_new_chain)
 				req->td_data->next = dma_addr;
-			} else {
-				/* req->td_data->next = virt_to_phys(td); */
-			}
+			/*
+			else
+				req->td_data->next = virt_to_phys(td);
+			*/
 			/* write tx bytes */
 			if (ep->in) {
 				/* first desc */
@@ -1024,11 +1005,12 @@
 							UDC_DMA_IN_STS_TXBYTES);
 			}
 		} else {
-			if (create_new_chain) {
+			if (create_new_chain)
 				last->next = dma_addr;
-			} else {
-				/* last->next = virt_to_phys(td); */
-			}
+			/*
+			else
+				last->next = virt_to_phys(td);
+			*/
 			if (ep->in) {
 				/* write tx bytes */
 				td->status = AMD_ADDBITS(td->status,
@@ -1095,20 +1077,11 @@
 		return -ESHUTDOWN;
 
 	/* map dma (usually done before) */
-	if (ep->dma && usbreq->length != 0
-			&& (usbreq->dma == DMA_DONT_USE || usbreq->dma == 0)) {
+	if (ep->dma) {
 		VDBG(dev, "DMA map req %p\n", req);
-		if (ep->in)
-			usbreq->dma = pci_map_single(dev->pdev,
-						usbreq->buf,
-						usbreq->length,
-						PCI_DMA_TODEVICE);
-		else
-			usbreq->dma = pci_map_single(dev->pdev,
-						usbreq->buf,
-						usbreq->length,
-						PCI_DMA_FROMDEVICE);
-		req->dma_mapping = 1;
+		retval = usb_gadget_map_request(&udc->gadget, usbreq, ep->in);
+		if (retval)
+			return retval;
 	}
 
 	VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n",
@@ -1479,11 +1452,10 @@
 
 	/* program speed */
 	tmp = readl(&dev->regs->cfg);
-	if (use_fullspeed) {
+	if (use_fullspeed)
 		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
-	} else {
+	else
 		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
-	}
 	writel(tmp, &dev->regs->cfg);
 
 	return 0;
@@ -1504,9 +1476,8 @@
 		mod_timer(&udc_timer, jiffies - 1);
 	}
 	/* stop poll stall timer */
-	if (timer_pending(&udc_pollstall_timer)) {
+	if (timer_pending(&udc_pollstall_timer))
 		mod_timer(&udc_pollstall_timer, jiffies - 1);
-	}
 	/* disable DMA */
 	tmp = readl(&dev->regs->ctl);
 	tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
@@ -1540,11 +1511,10 @@
 	/* read enum speed */
 	tmp = readl(&dev->regs->sts);
 	tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED);
-	if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH) {
+	if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH)
 		dev->gadget.speed = USB_SPEED_HIGH;
-	} else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL) {
+	else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL)
 		dev->gadget.speed = USB_SPEED_FULL;
-	}
 
 	/* set basic ep parameters */
 	for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
@@ -1570,9 +1540,8 @@
 		 * disabling ep interrupts when ENUM interrupt occurs but ep is
 		 * not enabled by gadget driver
 		 */
-		if (!ep->desc) {
+		if (!ep->desc)
 			ep_init(dev->regs, ep);
-		}
 
 		if (use_dma) {
 			/*
@@ -1670,9 +1639,8 @@
 		spin_lock(&dev->lock);
 
 		/* empty queues */
-		for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+		for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
 			empty_req_queue(&dev->ep[tmp]);
-		}
 
 	}
 
@@ -1746,9 +1714,8 @@
 			 * open the fifo
 			 */
 			udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV;
-			if (!stop_timer) {
+			if (!stop_timer)
 				add_timer(&udc_timer);
-			}
 		} else {
 			/*
 			 * fifo contains data now, setup timer for opening
@@ -1760,9 +1727,8 @@
 			set_rde++;
 			/* debug: lhadmot_timer_start = 221070 */
 			udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS;
-			if (!stop_timer) {
+			if (!stop_timer)
 				add_timer(&udc_timer);
-			}
 		}
 
 	} else
@@ -1907,19 +1873,17 @@
 			mod_timer(&udc_timer, jiffies - 1);
 		}
 		/* stop pollstall timer */
-		if (timer_pending(&udc_pollstall_timer)) {
+		if (timer_pending(&udc_pollstall_timer))
 			mod_timer(&udc_pollstall_timer, jiffies - 1);
-		}
 		/* enable DMA */
 		tmp = readl(&dev->regs->ctl);
 		tmp |= AMD_BIT(UDC_DEVCTL_MODE)
 				| AMD_BIT(UDC_DEVCTL_RDE)
 				| AMD_BIT(UDC_DEVCTL_TDE);
-		if (use_dma_bufferfill_mode) {
+		if (use_dma_bufferfill_mode)
 			tmp |= AMD_BIT(UDC_DEVCTL_BF);
-		} else if (use_dma_ppb_du) {
+		else if (use_dma_ppb_du)
 			tmp |= AMD_BIT(UDC_DEVCTL_DU);
-		}
 		writel(tmp, &dev->regs->ctl);
 	}
 
@@ -2104,9 +2068,8 @@
 				udc_timer.expires =
 					jiffies + HZ/UDC_RDE_TIMER_DIV;
 				set_rde = 1;
-				if (!stop_timer) {
+				if (!stop_timer)
 					add_timer(&udc_timer);
-				}
 			}
 		}
 	}
@@ -2131,7 +2094,7 @@
 	if (use_dma) {
 		/* BNA event ? */
 		if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
-			DBG(dev, "BNA ep%dout occurred - DESPTR = %x \n",
+			DBG(dev, "BNA ep%dout occurred - DESPTR = %x\n",
 					ep->num, readl(&ep->regs->desptr));
 			/* clear BNA */
 			writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts);
@@ -2294,9 +2257,8 @@
 						jiffies
 						+ HZ*UDC_RDE_TIMER_SECONDS;
 					set_rde = 1;
-					if (!stop_timer) {
+					if (!stop_timer)
 						add_timer(&udc_timer);
-					}
 				}
 				if (ep->num != UDC_EP0OUT_IX)
 					dev->data_ep_queued = 0;
@@ -2318,9 +2280,8 @@
 	/* check pending CNAKS */
 	if (cnak_pending) {
 		/* CNAk processing when rxfifo empty only */
-		if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+		if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
 			udc_process_cnak_queue(dev);
-		}
 	}
 
 	/* clear OUT bits in ep status */
@@ -2348,7 +2309,7 @@
 		/* BNA ? */
 		if (epsts & AMD_BIT(UDC_EPSTS_BNA)) {
 			dev_err(&dev->pdev->dev,
-				"BNA ep%din occurred - DESPTR = %08lx \n",
+				"BNA ep%din occurred - DESPTR = %08lx\n",
 				ep->num,
 				(unsigned long) readl(&ep->regs->desptr));
 
@@ -2361,7 +2322,7 @@
 	/* HE event ? */
 	if (epsts & AMD_BIT(UDC_EPSTS_HE)) {
 		dev_err(&dev->pdev->dev,
-			"HE ep%dn occurred - DESPTR = %08lx \n",
+			"HE ep%dn occurred - DESPTR = %08lx\n",
 			ep->num, (unsigned long) readl(&ep->regs->desptr));
 
 		/* clear HE */
@@ -2427,9 +2388,9 @@
 				/* write fifo */
 				udc_txfifo_write(ep, &req->req);
 				len = req->req.length - req->req.actual;
-						if (len > ep->ep.maxpacket)
-							len = ep->ep.maxpacket;
-						req->req.actual += len;
+				if (len > ep->ep.maxpacket)
+					len = ep->ep.maxpacket;
+				req->req.actual += len;
 				if (req->req.actual == req->req.length
 					|| (len != ep->ep.maxpacket)) {
 					/* complete req */
@@ -2581,9 +2542,8 @@
 			if (!timer_pending(&udc_timer)) {
 				udc_timer.expires = jiffies +
 							HZ/UDC_RDE_TIMER_DIV;
-				if (!stop_timer) {
+				if (!stop_timer)
 					add_timer(&udc_timer);
-				}
 			}
 		}
 
@@ -2697,9 +2657,8 @@
 	/* check pending CNAKS */
 	if (cnak_pending) {
 		/* CNAk processing when rxfifo empty only */
-		if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+		if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
 			udc_process_cnak_queue(dev);
-		}
 	}
 
 finished:
@@ -2723,7 +2682,7 @@
 	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts);
 	/* DMA completion */
 	if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
-		VDBG(dev, "isr: TDC clear \n");
+		VDBG(dev, "isr: TDC clear\n");
 		ret_val = IRQ_HANDLED;
 
 		/* clear TDC bit */
@@ -3426,7 +3385,7 @@
 }
 
 /* PCI device parameters */
-static const struct pci_device_id pci_id[] = {
+static DEFINE_PCI_DEVICE_TABLE(pci_id) = {
 	{
 		PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
 		.class =	(PCI_CLASS_SERIAL_USB << 8) | 0xfe,
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 143a725..15a8cdb 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -29,7 +29,6 @@
 #include <linux/clk.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
-#include <linux/prefetch.h>
 
 #include <asm/byteorder.h>
 #include <mach/hardware.h>
@@ -558,6 +557,7 @@
 
 	/* restore the endpoint's pristine config */
 	ep->desc = NULL;
+	ep->ep.desc = NULL;
 	ep->ep.maxpacket = ep->maxpacket;
 
 	/* reset fifos and endpoint */
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index e2fb6d5..5e10f65 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -659,6 +659,7 @@
 		return -EINVAL;
 	}
 	ep->desc = NULL;
+	ep->ep.desc = NULL;
 
 	list_splice_init(&ep->queue, &req_list);
 	if (ep->can_dma) {
diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c
index 9d89ae47..9889924 100644
--- a/drivers/usb/gadget/audio.c
+++ b/drivers/usb/gadget/audio.c
@@ -14,10 +14,8 @@
 #include <linux/kernel.h>
 #include <linux/utsname.h>
 
-#include "u_audio.h"
-
 #define DRIVER_DESC		"Linux USB Audio Gadget"
-#define DRIVER_VERSION		"Dec 18, 2008"
+#define DRIVER_VERSION		"Feb 2, 2012"
 
 /*-------------------------------------------------------------------------*/
 
@@ -33,8 +31,36 @@
 #include "config.c"
 #include "epautoconf.c"
 
-#include "u_audio.c"
-#include "f_audio.c"
+/* string IDs are assigned dynamically */
+
+#define STRING_MANUFACTURER_IDX		0
+#define STRING_PRODUCT_IDX		1
+
+static char manufacturer[50];
+
+static struct usb_string strings_dev[] = {
+	[STRING_MANUFACTURER_IDX].s = manufacturer,
+	[STRING_PRODUCT_IDX].s = DRIVER_DESC,
+	{  } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+	.language = 0x0409,	/* en-us */
+	.strings = strings_dev,
+};
+
+static struct usb_gadget_strings *audio_strings[] = {
+	&stringtab_dev,
+	NULL,
+};
+
+#ifdef CONFIG_GADGET_UAC1
+#include "u_uac1.h"
+#include "u_uac1.c"
+#include "f_uac1.c"
+#else
+#include "f_uac2.c"
+#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -54,9 +80,15 @@
 
 	.bcdUSB =		__constant_cpu_to_le16(0x200),
 
+#ifdef CONFIG_GADGET_UAC1
 	.bDeviceClass =		USB_CLASS_PER_INTERFACE,
 	.bDeviceSubClass =	0,
 	.bDeviceProtocol =	0,
+#else
+	.bDeviceClass =		USB_CLASS_MISC,
+	.bDeviceSubClass =	0x02,
+	.bDeviceProtocol =	0x01,
+#endif
 	/* .bMaxPacketSize0 = f(hardware) */
 
 	/* Vendor and product id defaults change according to what configs
@@ -108,6 +140,9 @@
 	.bConfigurationValue	= 1,
 	/* .iConfiguration = DYNAMIC */
 	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
+#ifndef CONFIG_GADGET_UAC1
+	.unbind			= uac2_unbind_config,
+#endif
 };
 
 /*-------------------------------------------------------------------------*/
@@ -157,7 +192,9 @@
 
 static int __exit audio_unbind(struct usb_composite_dev *cdev)
 {
+#ifdef CONFIG_GADGET_UAC1
 	gaudio_cleanup();
+#endif
 	return 0;
 }
 
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 1fc6129..d07e44c 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -37,10 +37,10 @@
 		 * Put the transceiver in non-driving mode. Otherwise host
 		 * may not detect soft-disconnection.
 		 */
-		val = otg_io_read(udc->transceiver, ULPI_FUNC_CTRL);
+		val = usb_phy_io_read(udc->transceiver, ULPI_FUNC_CTRL);
 		val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
 		val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
-		otg_io_write(udc->transceiver, val, ULPI_FUNC_CTRL);
+		usb_phy_io_write(udc->transceiver, val, ULPI_FUNC_CTRL);
 		break;
 	default:
 		dev_dbg(dev, "unknown ci13xxx_udc event\n");
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 27e3137..243ef1a 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2181,6 +2181,7 @@
 	} while (mEp->dir != direction);
 
 	mEp->desc = NULL;
+	mEp->ep.desc = NULL;
 
 	spin_unlock_irqrestore(mEp->lock, flags);
 	return retval;
@@ -2537,7 +2538,7 @@
 	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
 
 	if (udc->transceiver)
-		return otg_set_power(udc->transceiver, mA);
+		return usb_phy_set_power(udc->transceiver, mA);
 	return -ENOTSUPP;
 }
 
@@ -2900,7 +2901,7 @@
 	if (retval < 0)
 		goto free_udc;
 
-	udc->transceiver = otg_get_transceiver();
+	udc->transceiver = usb_get_transceiver();
 
 	if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
 		if (udc->transceiver == NULL) {
@@ -2928,7 +2929,8 @@
 		goto unreg_device;
 
 	if (udc->transceiver) {
-		retval = otg_set_peripheral(udc->transceiver, &udc->gadget);
+		retval = otg_set_peripheral(udc->transceiver->otg,
+						&udc->gadget);
 		if (retval)
 			goto remove_dbg;
 	}
@@ -2945,8 +2947,8 @@
 
 remove_trans:
 	if (udc->transceiver) {
-		otg_set_peripheral(udc->transceiver, &udc->gadget);
-		otg_put_transceiver(udc->transceiver);
+		otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
+		usb_put_transceiver(udc->transceiver);
 	}
 
 	err("error = %i", retval);
@@ -2958,7 +2960,7 @@
 	device_unregister(&udc->gadget.dev);
 put_transceiver:
 	if (udc->transceiver)
-		otg_put_transceiver(udc->transceiver);
+		usb_put_transceiver(udc->transceiver);
 free_udc:
 	kfree(udc);
 	_udc = NULL;
@@ -2981,8 +2983,8 @@
 	usb_del_gadget_udc(&udc->gadget);
 
 	if (udc->transceiver) {
-		otg_set_peripheral(udc->transceiver, &udc->gadget);
-		otg_put_transceiver(udc->transceiver);
+		otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
+		usb_put_transceiver(udc->transceiver);
 	}
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
 	dbg_remove_files(&udc->gadget.dev);
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index f4871e1..0d31af5 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -136,7 +136,7 @@
 	struct usb_gadget_driver  *driver;     /* 3rd party gadget driver */
 	struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
 	int                        vbus_active; /* is VBUS active */
-	struct otg_transceiver    *transceiver; /* Transceiver struct */
+	struct usb_phy            *transceiver; /* Transceiver struct */
 };
 
 /******************************************************************************
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index db815c2..e1cd56c 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -39,27 +39,27 @@
 #include <linux/usb.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/hcd.h>
+#include <linux/scatterlist.h>
 
 #include <asm/byteorder.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/unaligned.h>
 
-
 #define DRIVER_DESC	"USB Host+Gadget Emulator"
 #define DRIVER_VERSION	"02 May 2005"
 
 #define POWER_BUDGET	500	/* in mA; use 8 for low-power port testing */
 
-static const char	driver_name [] = "dummy_hcd";
-static const char	driver_desc [] = "USB Host+Gadget Emulator";
+static const char	driver_name[] = "dummy_hcd";
+static const char	driver_desc[] = "USB Host+Gadget Emulator";
 
-static const char	gadget_name [] = "dummy_udc";
+static const char	gadget_name[] = "dummy_udc";
 
-MODULE_DESCRIPTION (DRIVER_DESC);
-MODULE_AUTHOR ("David Brownell");
-MODULE_LICENSE ("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
 
 struct dummy_hcd_module_parameters {
 	bool is_super_speed;
@@ -83,10 +83,11 @@
 	struct usb_gadget		*gadget;
 	const struct usb_endpoint_descriptor *desc;
 	struct usb_ep			ep;
-	unsigned			halted : 1;
-	unsigned			wedged : 1;
-	unsigned			already_seen : 1;
-	unsigned			setup_stage : 1;
+	unsigned			halted:1;
+	unsigned			wedged:1;
+	unsigned			already_seen:1;
+	unsigned			setup_stage:1;
+	unsigned			stream_en:1;
 };
 
 struct dummy_request {
@@ -94,15 +95,15 @@
 	struct usb_request		req;
 };
 
-static inline struct dummy_ep *usb_ep_to_dummy_ep (struct usb_ep *_ep)
+static inline struct dummy_ep *usb_ep_to_dummy_ep(struct usb_ep *_ep)
 {
-	return container_of (_ep, struct dummy_ep, ep);
+	return container_of(_ep, struct dummy_ep, ep);
 }
 
 static inline struct dummy_request *usb_request_to_dummy_request
 		(struct usb_request *_req)
 {
-	return container_of (_req, struct dummy_request, req);
+	return container_of(_req, struct dummy_request, req);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -121,9 +122,9 @@
  * configurations, illegal or unsupported packet lengths, and so on.
  */
 
-static const char ep0name [] = "ep0";
+static const char ep0name[] = "ep0";
 
-static const char *const ep_name [] = {
+static const char *const ep_name[] = {
 	ep0name,				/* everyone has ep0 */
 
 	/* act like a net2280: high speed, six configurable endpoints */
@@ -147,6 +148,8 @@
 struct urbp {
 	struct urb		*urb;
 	struct list_head	urbp_list;
+	struct sg_mapping_iter	miter;
+	u32			miter_started;
 };
 
 
@@ -166,6 +169,8 @@
 
 	struct usb_device		*udev;
 	struct list_head		urbp_list;
+	u32				stream_en_ep;
+	u8				num_stream[30 / 2];
 
 	unsigned			active:1;
 	unsigned			old_active:1;
@@ -178,12 +183,12 @@
 	/*
 	 * SLAVE/GADGET side support
 	 */
-	struct dummy_ep			ep [DUMMY_ENDPOINTS];
+	struct dummy_ep			ep[DUMMY_ENDPOINTS];
 	int				address;
 	struct usb_gadget		gadget;
 	struct usb_gadget_driver	*driver;
 	struct dummy_request		fifo_req;
-	u8				fifo_buf [FIFO_SIZE];
+	u8				fifo_buf[FIFO_SIZE];
 	u16				devstatus;
 	unsigned			udc_suspended:1;
 	unsigned			pullup:1;
@@ -210,14 +215,14 @@
 	return dummy_hcd_to_hcd(dum)->self.controller;
 }
 
-static inline struct device *udc_dev (struct dummy *dum)
+static inline struct device *udc_dev(struct dummy *dum)
 {
 	return dum->gadget.dev.parent;
 }
 
-static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
+static inline struct dummy *ep_to_dummy(struct dummy_ep *ep)
 {
-	return container_of (ep->gadget, struct dummy, gadget);
+	return container_of(ep->gadget, struct dummy, gadget);
 }
 
 static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
@@ -229,9 +234,9 @@
 		return dum->hs_hcd;
 }
 
-static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
+static inline struct dummy *gadget_dev_to_dummy(struct device *dev)
 {
-	return container_of (dev, struct dummy, gadget.dev);
+	return container_of(dev, struct dummy, gadget.dev);
 }
 
 static struct dummy			the_controller;
@@ -241,24 +246,23 @@
 /* SLAVE/GADGET SIDE UTILITY ROUTINES */
 
 /* called with spinlock held */
-static void nuke (struct dummy *dum, struct dummy_ep *ep)
+static void nuke(struct dummy *dum, struct dummy_ep *ep)
 {
-	while (!list_empty (&ep->queue)) {
+	while (!list_empty(&ep->queue)) {
 		struct dummy_request	*req;
 
-		req = list_entry (ep->queue.next, struct dummy_request, queue);
-		list_del_init (&req->queue);
+		req = list_entry(ep->queue.next, struct dummy_request, queue);
+		list_del_init(&req->queue);
 		req->req.status = -ESHUTDOWN;
 
-		spin_unlock (&dum->lock);
-		req->req.complete (&ep->ep, &req->req);
-		spin_lock (&dum->lock);
+		spin_unlock(&dum->lock);
+		req->req.complete(&ep->ep, &req->req);
+		spin_lock(&dum->lock);
 	}
 }
 
 /* caller must hold lock */
-static void
-stop_activity (struct dummy *dum)
+static void stop_activity(struct dummy *dum)
 {
 	struct dummy_ep	*ep;
 
@@ -268,8 +272,8 @@
 	/* The timer is left running so that outstanding URBs can fail */
 
 	/* nuke any pending requests first, so driver i/o is quiesced */
-	list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
-		nuke (dum, ep);
+	list_for_each_entry(ep, &dum->gadget.ep_list, ep.ep_list)
+		nuke(dum, ep);
 
 	/* driver now does any non-usb quiescing necessary */
 }
@@ -404,8 +408,8 @@
 #define is_enabled(dum) \
 	(dum->port_status & USB_PORT_STAT_ENABLE)
 
-static int
-dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+static int dummy_enable(struct usb_ep *_ep,
+		const struct usb_endpoint_descriptor *desc)
 {
 	struct dummy		*dum;
 	struct dummy_hcd	*dum_hcd;
@@ -413,11 +417,11 @@
 	unsigned		max;
 	int			retval;
 
-	ep = usb_ep_to_dummy_ep (_ep);
+	ep = usb_ep_to_dummy_ep(_ep);
 	if (!_ep || !desc || ep->desc || _ep->name == ep0name
 			|| desc->bDescriptorType != USB_DT_ENDPOINT)
 		return -EINVAL;
-	dum = ep_to_dummy (ep);
+	dum = ep_to_dummy(ep);
 	if (!dum->driver)
 		return -ESHUTDOWN;
 
@@ -441,10 +445,10 @@
 	 * especially for "ep9out" style fixed function ones.)
 	 */
 	retval = -EINVAL;
-	switch (desc->bmAttributes & 0x03) {
+	switch (usb_endpoint_type(desc)) {
 	case USB_ENDPOINT_XFER_BULK:
-		if (strstr (ep->ep.name, "-iso")
-				|| strstr (ep->ep.name, "-int")) {
+		if (strstr(ep->ep.name, "-iso")
+				|| strstr(ep->ep.name, "-int")) {
 			goto done;
 		}
 		switch (dum->gadget.speed) {
@@ -466,7 +470,7 @@
 		}
 		break;
 	case USB_ENDPOINT_XFER_INT:
-		if (strstr (ep->ep.name, "-iso")) /* bulk is ok */
+		if (strstr(ep->ep.name, "-iso")) /* bulk is ok */
 			goto done;
 		/* real hardware might not handle all packet sizes */
 		switch (dum->gadget.speed) {
@@ -486,8 +490,8 @@
 		}
 		break;
 	case USB_ENDPOINT_XFER_ISOC:
-		if (strstr (ep->ep.name, "-bulk")
-				|| strstr (ep->ep.name, "-int"))
+		if (strstr(ep->ep.name, "-bulk")
+				|| strstr(ep->ep.name, "-int"))
 			goto done;
 		/* real hardware might not handle all packet sizes */
 		switch (dum->gadget.speed) {
@@ -510,14 +514,22 @@
 	}
 
 	_ep->maxpacket = max;
+	if (usb_ss_max_streams(_ep->comp_desc)) {
+		if (!usb_endpoint_xfer_bulk(desc)) {
+			dev_err(udc_dev(dum), "Can't enable stream support on "
+					"non-bulk ep %s\n", _ep->name);
+			return -EINVAL;
+		}
+		ep->stream_en = 1;
+	}
 	ep->desc = desc;
 
-	dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
+	dev_dbg(udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d stream %s\n",
 		_ep->name,
 		desc->bEndpointAddress & 0x0f,
 		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
 		({ char *val;
-		 switch (desc->bmAttributes & 0x03) {
+		 switch (usb_endpoint_type(desc)) {
 		 case USB_ENDPOINT_XFER_BULK:
 			 val = "bulk";
 			 break;
@@ -531,7 +543,7 @@
 			 val = "ctrl";
 			 break;
 		 }; val; }),
-		max);
+		max, ep->stream_en ? "enabled" : "disabled");
 
 	/* at this point real hardware should be NAKing transfers
 	 * to that endpoint, until a buffer is queued to it.
@@ -542,67 +554,67 @@
 	return retval;
 }
 
-static int dummy_disable (struct usb_ep *_ep)
+static int dummy_disable(struct usb_ep *_ep)
 {
 	struct dummy_ep		*ep;
 	struct dummy		*dum;
 	unsigned long		flags;
 	int			retval;
 
-	ep = usb_ep_to_dummy_ep (_ep);
+	ep = usb_ep_to_dummy_ep(_ep);
 	if (!_ep || !ep->desc || _ep->name == ep0name)
 		return -EINVAL;
-	dum = ep_to_dummy (ep);
+	dum = ep_to_dummy(ep);
 
-	spin_lock_irqsave (&dum->lock, flags);
+	spin_lock_irqsave(&dum->lock, flags);
 	ep->desc = NULL;
+	ep->stream_en = 0;
 	retval = 0;
-	nuke (dum, ep);
-	spin_unlock_irqrestore (&dum->lock, flags);
+	nuke(dum, ep);
+	spin_unlock_irqrestore(&dum->lock, flags);
 
-	dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name);
+	dev_dbg(udc_dev(dum), "disabled %s\n", _ep->name);
 	return retval;
 }
 
-static struct usb_request *
-dummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags)
+static struct usb_request *dummy_alloc_request(struct usb_ep *_ep,
+		gfp_t mem_flags)
 {
 	struct dummy_ep		*ep;
 	struct dummy_request	*req;
 
 	if (!_ep)
 		return NULL;
-	ep = usb_ep_to_dummy_ep (_ep);
+	ep = usb_ep_to_dummy_ep(_ep);
 
 	req = kzalloc(sizeof(*req), mem_flags);
 	if (!req)
 		return NULL;
-	INIT_LIST_HEAD (&req->queue);
+	INIT_LIST_HEAD(&req->queue);
 	return &req->req;
 }
 
-static void
-dummy_free_request (struct usb_ep *_ep, struct usb_request *_req)
+static void dummy_free_request(struct usb_ep *_ep, struct usb_request *_req)
 {
 	struct dummy_ep		*ep;
 	struct dummy_request	*req;
 
-	ep = usb_ep_to_dummy_ep (_ep);
-	if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
+	if (!_ep || !_req)
+		return;
+	ep = usb_ep_to_dummy_ep(_ep);
+	if (!ep->desc && _ep->name != ep0name)
 		return;
 
-	req = usb_request_to_dummy_request (_req);
-	WARN_ON (!list_empty (&req->queue));
-	kfree (req);
+	req = usb_request_to_dummy_request(_req);
+	WARN_ON(!list_empty(&req->queue));
+	kfree(req);
 }
 
-static void
-fifo_complete (struct usb_ep *ep, struct usb_request *req)
+static void fifo_complete(struct usb_ep *ep, struct usb_request *req)
 {
 }
 
-static int
-dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
+static int dummy_queue(struct usb_ep *_ep, struct usb_request *_req,
 		gfp_t mem_flags)
 {
 	struct dummy_ep		*ep;
@@ -611,49 +623,48 @@
 	struct dummy_hcd	*dum_hcd;
 	unsigned long		flags;
 
-	req = usb_request_to_dummy_request (_req);
-	if (!_req || !list_empty (&req->queue) || !_req->complete)
+	req = usb_request_to_dummy_request(_req);
+	if (!_req || !list_empty(&req->queue) || !_req->complete)
 		return -EINVAL;
 
-	ep = usb_ep_to_dummy_ep (_ep);
+	ep = usb_ep_to_dummy_ep(_ep);
 	if (!_ep || (!ep->desc && _ep->name != ep0name))
 		return -EINVAL;
 
-	dum = ep_to_dummy (ep);
+	dum = ep_to_dummy(ep);
 	dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
 	if (!dum->driver || !is_enabled(dum_hcd))
 		return -ESHUTDOWN;
 
 #if 0
-	dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
+	dev_dbg(udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
 			ep, _req, _ep->name, _req->length, _req->buf);
 #endif
-
 	_req->status = -EINPROGRESS;
 	_req->actual = 0;
-	spin_lock_irqsave (&dum->lock, flags);
+	spin_lock_irqsave(&dum->lock, flags);
 
 	/* implement an emulated single-request FIFO */
 	if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
-			list_empty (&dum->fifo_req.queue) &&
-			list_empty (&ep->queue) &&
+			list_empty(&dum->fifo_req.queue) &&
+			list_empty(&ep->queue) &&
 			_req->length <= FIFO_SIZE) {
 		req = &dum->fifo_req;
 		req->req = *_req;
 		req->req.buf = dum->fifo_buf;
-		memcpy (dum->fifo_buf, _req->buf, _req->length);
+		memcpy(dum->fifo_buf, _req->buf, _req->length);
 		req->req.context = dum;
 		req->req.complete = fifo_complete;
 
 		list_add_tail(&req->queue, &ep->queue);
-		spin_unlock (&dum->lock);
+		spin_unlock(&dum->lock);
 		_req->actual = _req->length;
 		_req->status = 0;
-		_req->complete (_ep, _req);
-		spin_lock (&dum->lock);
+		_req->complete(_ep, _req);
+		spin_lock(&dum->lock);
 	}  else
 		list_add_tail(&req->queue, &ep->queue);
-	spin_unlock_irqrestore (&dum->lock, flags);
+	spin_unlock_irqrestore(&dum->lock, flags);
 
 	/* real hardware would likely enable transfers here, in case
 	 * it'd been left NAKing.
@@ -661,7 +672,7 @@
 	return 0;
 }
 
-static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
+static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req)
 {
 	struct dummy_ep		*ep;
 	struct dummy		*dum;
@@ -671,31 +682,31 @@
 
 	if (!_ep || !_req)
 		return retval;
-	ep = usb_ep_to_dummy_ep (_ep);
-	dum = ep_to_dummy (ep);
+	ep = usb_ep_to_dummy_ep(_ep);
+	dum = ep_to_dummy(ep);
 
 	if (!dum->driver)
 		return -ESHUTDOWN;
 
-	local_irq_save (flags);
-	spin_lock (&dum->lock);
-	list_for_each_entry (req, &ep->queue, queue) {
+	local_irq_save(flags);
+	spin_lock(&dum->lock);
+	list_for_each_entry(req, &ep->queue, queue) {
 		if (&req->req == _req) {
-			list_del_init (&req->queue);
+			list_del_init(&req->queue);
 			_req->status = -ECONNRESET;
 			retval = 0;
 			break;
 		}
 	}
-	spin_unlock (&dum->lock);
+	spin_unlock(&dum->lock);
 
 	if (retval == 0) {
-		dev_dbg (udc_dev(dum),
+		dev_dbg(udc_dev(dum),
 				"dequeued req %p from %s, len %d buf %p\n",
 				req, _ep->name, _req->length, _req->buf);
-		_req->complete (_ep, _req);
+		_req->complete(_ep, _req);
 	}
-	local_irq_restore (flags);
+	local_irq_restore(flags);
 	return retval;
 }
 
@@ -707,14 +718,14 @@
 
 	if (!_ep)
 		return -EINVAL;
-	ep = usb_ep_to_dummy_ep (_ep);
-	dum = ep_to_dummy (ep);
+	ep = usb_ep_to_dummy_ep(_ep);
+	dum = ep_to_dummy(ep);
 	if (!dum->driver)
 		return -ESHUTDOWN;
 	if (!value)
 		ep->halted = ep->wedged = 0;
 	else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
-			!list_empty (&ep->queue))
+			!list_empty(&ep->queue))
 		return -EAGAIN;
 	else {
 		ep->halted = 1;
@@ -755,15 +766,15 @@
 /*-------------------------------------------------------------------------*/
 
 /* there are both host and device side versions of this call ... */
-static int dummy_g_get_frame (struct usb_gadget *_gadget)
+static int dummy_g_get_frame(struct usb_gadget *_gadget)
 {
 	struct timeval	tv;
 
-	do_gettimeofday (&tv);
+	do_gettimeofday(&tv);
 	return tv.tv_usec / 1000;
 }
 
-static int dummy_wakeup (struct usb_gadget *_gadget)
+static int dummy_wakeup(struct usb_gadget *_gadget)
 {
 	struct dummy_hcd *dum_hcd;
 
@@ -786,11 +797,11 @@
 	return 0;
 }
 
-static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
+static int dummy_set_selfpowered(struct usb_gadget *_gadget, int value)
 {
 	struct dummy	*dum;
 
-	dum = (gadget_to_dummy_hcd(_gadget))->dum;
+	dum = gadget_to_dummy_hcd(_gadget)->dum;
 	if (value)
 		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
 	else
@@ -798,22 +809,15 @@
 	return 0;
 }
 
-static void dummy_udc_udpate_ep0(struct dummy *dum)
+static void dummy_udc_update_ep0(struct dummy *dum)
 {
-	u32 i;
-
-	if (dum->gadget.speed == USB_SPEED_SUPER) {
-		for (i = 0; i < DUMMY_ENDPOINTS; i++)
-			dum->ep[i].ep.max_streams = 0x10;
+	if (dum->gadget.speed == USB_SPEED_SUPER)
 		dum->ep[0].ep.maxpacket = 9;
-	} else {
-		for (i = 0; i < DUMMY_ENDPOINTS; i++)
-			dum->ep[i].ep.max_streams = 0;
+	else
 		dum->ep[0].ep.maxpacket = 64;
-	}
 }
 
-static int dummy_pullup (struct usb_gadget *_gadget, int value)
+static int dummy_pullup(struct usb_gadget *_gadget, int value)
 {
 	struct dummy_hcd *dum_hcd;
 	struct dummy	*dum;
@@ -829,7 +833,7 @@
 					dum->driver->max_speed);
 		else
 			dum->gadget.speed = USB_SPEED_FULL;
-		dummy_udc_udpate_ep0(dum);
+		dummy_udc_update_ep0(dum);
 
 		if (dum->gadget.speed < dum->driver->max_speed)
 			dev_dbg(udc_dev(dum), "This device can perform faster"
@@ -838,10 +842,10 @@
 	}
 	dum_hcd = gadget_to_dummy_hcd(_gadget);
 
-	spin_lock_irqsave (&dum->lock, flags);
+	spin_lock_irqsave(&dum->lock, flags);
 	dum->pullup = (value != 0);
 	set_link_state(dum_hcd);
-	spin_unlock_irqrestore (&dum->lock, flags);
+	spin_unlock_irqrestore(&dum->lock, flags);
 
 	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
 	return 0;
@@ -864,16 +868,16 @@
 /*-------------------------------------------------------------------------*/
 
 /* "function" sysfs attribute */
-static ssize_t
-show_function (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_function(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
-	struct dummy	*dum = gadget_dev_to_dummy (dev);
+	struct dummy	*dum = gadget_dev_to_dummy(dev);
 
 	if (!dum->driver || !dum->driver->function)
 		return 0;
-	return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function);
+	return scnprintf(buf, PAGE_SIZE, "%s\n", dum->driver->function);
 }
-static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
+static DEVICE_ATTR(function, S_IRUGO, show_function, NULL);
 
 /*-------------------------------------------------------------------------*/
 
@@ -908,7 +912,7 @@
 	dum->devstatus = 0;
 
 	dum->driver = driver;
-	dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
+	dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n",
 			driver->driver.name);
 	return 0;
 }
@@ -919,7 +923,7 @@
 	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);
 	struct dummy		*dum = dum_hcd->dum;
 
-	dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
+	dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n",
 			driver->driver.name);
 
 	dum->driver = NULL;
@@ -932,8 +936,7 @@
 
 /* The gadget structure is stored inside the hcd structure and will be
  * released along with it. */
-static void
-dummy_gadget_release (struct device *dev)
+static void dummy_gadget_release(struct device *dev)
 {
 	return;
 }
@@ -954,6 +957,7 @@
 		ep->halted = ep->wedged = ep->already_seen =
 				ep->setup_stage = 0;
 		ep->ep.maxpacket = ~0;
+		ep->ep.max_streams = 16;
 		ep->last_io = jiffies;
 		ep->gadget = &dum->gadget;
 		ep->desc = NULL;
@@ -969,7 +973,7 @@
 #endif
 }
 
-static int dummy_udc_probe (struct platform_device *pdev)
+static int dummy_udc_probe(struct platform_device *pdev)
 {
 	struct dummy	*dum = &the_controller;
 	int		rc;
@@ -981,7 +985,7 @@
 	dev_set_name(&dum->gadget.dev, "gadget");
 	dum->gadget.dev.parent = &pdev->dev;
 	dum->gadget.dev.release = dummy_gadget_release;
-	rc = device_register (&dum->gadget.dev);
+	rc = device_register(&dum->gadget.dev);
 	if (rc < 0) {
 		put_device(&dum->gadget.dev);
 		return rc;
@@ -993,7 +997,7 @@
 	if (rc < 0)
 		goto err_udc;
 
-	rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
+	rc = device_create_file(&dum->gadget.dev, &dev_attr_function);
 	if (rc < 0)
 		goto err_dev;
 	platform_set_drvdata(pdev, dum);
@@ -1006,14 +1010,14 @@
 	return rc;
 }
 
-static int dummy_udc_remove (struct platform_device *pdev)
+static int dummy_udc_remove(struct platform_device *pdev)
 {
-	struct dummy	*dum = platform_get_drvdata (pdev);
+	struct dummy	*dum = platform_get_drvdata(pdev);
 
 	usb_del_gadget_udc(&dum->gadget);
-	platform_set_drvdata (pdev, NULL);
-	device_remove_file (&dum->gadget.dev, &dev_attr_function);
-	device_unregister (&dum->gadget.dev);
+	platform_set_drvdata(pdev, NULL);
+	device_remove_file(&dum->gadget.dev, &dev_attr_function);
+	device_unregister(&dum->gadget.dev);
 	return 0;
 }
 
@@ -1061,6 +1065,16 @@
 
 /*-------------------------------------------------------------------------*/
 
+static unsigned int dummy_get_ep_idx(const struct usb_endpoint_descriptor *desc)
+{
+	unsigned int index;
+
+	index = usb_endpoint_num(desc) << 1;
+	if (usb_endpoint_dir_in(desc))
+		index |= 1;
+	return index;
+}
+
 /* MASTER/HOST SIDE DRIVER
  *
  * this uses the hcd framework to hook up to host side drivers.
@@ -1073,7 +1087,82 @@
  * usb 2.0 rules.
  */
 
-static int dummy_urb_enqueue (
+static int dummy_ep_stream_en(struct dummy_hcd *dum_hcd, struct urb *urb)
+{
+	const struct usb_endpoint_descriptor *desc = &urb->ep->desc;
+	u32 index;
+
+	if (!usb_endpoint_xfer_bulk(desc))
+		return 0;
+
+	index = dummy_get_ep_idx(desc);
+	return (1 << index) & dum_hcd->stream_en_ep;
+}
+
+/*
+ * The max stream number is saved as a nibble so for the 30 possible endpoints
+ * we only 15 bytes of memory. Therefore we are limited to max 16 streams (0
+ * means we use only 1 stream). The maximum according to the spec is 16bit so
+ * if the 16 stream limit is about to go, the array size should be incremented
+ * to 30 elements of type u16.
+ */
+static int get_max_streams_for_pipe(struct dummy_hcd *dum_hcd,
+		unsigned int pipe)
+{
+	int max_streams;
+
+	max_streams = dum_hcd->num_stream[usb_pipeendpoint(pipe)];
+	if (usb_pipeout(pipe))
+		max_streams >>= 4;
+	else
+		max_streams &= 0xf;
+	max_streams++;
+	return max_streams;
+}
+
+static void set_max_streams_for_pipe(struct dummy_hcd *dum_hcd,
+		unsigned int pipe, unsigned int streams)
+{
+	int max_streams;
+
+	streams--;
+	max_streams = dum_hcd->num_stream[usb_pipeendpoint(pipe)];
+	if (usb_pipeout(pipe)) {
+		streams <<= 4;
+		max_streams &= 0xf;
+	} else {
+		max_streams &= 0xf0;
+	}
+	max_streams |= streams;
+	dum_hcd->num_stream[usb_pipeendpoint(pipe)] = max_streams;
+}
+
+static int dummy_validate_stream(struct dummy_hcd *dum_hcd, struct urb *urb)
+{
+	unsigned int max_streams;
+	int enabled;
+
+	enabled = dummy_ep_stream_en(dum_hcd, urb);
+	if (!urb->stream_id) {
+		if (enabled)
+			return -EINVAL;
+		return 0;
+	}
+	if (!enabled)
+		return -EINVAL;
+
+	max_streams = get_max_streams_for_pipe(dum_hcd,
+			usb_pipeendpoint(urb->pipe));
+	if (urb->stream_id > max_streams) {
+		dev_err(dummy_dev(dum_hcd), "Stream id %d is out of range.\n",
+				urb->stream_id);
+		BUG();
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int dummy_urb_enqueue(
 	struct usb_hcd			*hcd,
 	struct urb			*urb,
 	gfp_t				mem_flags
@@ -1083,16 +1172,21 @@
 	unsigned long	flags;
 	int		rc;
 
-	if (!urb->transfer_buffer && urb->transfer_buffer_length)
-		return -EINVAL;
-
-	urbp = kmalloc (sizeof *urbp, mem_flags);
+	urbp = kmalloc(sizeof *urbp, mem_flags);
 	if (!urbp)
 		return -ENOMEM;
 	urbp->urb = urb;
+	urbp->miter_started = 0;
 
 	dum_hcd = hcd_to_dummy_hcd(hcd);
 	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
+
+	rc = dummy_validate_stream(dum_hcd, urb);
+	if (rc) {
+		kfree(urbp);
+		goto done;
+	}
+
 	rc = usb_hcd_link_urb_to_ep(hcd, urb);
 	if (rc) {
 		kfree(urbp);
@@ -1107,7 +1201,7 @@
 
 	list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
 	urb->hcpriv = urbp;
-	if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
+	if (usb_pipetype(urb->pipe) == PIPE_CONTROL)
 		urb->error_count = 1;		/* mark as a new urb */
 
 	/* kick the scheduler, it'll do the rest */
@@ -1139,20 +1233,91 @@
 	return rc;
 }
 
-/* transfer up to a frame's worth; caller must own lock */
-static int
-transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
-		int *status)
+static int dummy_perform_transfer(struct urb *urb, struct dummy_request *req,
+		u32 len)
 {
+	void *ubuf, *rbuf;
+	struct urbp *urbp = urb->hcpriv;
+	int to_host;
+	struct sg_mapping_iter *miter = &urbp->miter;
+	u32 trans = 0;
+	u32 this_sg;
+	bool next_sg;
+
+	to_host = usb_pipein(urb->pipe);
+	rbuf = req->req.buf + req->req.actual;
+
+	if (!urb->num_sgs) {
+		ubuf = urb->transfer_buffer + urb->actual_length;
+		if (to_host)
+			memcpy(ubuf, rbuf, len);
+		else
+			memcpy(rbuf, ubuf, len);
+		return len;
+	}
+
+	if (!urbp->miter_started) {
+		u32 flags = SG_MITER_ATOMIC;
+
+		if (to_host)
+			flags |= SG_MITER_TO_SG;
+		else
+			flags |= SG_MITER_FROM_SG;
+
+		sg_miter_start(miter, urb->sg, urb->num_sgs, flags);
+		urbp->miter_started = 1;
+	}
+	next_sg = sg_miter_next(miter);
+	if (next_sg == false) {
+		WARN_ON_ONCE(1);
+		return -EINVAL;
+	}
+	do {
+		ubuf = miter->addr;
+		this_sg = min_t(u32, len, miter->length);
+		miter->consumed = this_sg;
+		trans += this_sg;
+
+		if (to_host)
+			memcpy(ubuf, rbuf, this_sg);
+		else
+			memcpy(rbuf, ubuf, this_sg);
+		len -= this_sg;
+
+		if (!len)
+			break;
+		next_sg = sg_miter_next(miter);
+		if (next_sg == false) {
+			WARN_ON_ONCE(1);
+			return -EINVAL;
+		}
+
+		rbuf += this_sg;
+	} while (1);
+
+	sg_miter_stop(miter);
+	return trans;
+}
+
+/* transfer up to a frame's worth; caller must own lock */
+static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb,
+		struct dummy_ep *ep, int limit, int *status)
+{
+	struct dummy		*dum = dum_hcd->dum;
 	struct dummy_request	*req;
 
 top:
 	/* if there's no request queued, the device is NAKing; return */
-	list_for_each_entry (req, &ep->queue, queue) {
+	list_for_each_entry(req, &ep->queue, queue) {
 		unsigned	host_len, dev_len, len;
 		int		is_short, to_host;
 		int		rescan = 0;
 
+		if (dummy_ep_stream_en(dum_hcd, urb)) {
+			if ((urb->stream_id != req->req.stream_id))
+				continue;
+		}
+
 		/* 1..N packets of ep->ep.maxpacket each ... the last one
 		 * may be short (including zero length).
 		 *
@@ -1162,20 +1327,18 @@
 		 */
 		host_len = urb->transfer_buffer_length - urb->actual_length;
 		dev_len = req->req.length - req->req.actual;
-		len = min (host_len, dev_len);
+		len = min(host_len, dev_len);
 
 		/* FIXME update emulated data toggle too */
 
-		to_host = usb_pipein (urb->pipe);
-		if (unlikely (len == 0))
+		to_host = usb_pipein(urb->pipe);
+		if (unlikely(len == 0))
 			is_short = 1;
 		else {
-			char		*ubuf, *rbuf;
-
 			/* not enough bandwidth left? */
 			if (limit < ep->ep.maxpacket && limit < len)
 				break;
-			len = min (len, (unsigned) limit);
+			len = min_t(unsigned, len, limit);
 			if (len == 0)
 				break;
 
@@ -1186,18 +1349,16 @@
 			}
 			is_short = (len % ep->ep.maxpacket) != 0;
 
-			/* else transfer packet(s) */
-			ubuf = urb->transfer_buffer + urb->actual_length;
-			rbuf = req->req.buf + req->req.actual;
-			if (to_host)
-				memcpy (ubuf, rbuf, len);
-			else
-				memcpy (rbuf, ubuf, len);
-			ep->last_io = jiffies;
+			len = dummy_perform_transfer(urb, req, len);
 
-			limit -= len;
-			urb->actual_length += len;
-			req->req.actual += len;
+			ep->last_io = jiffies;
+			if ((int)len < 0) {
+				req->req.status = len;
+			} else {
+				limit -= len;
+				urb->actual_length += len;
+				req->req.actual += len;
+			}
 		}
 
 		/* short packets terminate, maybe with overflow/underflow.
@@ -1238,11 +1399,11 @@
 
 		/* device side completion --> continuable */
 		if (req->req.status != -EINPROGRESS) {
-			list_del_init (&req->queue);
+			list_del_init(&req->queue);
 
-			spin_unlock (&dum->lock);
-			req->req.complete (&ep->ep, &req->req);
-			spin_lock (&dum->lock);
+			spin_unlock(&dum->lock);
+			req->req.complete(&ep->ep, &req->req);
+			spin_lock(&dum->lock);
 
 			/* requests might have been unlinked... */
 			rescan = 1;
@@ -1259,7 +1420,7 @@
 	return limit;
 }
 
-static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
+static int periodic_bytes(struct dummy *dum, struct dummy_ep *ep)
 {
 	int	limit = ep->ep.maxpacket;
 
@@ -1273,7 +1434,7 @@
 		limit += limit * tmp;
 	}
 	if (dum->gadget.speed == USB_SPEED_SUPER) {
-		switch (ep->desc->bmAttributes & 0x03) {
+		switch (usb_endpoint_type(ep->desc)) {
 		case USB_ENDPOINT_XFER_ISOC:
 			/* Sec. 4.4.8.2 USB3.0 Spec */
 			limit = 3 * 16 * 1024 * 8;
@@ -1295,7 +1456,7 @@
 			USB_PORT_STAT_SUSPEND)) \
 		== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
 
-static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
+static struct dummy_ep *find_endpoint(struct dummy *dum, u8 address)
 {
 	int		i;
 
@@ -1303,9 +1464,9 @@
 			dum->ss_hcd : dum->hs_hcd)))
 		return NULL;
 	if ((address & ~USB_DIR_IN) == 0)
-		return &dum->ep [0];
+		return &dum->ep[0];
 	for (i = 1; i < DUMMY_ENDPOINTS; i++) {
-		struct dummy_ep	*ep = &dum->ep [i];
+		struct dummy_ep	*ep = &dum->ep[i];
 
 		if (!ep->desc)
 			continue;
@@ -1535,19 +1696,19 @@
 	/* FIXME if HZ != 1000 this will probably misbehave ... */
 
 	/* look at each urb queued by the host side driver */
-	spin_lock_irqsave (&dum->lock, flags);
+	spin_lock_irqsave(&dum->lock, flags);
 
 	if (!dum_hcd->udev) {
 		dev_err(dummy_dev(dum_hcd),
 				"timer fired with no URBs pending?\n");
-		spin_unlock_irqrestore (&dum->lock, flags);
+		spin_unlock_irqrestore(&dum->lock, flags);
 		return;
 	}
 
 	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
-		if (!ep_name [i])
+		if (!ep_name[i])
 			break;
-		dum->ep [i].already_seen = 0;
+		dum->ep[i].already_seen = 0;
 	}
 
 restart:
@@ -1564,7 +1725,7 @@
 			goto return_urb;
 		else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
 			continue;
-		type = usb_pipetype (urb->pipe);
+		type = usb_pipetype(urb->pipe);
 
 		/* used up this frame's non-periodic bandwidth?
 		 * FIXME there's infinite bandwidth for control and
@@ -1575,7 +1736,7 @@
 
 		/* find the gadget's ep for this request (if configured) */
 		address = usb_pipeendpoint (urb->pipe);
-		if (usb_pipein (urb->pipe))
+		if (usb_pipein(urb->pipe))
 			address |= USB_DIR_IN;
 		ep = find_endpoint(dum, address);
 		if (!ep) {
@@ -1590,7 +1751,7 @@
 		if (ep->already_seen)
 			continue;
 		ep->already_seen = 1;
-		if (ep == &dum->ep [0] && urb->error_count) {
+		if (ep == &dum->ep[0] && urb->error_count) {
 			ep->setup_stage = 1;	/* a new urb */
 			urb->error_count = 0;
 		}
@@ -1604,21 +1765,21 @@
 		/* FIXME make sure both ends agree on maxpacket */
 
 		/* handle control requests */
-		if (ep == &dum->ep [0] && ep->setup_stage) {
+		if (ep == &dum->ep[0] && ep->setup_stage) {
 			struct usb_ctrlrequest		setup;
 			int				value = 1;
 
-			setup = *(struct usb_ctrlrequest*) urb->setup_packet;
+			setup = *(struct usb_ctrlrequest *) urb->setup_packet;
 			/* paranoia, in case of stale queued data */
-			list_for_each_entry (req, &ep->queue, queue) {
-				list_del_init (&req->queue);
+			list_for_each_entry(req, &ep->queue, queue) {
+				list_del_init(&req->queue);
 				req->req.status = -EOVERFLOW;
-				dev_dbg (udc_dev(dum), "stale req = %p\n",
+				dev_dbg(udc_dev(dum), "stale req = %p\n",
 						req);
 
-				spin_unlock (&dum->lock);
-				req->req.complete (&ep->ep, &req->req);
-				spin_lock (&dum->lock);
+				spin_unlock(&dum->lock);
+				req->req.complete(&ep->ep, &req->req);
+				spin_lock(&dum->lock);
 				ep->already_seen = 0;
 				goto restart;
 			}
@@ -1638,10 +1799,10 @@
 			 * until setup() returns; no reentrancy issues etc.
 			 */
 			if (value > 0) {
-				spin_unlock (&dum->lock);
-				value = dum->driver->setup (&dum->gadget,
+				spin_unlock(&dum->lock);
+				value = dum->driver->setup(&dum->gadget,
 						&setup);
-				spin_lock (&dum->lock);
+				spin_lock(&dum->lock);
 
 				if (value >= 0) {
 					/* no delays (max 64KB data stage) */
@@ -1653,7 +1814,7 @@
 
 			if (value < 0) {
 				if (value != -EOPNOTSUPP)
-					dev_dbg (udc_dev(dum),
+					dev_dbg(udc_dev(dum),
 						"setup --> %d\n",
 						value);
 				status = -EPIPE;
@@ -1665,14 +1826,14 @@
 
 		/* non-control requests */
 		limit = total;
-		switch (usb_pipetype (urb->pipe)) {
+		switch (usb_pipetype(urb->pipe)) {
 		case PIPE_ISOCHRONOUS:
 			/* FIXME is it urb->interval since the last xfer?
 			 * use urb->iso_frame_desc[i].
 			 * complete whether or not ep has requests queued.
 			 * report random errors, to debug drivers.
 			 */
-			limit = max (limit, periodic_bytes (dum, ep));
+			limit = max(limit, periodic_bytes(dum, ep));
 			status = -ENOSYS;
 			break;
 
@@ -1680,14 +1841,13 @@
 			/* FIXME is it urb->interval since the last xfer?
 			 * this almost certainly polls too fast.
 			 */
-			limit = max (limit, periodic_bytes (dum, ep));
+			limit = max(limit, periodic_bytes(dum, ep));
 			/* FALLTHROUGH */
 
-		// case PIPE_BULK:  case PIPE_CONTROL:
 		default:
-		treat_control_like_bulk:
+treat_control_like_bulk:
 			ep->last_io = jiffies;
-			total = transfer(dum, urb, ep, limit, &status);
+			total = transfer(dum_hcd, urb, ep, limit, &status);
 			break;
 		}
 
@@ -1696,15 +1856,15 @@
 			continue;
 
 return_urb:
-		list_del (&urbp->urbp_list);
-		kfree (urbp);
+		list_del(&urbp->urbp_list);
+		kfree(urbp);
 		if (ep)
 			ep->already_seen = ep->setup_stage = 0;
 
 		usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
-		spin_unlock (&dum->lock);
+		spin_unlock(&dum->lock);
 		usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
-		spin_lock (&dum->lock);
+		spin_lock(&dum->lock);
 
 		goto restart;
 	}
@@ -1717,7 +1877,7 @@
 		mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));
 	}
 
-	spin_unlock_irqrestore (&dum->lock, flags);
+	spin_unlock_irqrestore(&dum->lock, flags);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1729,7 +1889,7 @@
 	| USB_PORT_STAT_C_OVERCURRENT \
 	| USB_PORT_STAT_C_RESET) << 16)
 
-static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
+static int dummy_hub_status(struct usb_hcd *hcd, char *buf)
 {
 	struct dummy_hcd	*dum_hcd;
 	unsigned long		flags;
@@ -1753,7 +1913,7 @@
 				dum_hcd->port_status);
 		retval = 1;
 		if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED)
-			usb_hcd_resume_root_hub (hcd);
+			usb_hcd_resume_root_hub(hcd);
 	}
 done:
 	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
@@ -1772,10 +1932,9 @@
 	desc->u.ss.DeviceRemovable = 0xffff;
 }
 
-static inline void
-hub_descriptor (struct usb_hub_descriptor *desc)
+static inline void hub_descriptor(struct usb_hub_descriptor *desc)
 {
-	memset (desc, 0, sizeof *desc);
+	memset(desc, 0, sizeof *desc);
 	desc->bDescriptorType = 0x29;
 	desc->bDescLength = 9;
 	desc->wHubCharacteristics = cpu_to_le16(0x0001);
@@ -1784,7 +1943,7 @@
 	desc->u.hs.DeviceRemovable[1] = 0xff;
 }
 
-static int dummy_hub_control (
+static int dummy_hub_control(
 	struct usb_hcd	*hcd,
 	u16		typeReq,
 	u16		wValue,
@@ -1852,7 +2011,7 @@
 			hub_descriptor((struct usb_hub_descriptor *) buf);
 		break;
 	case GetHubStatus:
-		*(__le32 *) buf = cpu_to_le32 (0);
+		*(__le32 *) buf = cpu_to_le32(0);
 		break;
 	case GetPortStatus:
 		if (wIndex != 1)
@@ -1894,8 +2053,8 @@
 			}
 		}
 		set_link_state(dum_hcd);
-		((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status);
-		((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);
+		((__le16 *) buf)[0] = cpu_to_le16(dum_hcd->port_status);
+		((__le16 *) buf)[1] = cpu_to_le16(dum_hcd->port_status >> 16);
 		break;
 	case SetHubFeature:
 		retval = -EPIPE;
@@ -2029,15 +2188,15 @@
 	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 
 	if ((dum_hcd->port_status & PORT_C_MASK) != 0)
-		usb_hcd_poll_rh_status (hcd);
+		usb_hcd_poll_rh_status(hcd);
 	return retval;
 }
 
-static int dummy_bus_suspend (struct usb_hcd *hcd)
+static int dummy_bus_suspend(struct usb_hcd *hcd)
 {
 	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
 
-	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
+	dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
 
 	spin_lock_irq(&dum_hcd->dum->lock);
 	dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
@@ -2047,12 +2206,12 @@
 	return 0;
 }
 
-static int dummy_bus_resume (struct usb_hcd *hcd)
+static int dummy_bus_resume(struct usb_hcd *hcd)
 {
 	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
 	int rc = 0;
 
-	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
+	dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
 
 	spin_lock_irq(&dum_hcd->dum->lock);
 	if (!HCD_HW_ACCESSIBLE(hcd)) {
@@ -2070,55 +2229,54 @@
 
 /*-------------------------------------------------------------------------*/
 
-static inline ssize_t
-show_urb (char *buf, size_t size, struct urb *urb)
+static inline ssize_t show_urb(char *buf, size_t size, struct urb *urb)
 {
-	int ep = usb_pipeendpoint (urb->pipe);
+	int ep = usb_pipeendpoint(urb->pipe);
 
-	return snprintf (buf, size,
+	return snprintf(buf, size,
 		"urb/%p %s ep%d%s%s len %d/%d\n",
 		urb,
 		({ char *s;
-		 switch (urb->dev->speed) {
-		 case USB_SPEED_LOW:
+		switch (urb->dev->speed) {
+		case USB_SPEED_LOW:
 			s = "ls";
 			break;
-		 case USB_SPEED_FULL:
+		case USB_SPEED_FULL:
 			s = "fs";
 			break;
-		 case USB_SPEED_HIGH:
+		case USB_SPEED_HIGH:
 			s = "hs";
 			break;
-		 case USB_SPEED_SUPER:
+		case USB_SPEED_SUPER:
 			s = "ss";
 			break;
-		 default:
+		default:
 			s = "?";
 			break;
 		 }; s; }),
-		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
+		ep, ep ? (usb_pipein(urb->pipe) ? "in" : "out") : "",
 		({ char *s; \
-		 switch (usb_pipetype (urb->pipe)) { \
-		 case PIPE_CONTROL: \
+		switch (usb_pipetype(urb->pipe)) { \
+		case PIPE_CONTROL: \
 			s = ""; \
 			break; \
-		 case PIPE_BULK: \
+		case PIPE_BULK: \
 			s = "-bulk"; \
 			break; \
-		 case PIPE_INTERRUPT: \
+		case PIPE_INTERRUPT: \
 			s = "-int"; \
 			break; \
-		 default: \
+		default: \
 			s = "-iso"; \
 			break; \
-		}; s;}),
+		}; s; }),
 		urb->actual_length, urb->transfer_buffer_length);
 }
 
-static ssize_t
-show_urbs (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_urbs(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
-	struct usb_hcd		*hcd = dev_get_drvdata (dev);
+	struct usb_hcd		*hcd = dev_get_drvdata(dev);
 	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
 	struct urbp		*urbp;
 	size_t			size = 0;
@@ -2128,7 +2286,7 @@
 	list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {
 		size_t		temp;
 
-		temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
+		temp = show_urb(buf, PAGE_SIZE - size, urbp->urb);
 		buf += temp;
 		size += temp;
 	}
@@ -2136,7 +2294,7 @@
 
 	return size;
 }
-static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
+static DEVICE_ATTR(urbs, S_IRUGO, show_urbs, NULL);
 
 static int dummy_start_ss(struct dummy_hcd *dum_hcd)
 {
@@ -2144,6 +2302,7 @@
 	dum_hcd->timer.function = dummy_timer;
 	dum_hcd->timer.data = (unsigned long)dum_hcd;
 	dum_hcd->rh_state = DUMMY_RH_RUNNING;
+	dum_hcd->stream_en_ep = 0;
 	INIT_LIST_HEAD(&dum_hcd->urbp_list);
 	dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET;
 	dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING;
@@ -2189,11 +2348,11 @@
 	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
 }
 
-static void dummy_stop (struct usb_hcd *hcd)
+static void dummy_stop(struct usb_hcd *hcd)
 {
 	struct dummy		*dum;
 
-	dum = (hcd_to_dummy_hcd(hcd))->dum;
+	dum = hcd_to_dummy_hcd(hcd)->dum;
 	device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
 	usb_gadget_unregister_driver(dum->driver);
 	dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
@@ -2201,13 +2360,14 @@
 
 /*-------------------------------------------------------------------------*/
 
-static int dummy_h_get_frame (struct usb_hcd *hcd)
+static int dummy_h_get_frame(struct usb_hcd *hcd)
 {
-	return dummy_g_get_frame (NULL);
+	return dummy_g_get_frame(NULL);
 }
 
 static int dummy_setup(struct usb_hcd *hcd)
 {
+	hcd->self.sg_tablesize = ~0;
 	if (usb_hcd_is_primary_hcd(hcd)) {
 		the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
 		the_controller.hs_hcd->dum = &the_controller;
@@ -2228,27 +2388,82 @@
 }
 
 /* Change a group of bulk endpoints to support multiple stream IDs */
-int dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
+static int dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
 	struct usb_host_endpoint **eps, unsigned int num_eps,
 	unsigned int num_streams, gfp_t mem_flags)
 {
-	if (hcd->speed != HCD_USB3)
-		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
-			"%s() - ERROR! Not supported for USB2.0 roothub\n",
-			__func__);
-	return 0;
+	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
+	unsigned long flags;
+	int max_stream;
+	int ret_streams = num_streams;
+	unsigned int index;
+	unsigned int i;
+
+	if (!num_eps)
+		return -EINVAL;
+
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
+	for (i = 0; i < num_eps; i++) {
+		index = dummy_get_ep_idx(&eps[i]->desc);
+		if ((1 << index) & dum_hcd->stream_en_ep) {
+			ret_streams = -EINVAL;
+			goto out;
+		}
+		max_stream = usb_ss_max_streams(&eps[i]->ss_ep_comp);
+		if (!max_stream) {
+			ret_streams = -EINVAL;
+			goto out;
+		}
+		if (max_stream < ret_streams) {
+			dev_dbg(dummy_dev(dum_hcd), "Ep 0x%x only supports %u "
+					"stream IDs.\n",
+					eps[i]->desc.bEndpointAddress,
+					max_stream);
+			ret_streams = max_stream;
+		}
+	}
+
+	for (i = 0; i < num_eps; i++) {
+		index = dummy_get_ep_idx(&eps[i]->desc);
+		dum_hcd->stream_en_ep |= 1 << index;
+		set_max_streams_for_pipe(dum_hcd,
+				usb_endpoint_num(&eps[i]->desc), ret_streams);
+	}
+out:
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
+	return ret_streams;
 }
 
 /* Reverts a group of bulk endpoints back to not using stream IDs. */
-int dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
+static int dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
 	struct usb_host_endpoint **eps, unsigned int num_eps,
 	gfp_t mem_flags)
 {
-	if (hcd->speed != HCD_USB3)
-		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
-			"%s() - ERROR! Not supported for USB2.0 roothub\n",
-			__func__);
-	return 0;
+	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
+	unsigned long flags;
+	int ret;
+	unsigned int index;
+	unsigned int i;
+
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
+	for (i = 0; i < num_eps; i++) {
+		index = dummy_get_ep_idx(&eps[i]->desc);
+		if (!((1 << index) & dum_hcd->stream_en_ep)) {
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	for (i = 0; i < num_eps; i++) {
+		index = dummy_get_ep_idx(&eps[i]->desc);
+		dum_hcd->stream_en_ep &= ~(1 << index);
+		set_max_streams_for_pipe(dum_hcd,
+				usb_endpoint_num(&eps[i]->desc), 0);
+	}
+	ret = 0;
+out:
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
+	return ret;
 }
 
 static struct hc_driver dummy_hcd = {
@@ -2262,13 +2477,13 @@
 	.start =		dummy_start,
 	.stop =			dummy_stop,
 
-	.urb_enqueue = 		dummy_urb_enqueue,
-	.urb_dequeue = 		dummy_urb_dequeue,
+	.urb_enqueue =		dummy_urb_enqueue,
+	.urb_dequeue =		dummy_urb_dequeue,
 
-	.get_frame_number = 	dummy_h_get_frame,
+	.get_frame_number =	dummy_h_get_frame,
 
-	.hub_status_data = 	dummy_hub_status,
-	.hub_control = 		dummy_hub_control,
+	.hub_status_data =	dummy_hub_status,
+	.hub_control =		dummy_hub_control,
 	.bus_suspend =		dummy_bus_suspend,
 	.bus_resume =		dummy_bus_resume,
 
@@ -2323,7 +2538,7 @@
 {
 	struct dummy		*dum;
 
-	dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum;
+	dum = hcd_to_dummy_hcd(platform_get_drvdata(pdev))->dum;
 
 	if (dum->ss_hcd) {
 		usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
@@ -2339,15 +2554,15 @@
 	return 0;
 }
 
-static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
+static int dummy_hcd_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	struct usb_hcd		*hcd;
 	struct dummy_hcd	*dum_hcd;
 	int			rc = 0;
 
-	dev_dbg (&pdev->dev, "%s\n", __func__);
+	dev_dbg(&pdev->dev, "%s\n", __func__);
 
-	hcd = platform_get_drvdata (pdev);
+	hcd = platform_get_drvdata(pdev);
 	dum_hcd = hcd_to_dummy_hcd(hcd);
 	if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
 		dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
@@ -2357,15 +2572,15 @@
 	return rc;
 }
 
-static int dummy_hcd_resume (struct platform_device *pdev)
+static int dummy_hcd_resume(struct platform_device *pdev)
 {
 	struct usb_hcd		*hcd;
 
-	dev_dbg (&pdev->dev, "%s\n", __func__);
+	dev_dbg(&pdev->dev, "%s\n", __func__);
 
-	hcd = platform_get_drvdata (pdev);
+	hcd = platform_get_drvdata(pdev);
 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-	usb_hcd_poll_rh_status (hcd);
+	usb_hcd_poll_rh_status(hcd);
 	return 0;
 }
 
@@ -2385,11 +2600,11 @@
 static struct platform_device *the_udc_pdev;
 static struct platform_device *the_hcd_pdev;
 
-static int __init init (void)
+static int __init init(void)
 {
 	int	retval = -ENOMEM;
 
-	if (usb_disabled ())
+	if (usb_disabled())
 		return -ENODEV;
 
 	if (!mod_data.is_high_speed && mod_data.is_super_speed)
@@ -2448,13 +2663,13 @@
 	platform_device_put(the_hcd_pdev);
 	return retval;
 }
-module_init (init);
+module_init(init);
 
-static void __exit cleanup (void)
+static void __exit cleanup(void)
 {
 	platform_device_unregister(the_udc_pdev);
 	platform_device_unregister(the_hcd_pdev);
 	platform_driver_unregister(&dummy_udc_driver);
 	platform_driver_unregister(&dummy_hcd_driver);
 }
-module_exit (cleanup);
+module_exit(cleanup);
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index e0e6375..51f3d42 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -275,24 +275,24 @@
 		/* ep-e, ep-f are PIO with only 64 byte fifos */
 		ep = find_ep (gadget, "ep-e");
 		if (ep && ep_matches(gadget, ep, desc, ep_comp))
-			return ep;
+			goto found_ep;
 		ep = find_ep (gadget, "ep-f");
 		if (ep && ep_matches(gadget, ep, desc, ep_comp))
-			return ep;
+			goto found_ep;
 
 	} else if (gadget_is_goku (gadget)) {
 		if (USB_ENDPOINT_XFER_INT == type) {
 			/* single buffering is enough */
 			ep = find_ep(gadget, "ep3-bulk");
 			if (ep && ep_matches(gadget, ep, desc, ep_comp))
-				return ep;
+				goto found_ep;
 		} else if (USB_ENDPOINT_XFER_BULK == type
 				&& (USB_DIR_IN & desc->bEndpointAddress)) {
 			/* DMA may be available */
 			ep = find_ep(gadget, "ep2-bulk");
 			if (ep && ep_matches(gadget, ep, desc,
 					      ep_comp))
-				return ep;
+				goto found_ep;
 		}
 
 #ifdef CONFIG_BLACKFIN
@@ -311,18 +311,22 @@
 		} else
 			ep = NULL;
 		if (ep && ep_matches(gadget, ep, desc, ep_comp))
-			return ep;
+			goto found_ep;
 #endif
 	}
 
 	/* Second, look at endpoints until an unclaimed one looks usable */
 	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
 		if (ep_matches(gadget, ep, desc, ep_comp))
-			return ep;
+			goto found_ep;
 	}
 
 	/* Fail */
 	return NULL;
+found_ep:
+	ep->desc = NULL;
+	ep->comp_desc = NULL;
+	return ep;
 }
 
 /**
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 3f88493..d672250a 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -5,7 +5,7 @@
  * Copyright (C) 2008 by David Brownell
  * Copyright (C) 2008 by Nokia Corporation
  * Copyright (C) 2009 by Samsung Electronics
- * Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
+ * Author: Michal Nazarewicz (mina86@mina86.com)
  *
  * This software is distributed under the terms of the GNU General
  * Public License ("GPL") as published by the Free Software Foundation,
@@ -237,6 +237,42 @@
 	NULL,
 };
 
+static struct usb_endpoint_descriptor acm_ss_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor acm_ss_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor acm_ss_bulk_comp_desc = {
+	.bLength =              sizeof acm_ss_bulk_comp_desc,
+	.bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_descriptor_header *acm_ss_function[] = {
+	(struct usb_descriptor_header *) &acm_iad_descriptor,
+	(struct usb_descriptor_header *) &acm_control_interface_desc,
+	(struct usb_descriptor_header *) &acm_header_desc,
+	(struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &acm_descriptor,
+	(struct usb_descriptor_header *) &acm_union_desc,
+	(struct usb_descriptor_header *) &acm_hs_notify_desc,
+	(struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
+	(struct usb_descriptor_header *) &acm_data_interface_desc,
+	(struct usb_descriptor_header *) &acm_ss_in_desc,
+	(struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
+	(struct usb_descriptor_header *) &acm_ss_out_desc,
+	(struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
+	NULL,
+};
+
 /* string descriptors: */
 
 #define ACM_CTRL_IDX	0
@@ -643,9 +679,21 @@
 		/* copy descriptors */
 		f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
 	}
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		acm_ss_in_desc.bEndpointAddress =
+			acm_fs_in_desc.bEndpointAddress;
+		acm_ss_out_desc.bEndpointAddress =
+			acm_fs_out_desc.bEndpointAddress;
+
+		/* copy descriptors, and track endpoint copies */
+		f->ss_descriptors = usb_copy_descriptors(acm_ss_function);
+		if (!f->ss_descriptors)
+			goto fail;
+	}
 
 	DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
 			acm->port_num,
+			gadget_is_superspeed(c->cdev->gadget) ? "super" :
 			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
 			acm->port.in->name, acm->port.out->name,
 			acm->notify->name);
@@ -675,6 +723,8 @@
 
 	if (gadget_is_dualspeed(c->cdev->gadget))
 		usb_free_descriptors(f->hs_descriptors);
+	if (gadget_is_superspeed(c->cdev->gadget))
+		usb_free_descriptors(f->ss_descriptors);
 	usb_free_descriptors(f->descriptors);
 	gs_free_req(acm->notify, acm->notify_req);
 	kfree(acm);
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 11c07cb..30b908f 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -97,6 +97,20 @@
 
 /* interface descriptor: */
 
+static struct usb_interface_assoc_descriptor
+ecm_iad_descriptor = {
+	.bLength =		sizeof ecm_iad_descriptor,
+	.bDescriptorType =	USB_DT_INTERFACE_ASSOCIATION,
+
+	/* .bFirstInterface =	DYNAMIC, */
+	.bInterfaceCount =	2,	/* control + data */
+	.bFunctionClass =	USB_CLASS_COMM,
+	.bFunctionSubClass =	USB_CDC_SUBCLASS_ETHERNET,
+	.bFunctionProtocol =	USB_CDC_PROTO_NONE,
+	/* .iFunction =		DYNAMIC */
+};
+
+
 static struct usb_interface_descriptor ecm_control_intf = {
 	.bLength =		sizeof ecm_control_intf,
 	.bDescriptorType =	USB_DT_INTERFACE,
@@ -199,6 +213,7 @@
 
 static struct usb_descriptor_header *ecm_fs_function[] = {
 	/* CDC ECM control descriptors */
+	(struct usb_descriptor_header *) &ecm_iad_descriptor,
 	(struct usb_descriptor_header *) &ecm_control_intf,
 	(struct usb_descriptor_header *) &ecm_header_desc,
 	(struct usb_descriptor_header *) &ecm_union_desc,
@@ -247,6 +262,7 @@
 
 static struct usb_descriptor_header *ecm_hs_function[] = {
 	/* CDC ECM control descriptors */
+	(struct usb_descriptor_header *) &ecm_iad_descriptor,
 	(struct usb_descriptor_header *) &ecm_control_intf,
 	(struct usb_descriptor_header *) &ecm_header_desc,
 	(struct usb_descriptor_header *) &ecm_union_desc,
@@ -339,6 +355,7 @@
 	[0].s = "CDC Ethernet Control Model (ECM)",
 	[1].s = NULL /* DYNAMIC */,
 	[2].s = "CDC Ethernet Data",
+	[3].s = "CDC ECM",
 	{  } /* end of list */
 };
 
@@ -674,6 +691,7 @@
 	if (status < 0)
 		goto fail;
 	ecm->ctrl_id = status;
+	ecm_iad_descriptor.bFirstInterface = status;
 
 	ecm_control_intf.bInterfaceNumber = status;
 	ecm_union_desc.bMasterInterface0 = status;
@@ -864,6 +882,13 @@
 			return status;
 		ecm_string_defs[1].id = status;
 		ecm_desc.iMACAddress = status;
+
+		/* IAD label */
+		status = usb_string_id(c->cdev);
+		if (status < 0)
+			return status;
+		ecm_string_defs[3].id = status;
+		ecm_iad_descriptor.iFunction = status;
 	}
 
 	/* allocate and initialize one new instance */
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index f63dc6c..7f445ec 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -2,7 +2,7 @@
  * f_fs.c -- user mode file system API for USB composite function controllers
  *
  * Copyright (C) 2010 Samsung Electronics
- * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ * Author: Michal Nazarewicz <mina86@mina86.com>
  *
  * Based on inode.c (GadgetFS) which was:
  * Copyright (C) 2003-2004 David Brownell
@@ -1258,9 +1258,7 @@
 	if (unlikely(atomic_dec_and_test(&ffs->ref))) {
 		pr_info("%s(): freeing\n", __func__);
 		ffs_data_clear(ffs);
-		BUG_ON(mutex_is_locked(&ffs->mutex) ||
-		       spin_is_locked(&ffs->ev.waitq.lock) ||
-		       waitqueue_active(&ffs->ev.waitq) ||
+		BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
 		       waitqueue_active(&ffs->ep0req_completion.wait));
 		kfree(ffs);
 	}
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index ee8ceec..a371e96 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2003-2008 Alan Stern
  * Copyright (C) 2009 Samsung Electronics
- *                    Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ *                    Author: Michal Nazarewicz <mina86@mina86.com>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -304,7 +304,6 @@
 
 static const char fsg_string_interface[] = "Mass Storage";
 
-#define FSG_NO_INTR_EP 1
 #define FSG_NO_DEVICE_STRINGS    1
 #define FSG_NO_OTG               1
 #define FSG_NO_INTR_EP           1
@@ -620,7 +619,7 @@
 
 	switch (ctrl->bRequest) {
 
-	case USB_BULK_RESET_REQUEST:
+	case US_BULK_RESET_REQUEST:
 		if (ctrl->bRequestType !=
 		    (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
 			break;
@@ -636,7 +635,7 @@
 		raise_exception(fsg->common, FSG_STATE_RESET);
 		return DELAYED_STATUS;
 
-	case USB_BULK_GET_MAX_LUN_REQUEST:
+	case US_BULK_GET_MAX_LUN:
 		if (ctrl->bRequestType !=
 		    (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
 			break;
@@ -1742,7 +1741,7 @@
 	struct fsg_buffhd	*bh;
 	struct bulk_cs_wrap	*csw;
 	int			rc;
-	u8			status = USB_STATUS_PASS;
+	u8			status = US_BULK_STAT_OK;
 	u32			sd, sdinfo = 0;
 
 	/* Wait for the next buffer to become available */
@@ -1763,11 +1762,11 @@
 
 	if (common->phase_error) {
 		DBG(common, "sending phase-error status\n");
-		status = USB_STATUS_PHASE_ERROR;
+		status = US_BULK_STAT_PHASE;
 		sd = SS_INVALID_COMMAND;
 	} else if (sd != SS_NO_SENSE) {
 		DBG(common, "sending command-failure status\n");
-		status = USB_STATUS_FAIL;
+		status = US_BULK_STAT_FAIL;
 		VDBG(common, "  sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
 				"  info x%x\n",
 				SK(sd), ASC(sd), ASCQ(sd), sdinfo);
@@ -1776,12 +1775,12 @@
 	/* Store and send the Bulk-only CSW */
 	csw = (void *)bh->buf;
 
-	csw->Signature = cpu_to_le32(USB_BULK_CS_SIG);
+	csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
 	csw->Tag = common->tag;
 	csw->Residue = cpu_to_le32(common->residue);
 	csw->Status = status;
 
-	bh->inreq->length = USB_BULK_CS_WRAP_LEN;
+	bh->inreq->length = US_BULK_CS_WRAP_LEN;
 	bh->inreq->zero = 0;
 	if (!start_in_transfer(common, bh))
 		/* Don't know what to do if common->fsg is NULL */
@@ -2221,7 +2220,7 @@
 static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 {
 	struct usb_request	*req = bh->outreq;
-	struct fsg_bulk_cb_wrap	*cbw = req->buf;
+	struct bulk_cb_wrap	*cbw = req->buf;
 	struct fsg_common	*common = fsg->common;
 
 	/* Was this a real packet?  Should it be ignored? */
@@ -2229,9 +2228,9 @@
 		return -EINVAL;
 
 	/* Is the CBW valid? */
-	if (req->actual != USB_BULK_CB_WRAP_LEN ||
+	if (req->actual != US_BULK_CB_WRAP_LEN ||
 			cbw->Signature != cpu_to_le32(
-				USB_BULK_CB_SIG)) {
+				US_BULK_CB_SIGN)) {
 		DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
 				req->actual,
 				le32_to_cpu(cbw->Signature));
@@ -2253,7 +2252,7 @@
 	}
 
 	/* Is the CBW meaningful? */
-	if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
+	if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
 			cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
 		DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
 				"cmdlen %u\n",
@@ -2273,7 +2272,7 @@
 	/* Save the command for later */
 	common->cmnd_size = cbw->Length;
 	memcpy(common->cmnd, cbw->CDB, common->cmnd_size);
-	if (cbw->Flags & USB_BULK_IN_FLAG)
+	if (cbw->Flags & US_BULK_FLAG_IN)
 		common->data_dir = DATA_DIR_TO_HOST;
 	else
 		common->data_dir = DATA_DIR_FROM_HOST;
@@ -2303,7 +2302,7 @@
 	}
 
 	/* Queue a request to read a Bulk-only CBW */
-	set_bulk_out_req_length(common, bh, USB_BULK_CB_WRAP_LEN);
+	set_bulk_out_req_length(common, bh, US_BULK_CB_WRAP_LEN);
 	if (!start_out_transfer(common, bh))
 		/* Don't know what to do if common->fsg is NULL */
 		return -EIO;
diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c
index 3797b3d..2f7e8f2 100644
--- a/drivers/usb/gadget/f_midi.c
+++ b/drivers/usb/gadget/f_midi.c
@@ -780,7 +780,7 @@
 	midi->out_ep->driver_data = cdev;	/* claim */
 
 	/* allocate temporary function list */
-	midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(midi_function),
+	midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(*midi_function),
 				GFP_KERNEL);
 	if (!midi_function) {
 		status = -ENOMEM;
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 704d1d9..7b1cf18 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -5,7 +5,7 @@
  * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
  * Copyright (C) 2008 Nokia Corporation
  * Copyright (C) 2009 Samsung Electronics
- *                    Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
+ *                    Author: Michal Nazarewicz (mina86@mina86.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
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index cf33a8d..07197d6 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -99,6 +99,34 @@
 	NULL,
 };
 
+static struct usb_endpoint_descriptor gser_ss_in_desc __initdata = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor gser_ss_out_desc __initdata = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc __initdata = {
+	.bLength =              sizeof gser_ss_bulk_comp_desc,
+	.bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_descriptor_header *gser_ss_function[] __initdata = {
+	(struct usb_descriptor_header *) &gser_interface_desc,
+	(struct usb_descriptor_header *) &gser_ss_in_desc,
+	(struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
+	(struct usb_descriptor_header *) &gser_ss_out_desc,
+	(struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
+	NULL,
+};
+
 /* string descriptors: */
 
 static struct usb_string gser_string_defs[] = {
@@ -201,9 +229,21 @@
 		/* copy descriptors, and track endpoint copies */
 		f->hs_descriptors = usb_copy_descriptors(gser_hs_function);
 	}
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		gser_ss_in_desc.bEndpointAddress =
+			gser_fs_in_desc.bEndpointAddress;
+		gser_ss_out_desc.bEndpointAddress =
+			gser_fs_out_desc.bEndpointAddress;
+
+		/* copy descriptors, and track endpoint copies */
+		f->ss_descriptors = usb_copy_descriptors(gser_ss_function);
+		if (!f->ss_descriptors)
+			goto fail;
+	}
 
 	DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
 			gser->port_num,
+			gadget_is_superspeed(c->cdev->gadget) ? "super" :
 			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
 			gser->port.in->name, gser->port.out->name);
 	return 0;
@@ -225,6 +265,8 @@
 {
 	if (gadget_is_dualspeed(c->cdev->gadget))
 		usb_free_descriptors(f->hs_descriptors);
+	if (gadget_is_superspeed(c->cdev->gadget))
+		usb_free_descriptors(f->ss_descriptors);
 	usb_free_descriptors(f->descriptors);
 	kfree(func_to_gser(f));
 }
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
index c154064..21ab474 100644
--- a/drivers/usb/gadget/f_subset.c
+++ b/drivers/usb/gadget/f_subset.c
@@ -74,7 +74,7 @@
 
 /* interface descriptor: */
 
-static struct usb_interface_descriptor subset_data_intf __initdata = {
+static struct usb_interface_descriptor subset_data_intf = {
 	.bLength =		sizeof subset_data_intf,
 	.bDescriptorType =	USB_DT_INTERFACE,
 
@@ -87,7 +87,7 @@
 	/* .iInterface = DYNAMIC */
 };
 
-static struct usb_cdc_header_desc mdlm_header_desc __initdata = {
+static struct usb_cdc_header_desc mdlm_header_desc = {
 	.bLength =		sizeof mdlm_header_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
@@ -95,7 +95,7 @@
 	.bcdCDC =		cpu_to_le16(0x0110),
 };
 
-static struct usb_cdc_mdlm_desc mdlm_desc __initdata = {
+static struct usb_cdc_mdlm_desc mdlm_desc = {
 	.bLength =		sizeof mdlm_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_MDLM_TYPE,
@@ -111,7 +111,7 @@
  * can't really use its struct.  All we do here is say that we're using
  * the submode of "SAFE" which directly matches the CDC Subset.
  */
-static u8 mdlm_detail_desc[] __initdata = {
+static u8 mdlm_detail_desc[] = {
 	6,
 	USB_DT_CS_INTERFACE,
 	USB_CDC_MDLM_DETAIL_TYPE,
@@ -121,7 +121,7 @@
 	0,	/* network data capabilities ("raw" encapsulation) */
 };
 
-static struct usb_cdc_ether_desc ether_desc __initdata = {
+static struct usb_cdc_ether_desc ether_desc = {
 	.bLength =		sizeof ether_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_ETHERNET_TYPE,
@@ -136,7 +136,7 @@
 
 /* full speed support: */
 
-static struct usb_endpoint_descriptor fs_subset_in_desc __initdata = {
+static struct usb_endpoint_descriptor fs_subset_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -144,7 +144,7 @@
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_endpoint_descriptor fs_subset_out_desc __initdata = {
+static struct usb_endpoint_descriptor fs_subset_out_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -152,7 +152,7 @@
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_descriptor_header *fs_eth_function[] __initdata = {
+static struct usb_descriptor_header *fs_eth_function[] = {
 	(struct usb_descriptor_header *) &subset_data_intf,
 	(struct usb_descriptor_header *) &mdlm_header_desc,
 	(struct usb_descriptor_header *) &mdlm_desc,
@@ -165,7 +165,7 @@
 
 /* high speed support: */
 
-static struct usb_endpoint_descriptor hs_subset_in_desc __initdata = {
+static struct usb_endpoint_descriptor hs_subset_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -173,7 +173,7 @@
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_endpoint_descriptor hs_subset_out_desc __initdata = {
+static struct usb_endpoint_descriptor hs_subset_out_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -181,7 +181,7 @@
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *hs_eth_function[] __initdata = {
+static struct usb_descriptor_header *hs_eth_function[] = {
 	(struct usb_descriptor_header *) &subset_data_intf,
 	(struct usb_descriptor_header *) &mdlm_header_desc,
 	(struct usb_descriptor_header *) &mdlm_desc,
@@ -194,7 +194,7 @@
 
 /* super speed support: */
 
-static struct usb_endpoint_descriptor ss_subset_in_desc __initdata = {
+static struct usb_endpoint_descriptor ss_subset_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -202,7 +202,7 @@
 	.wMaxPacketSize =	cpu_to_le16(1024),
 };
 
-static struct usb_endpoint_descriptor ss_subset_out_desc __initdata = {
+static struct usb_endpoint_descriptor ss_subset_out_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -210,7 +210,7 @@
 	.wMaxPacketSize =	cpu_to_le16(1024),
 };
 
-static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc __initdata = {
+static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc = {
 	.bLength =		sizeof ss_subset_bulk_comp_desc,
 	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
 
@@ -219,7 +219,7 @@
 	/* .bmAttributes =	0, */
 };
 
-static struct usb_descriptor_header *ss_eth_function[] __initdata = {
+static struct usb_descriptor_header *ss_eth_function[] = {
 	(struct usb_descriptor_header *) &subset_data_intf,
 	(struct usb_descriptor_header *) &mdlm_header_desc,
 	(struct usb_descriptor_header *) &mdlm_desc,
@@ -290,7 +290,7 @@
 
 /* serial function driver setup/binding */
 
-static int __init
+static int
 geth_bind(struct usb_configuration *c, struct usb_function *f)
 {
 	struct usb_composite_dev *cdev = c->cdev;
@@ -404,7 +404,7 @@
  * Caller must have called @gether_setup().  Caller is also responsible
  * for calling @gether_cleanup() before module unload.
  */
-int __init geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
 {
 	struct f_gether	*geth;
 	int		status;
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_uac1.c
similarity index 97%
rename from drivers/usb/gadget/f_audio.c
rename to drivers/usb/gadget/f_uac1.c
index ec7ffcd..1a5dcd5 100644
--- a/drivers/usb/gadget/f_audio.c
+++ b/drivers/usb/gadget/f_uac1.c
@@ -14,7 +14,7 @@
 #include <linux/device.h>
 #include <linux/atomic.h>
 
-#include "u_audio.h"
+#include "u_uac1.h"
 
 #define OUT_EP_MAX_PACKET_SIZE	200
 static int req_buf_size = OUT_EP_MAX_PACKET_SIZE;
@@ -216,29 +216,6 @@
 	NULL,
 };
 
-/* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX		0
-#define STRING_PRODUCT_IDX		1
-
-static char manufacturer[50];
-
-static struct usb_string strings_dev[] = {
-	[STRING_MANUFACTURER_IDX].s = manufacturer,
-	[STRING_PRODUCT_IDX].s = DRIVER_DESC,
-	{  } /* end of list */
-};
-
-static struct usb_gadget_strings stringtab_dev = {
-	.language	= 0x0409,	/* en-us */
-	.strings	= strings_dev,
-};
-
-static struct usb_gadget_strings *audio_strings[] = {
-	&stringtab_dev,
-	NULL,
-};
-
 /*
  * This function is an ALSA sound card following USB Audio Class Spec 1.0.
  */
diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/f_uac2.c
new file mode 100644
index 0000000..e7cc4de
--- /dev/null
+++ b/drivers/usb/gadget/f_uac2.c
@@ -0,0 +1,1449 @@
+/*
+ * f_uac2.c -- USB Audio Class 2.0 Function
+ *
+ * Copyright (C) 2011
+ *    Yadwinder Singh (yadi.brar01@gmail.com)
+ *    Jaswinder Singh (jaswinder.singh@linaro.org)
+ *
+ * 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.
+ */
+
+#include <linux/usb/audio.h>
+#include <linux/usb/audio-v2.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+/* Playback(USB-IN) Default Stereo - Fl/Fr */
+static int p_chmask = 0x3;
+module_param(p_chmask, uint, S_IRUGO);
+MODULE_PARM_DESC(p_chmask, "Playback Channel Mask");
+
+/* Playback Default 48 KHz */
+static int p_srate = 48000;
+module_param(p_srate, uint, S_IRUGO);
+MODULE_PARM_DESC(p_srate, "Playback Sampling Rate");
+
+/* Playback Default 16bits/sample */
+static int p_ssize = 2;
+module_param(p_ssize, uint, S_IRUGO);
+MODULE_PARM_DESC(p_ssize, "Playback Sample Size(bytes)");
+
+/* Capture(USB-OUT) Default Stereo - Fl/Fr */
+static int c_chmask = 0x3;
+module_param(c_chmask, uint, S_IRUGO);
+MODULE_PARM_DESC(c_chmask, "Capture Channel Mask");
+
+/* Capture Default 64 KHz */
+static int c_srate = 64000;
+module_param(c_srate, uint, S_IRUGO);
+MODULE_PARM_DESC(c_srate, "Capture Sampling Rate");
+
+/* Capture Default 16bits/sample */
+static int c_ssize = 2;
+module_param(c_ssize, uint, S_IRUGO);
+MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)");
+
+#define DMA_ADDR_INVALID	(~(dma_addr_t)0)
+
+#define ALT_SET(x, a)	do {(x) &= ~0xff; (x) |= (a); } while (0)
+#define ALT_GET(x)	((x) & 0xff)
+#define INTF_SET(x, i)	do {(x) &= 0xff; (x) |= ((i) << 8); } while (0)
+#define INTF_GET(x)	((x >> 8) & 0xff)
+
+/* Keep everyone on toes */
+#define USB_XFERS	2
+
+/*
+ * The driver implements a simple UAC_2 topology.
+ * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture
+ * ALSA_Playback -> IT_2 -> OT_4 -> USB-IN
+ * Capture and Playback sampling rates are independently
+ *  controlled by two clock sources :
+ *    CLK_5 := c_srate, and CLK_6 := p_srate
+ */
+#define USB_OUT_IT_ID	1
+#define IO_IN_IT_ID	2
+#define IO_OUT_OT_ID	3
+#define USB_IN_OT_ID	4
+#define USB_OUT_CLK_ID	5
+#define USB_IN_CLK_ID	6
+
+#define CONTROL_ABSENT	0
+#define CONTROL_RDONLY	1
+#define CONTROL_RDWR	3
+
+#define CLK_FREQ_CTRL	0
+#define CLK_VLD_CTRL	2
+
+#define COPY_CTRL	0
+#define CONN_CTRL	2
+#define OVRLD_CTRL	4
+#define CLSTR_CTRL	6
+#define UNFLW_CTRL	8
+#define OVFLW_CTRL	10
+
+const char *uac2_name = "snd_uac2";
+
+struct uac2_req {
+	struct uac2_rtd_params *pp; /* parent param */
+	struct usb_request *req;
+};
+
+struct uac2_rtd_params {
+	bool ep_enabled; /* if the ep is enabled */
+	/* Size of the ring buffer */
+	size_t dma_bytes;
+	unsigned char *dma_area;
+
+	struct snd_pcm_substream *ss;
+
+	/* Ring buffer */
+	ssize_t hw_ptr;
+
+	void *rbuf;
+
+	size_t period_size;
+
+	unsigned max_psize;
+	struct uac2_req ureq[USB_XFERS];
+
+	spinlock_t lock;
+};
+
+struct snd_uac2_chip {
+	struct platform_device pdev;
+	struct platform_driver pdrv;
+
+	struct uac2_rtd_params p_prm;
+	struct uac2_rtd_params c_prm;
+
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+};
+
+#define BUFF_SIZE_MAX	(PAGE_SIZE * 16)
+#define PRD_SIZE_MAX	PAGE_SIZE
+#define MIN_PERIODS	4
+
+static struct snd_pcm_hardware uac2_pcm_hardware = {
+	.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER
+		 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID
+		 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+	.rates = SNDRV_PCM_RATE_CONTINUOUS,
+	.periods_max = BUFF_SIZE_MAX / PRD_SIZE_MAX,
+	.buffer_bytes_max = BUFF_SIZE_MAX,
+	.period_bytes_max = PRD_SIZE_MAX,
+	.periods_min = MIN_PERIODS,
+};
+
+struct audio_dev {
+	/* Currently active {Interface[15:8] | AltSettings[7:0]} */
+	__u16 ac_alt, as_out_alt, as_in_alt;
+
+	struct usb_ep *in_ep, *out_ep;
+	struct usb_function func;
+
+	/* The ALSA Sound Card it represents on the USB-Client side */
+	struct snd_uac2_chip uac2;
+};
+
+static struct audio_dev *agdev_g;
+
+static inline
+struct audio_dev *func_to_agdev(struct usb_function *f)
+{
+	return container_of(f, struct audio_dev, func);
+}
+
+static inline
+struct audio_dev *uac2_to_agdev(struct snd_uac2_chip *u)
+{
+	return container_of(u, struct audio_dev, uac2);
+}
+
+static inline
+struct snd_uac2_chip *pdev_to_uac2(struct platform_device *p)
+{
+	return container_of(p, struct snd_uac2_chip, pdev);
+}
+
+static inline
+struct snd_uac2_chip *prm_to_uac2(struct uac2_rtd_params *r)
+{
+	struct snd_uac2_chip *uac2 = container_of(r,
+					struct snd_uac2_chip, c_prm);
+
+	if (&uac2->c_prm != r)
+		uac2 = container_of(r, struct snd_uac2_chip, p_prm);
+
+	return uac2;
+}
+
+static inline
+uint num_channels(uint chanmask)
+{
+	uint num = 0;
+
+	while (chanmask) {
+		num += (chanmask & 1);
+		chanmask >>= 1;
+	}
+
+	return num;
+}
+
+static void
+agdev_iso_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	unsigned pending;
+	unsigned long flags;
+	bool update_alsa = false;
+	unsigned char *src, *dst;
+	int status = req->status;
+	struct uac2_req *ur = req->context;
+	struct snd_pcm_substream *substream;
+	struct uac2_rtd_params *prm = ur->pp;
+	struct snd_uac2_chip *uac2 = prm_to_uac2(prm);
+
+	/* i/f shutting down */
+	if (!prm->ep_enabled)
+		return;
+
+	/*
+	 * We can't really do much about bad xfers.
+	 * Afterall, the ISOCH xfers could fail legitimately.
+	 */
+	if (status)
+		pr_debug("%s: iso_complete status(%d) %d/%d\n",
+			__func__, status, req->actual, req->length);
+
+	substream = prm->ss;
+
+	/* Do nothing if ALSA isn't active */
+	if (!substream)
+		goto exit;
+
+	spin_lock_irqsave(&prm->lock, flags);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		src = prm->dma_area + prm->hw_ptr;
+		req->actual = req->length;
+		dst = req->buf;
+	} else {
+		dst = prm->dma_area + prm->hw_ptr;
+		src = req->buf;
+	}
+
+	pending = prm->hw_ptr % prm->period_size;
+	pending += req->actual;
+	if (pending >= prm->period_size)
+		update_alsa = true;
+
+	prm->hw_ptr = (prm->hw_ptr + req->actual) % prm->dma_bytes;
+
+	spin_unlock_irqrestore(&prm->lock, flags);
+
+	/* Pack USB load in ALSA ring buffer */
+	memcpy(dst, src, req->actual);
+exit:
+	if (usb_ep_queue(ep, req, GFP_ATOMIC))
+		dev_err(&uac2->pdev.dev, "%d Error!\n", __LINE__);
+
+	if (update_alsa)
+		snd_pcm_period_elapsed(substream);
+
+	return;
+}
+
+static int
+uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream);
+	struct audio_dev *agdev = uac2_to_agdev(uac2);
+	struct uac2_rtd_params *prm;
+	unsigned long flags;
+	struct usb_ep *ep;
+	int err = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ep = agdev->in_ep;
+		prm = &uac2->p_prm;
+	} else {
+		ep = agdev->out_ep;
+		prm = &uac2->c_prm;
+	}
+
+	spin_lock_irqsave(&prm->lock, flags);
+
+	/* Reset */
+	prm->hw_ptr = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		prm->ss = substream;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		prm->ss = NULL;
+		break;
+	default:
+		err = -EINVAL;
+	}
+
+	spin_unlock_irqrestore(&prm->lock, flags);
+
+	/* Clear buffer after Play stops */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !prm->ss)
+		memset(prm->rbuf, 0, prm->max_psize * USB_XFERS);
+
+	return err;
+}
+
+static snd_pcm_uframes_t uac2_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream);
+	struct uac2_rtd_params *prm;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		prm = &uac2->p_prm;
+	else
+		prm = &uac2->c_prm;
+
+	return bytes_to_frames(substream->runtime, prm->hw_ptr);
+}
+
+static int uac2_pcm_hw_params(struct snd_pcm_substream *substream,
+			       struct snd_pcm_hw_params *hw_params)
+{
+	struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream);
+	struct uac2_rtd_params *prm;
+	int err;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		prm = &uac2->p_prm;
+	else
+		prm = &uac2->c_prm;
+
+	err = snd_pcm_lib_malloc_pages(substream,
+					params_buffer_bytes(hw_params));
+	if (err >= 0) {
+		prm->dma_bytes = substream->runtime->dma_bytes;
+		prm->dma_area = substream->runtime->dma_area;
+		prm->period_size = params_period_bytes(hw_params);
+	}
+
+	return err;
+}
+
+static int uac2_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream);
+	struct uac2_rtd_params *prm;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		prm = &uac2->p_prm;
+	else
+		prm = &uac2->c_prm;
+
+	prm->dma_area = NULL;
+	prm->dma_bytes = 0;
+	prm->period_size = 0;
+
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int uac2_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	runtime->hw = uac2_pcm_hardware;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		spin_lock_init(&uac2->p_prm.lock);
+		runtime->hw.rate_min = p_srate;
+		runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; /* ! p_ssize ! */
+		runtime->hw.channels_min = num_channels(p_chmask);
+		runtime->hw.period_bytes_min = 2 * uac2->p_prm.max_psize
+						/ runtime->hw.periods_min;
+	} else {
+		spin_lock_init(&uac2->c_prm.lock);
+		runtime->hw.rate_min = c_srate;
+		runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; /* ! c_ssize ! */
+		runtime->hw.channels_min = num_channels(c_chmask);
+		runtime->hw.period_bytes_min = 2 * uac2->c_prm.max_psize
+						/ runtime->hw.periods_min;
+	}
+
+	runtime->hw.rate_max = runtime->hw.rate_min;
+	runtime->hw.channels_max = runtime->hw.channels_min;
+
+	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+
+	return 0;
+}
+
+/* ALSA cries without these function pointers */
+static int uac2_pcm_null(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+static struct snd_pcm_ops uac2_pcm_ops = {
+	.open = uac2_pcm_open,
+	.close = uac2_pcm_null,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = uac2_pcm_hw_params,
+	.hw_free = uac2_pcm_hw_free,
+	.trigger = uac2_pcm_trigger,
+	.pointer = uac2_pcm_pointer,
+	.prepare = uac2_pcm_null,
+};
+
+static int __devinit snd_uac2_probe(struct platform_device *pdev)
+{
+	struct snd_uac2_chip *uac2 = pdev_to_uac2(pdev);
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+	int err;
+
+	/* Choose any slot, with no id */
+	err = snd_card_create(-1, NULL, THIS_MODULE, 0, &card);
+	if (err < 0)
+		return err;
+
+	uac2->card = card;
+
+	/*
+	 * Create first PCM device
+	 * Create a substream only for non-zero channel streams
+	 */
+	err = snd_pcm_new(uac2->card, "UAC2 PCM", 0,
+			       p_chmask ? 1 : 0, c_chmask ? 1 : 0, &pcm);
+	if (err < 0)
+		goto snd_fail;
+
+	strcpy(pcm->name, "UAC2 PCM");
+	pcm->private_data = uac2;
+
+	uac2->pcm = pcm;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac2_pcm_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac2_pcm_ops);
+
+	strcpy(card->driver, "UAC2_Gadget");
+	strcpy(card->shortname, "UAC2_Gadget");
+	sprintf(card->longname, "UAC2_Gadget %i", pdev->id);
+
+	snd_card_set_dev(card, &pdev->dev);
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+		snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX);
+
+	err = snd_card_register(card);
+	if (!err) {
+		platform_set_drvdata(pdev, card);
+		return 0;
+	}
+
+snd_fail:
+	snd_card_free(card);
+
+	uac2->pcm = NULL;
+	uac2->card = NULL;
+
+	return err;
+}
+
+static int __devexit snd_uac2_remove(struct platform_device *pdev)
+{
+	struct snd_card *card = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (card)
+		return snd_card_free(card);
+
+	return 0;
+}
+
+static int alsa_uac2_init(struct audio_dev *agdev)
+{
+	struct snd_uac2_chip *uac2 = &agdev->uac2;
+	int err;
+
+	uac2->pdrv.probe = snd_uac2_probe;
+	uac2->pdrv.remove = snd_uac2_remove;
+	uac2->pdrv.driver.name = uac2_name;
+
+	uac2->pdev.id = 0;
+	uac2->pdev.name = uac2_name;
+
+	/* Register snd_uac2 driver */
+	err = platform_driver_register(&uac2->pdrv);
+	if (err)
+		return err;
+
+	/* Register snd_uac2 device */
+	err = platform_device_register(&uac2->pdev);
+	if (err)
+		platform_driver_unregister(&uac2->pdrv);
+
+	return err;
+}
+
+static void alsa_uac2_exit(struct audio_dev *agdev)
+{
+	struct snd_uac2_chip *uac2 = &agdev->uac2;
+
+	platform_driver_unregister(&uac2->pdrv);
+	platform_device_unregister(&uac2->pdev);
+}
+
+
+/* --------- USB Function Interface ------------- */
+
+enum {
+	STR_ASSOC,
+	STR_IF_CTRL,
+	STR_CLKSRC_IN,
+	STR_CLKSRC_OUT,
+	STR_USB_IT,
+	STR_IO_IT,
+	STR_USB_OT,
+	STR_IO_OT,
+	STR_AS_OUT_ALT0,
+	STR_AS_OUT_ALT1,
+	STR_AS_IN_ALT0,
+	STR_AS_IN_ALT1,
+};
+
+static const char ifassoc[] = "Source/Sink";
+static const char ifctrl[] = "Topology Control";
+static char clksrc_in[8];
+static char clksrc_out[8];
+static const char usb_it[] = "USBH Out";
+static const char io_it[] = "USBD Out";
+static const char usb_ot[] = "USBH In";
+static const char io_ot[] = "USBD In";
+static const char out_alt0[] = "Playback Inactive";
+static const char out_alt1[] = "Playback Active";
+static const char in_alt0[] = "Capture Inactive";
+static const char in_alt1[] = "Capture Active";
+
+static struct usb_string strings_fn[] = {
+	[STR_ASSOC].s = ifassoc,
+	[STR_IF_CTRL].s = ifctrl,
+	[STR_CLKSRC_IN].s = clksrc_in,
+	[STR_CLKSRC_OUT].s = clksrc_out,
+	[STR_USB_IT].s = usb_it,
+	[STR_IO_IT].s = io_it,
+	[STR_USB_OT].s = usb_ot,
+	[STR_IO_OT].s = io_ot,
+	[STR_AS_OUT_ALT0].s = out_alt0,
+	[STR_AS_OUT_ALT1].s = out_alt1,
+	[STR_AS_IN_ALT0].s = in_alt0,
+	[STR_AS_IN_ALT1].s = in_alt1,
+	{ },
+};
+
+static struct usb_gadget_strings str_fn = {
+	.language = 0x0409,	/* en-us */
+	.strings = strings_fn,
+};
+
+static struct usb_gadget_strings *fn_strings[] = {
+	&str_fn,
+	NULL,
+};
+
+static struct usb_qualifier_descriptor devqual_desc = {
+	.bLength = sizeof devqual_desc,
+	.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
+
+	.bcdUSB = cpu_to_le16(0x200),
+	.bDeviceClass = USB_CLASS_MISC,
+	.bDeviceSubClass = 0x02,
+	.bDeviceProtocol = 0x01,
+	.bNumConfigurations = 1,
+	.bRESERVED = 0,
+};
+
+static struct usb_interface_assoc_descriptor iad_desc = {
+	.bLength = sizeof iad_desc,
+	.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
+
+	.bFirstInterface = 0,
+	.bInterfaceCount = 3,
+	.bFunctionClass = USB_CLASS_AUDIO,
+	.bFunctionSubClass = UAC2_FUNCTION_SUBCLASS_UNDEFINED,
+	.bFunctionProtocol = UAC_VERSION_2,
+};
+
+/* Audio Control Interface */
+static struct usb_interface_descriptor std_ac_if_desc = {
+	.bLength = sizeof std_ac_if_desc,
+	.bDescriptorType = USB_DT_INTERFACE,
+
+	.bAlternateSetting = 0,
+	.bNumEndpoints = 0,
+	.bInterfaceClass = USB_CLASS_AUDIO,
+	.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+	.bInterfaceProtocol = UAC_VERSION_2,
+};
+
+/* Clock source for IN traffic */
+struct uac_clock_source_descriptor in_clk_src_desc = {
+	.bLength = sizeof in_clk_src_desc,
+	.bDescriptorType = USB_DT_CS_INTERFACE,
+
+	.bDescriptorSubtype = UAC2_CLOCK_SOURCE,
+	.bClockID = USB_IN_CLK_ID,
+	.bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED,
+	.bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL),
+	.bAssocTerminal = 0,
+};
+
+/* Clock source for OUT traffic */
+struct uac_clock_source_descriptor out_clk_src_desc = {
+	.bLength = sizeof out_clk_src_desc,
+	.bDescriptorType = USB_DT_CS_INTERFACE,
+
+	.bDescriptorSubtype = UAC2_CLOCK_SOURCE,
+	.bClockID = USB_OUT_CLK_ID,
+	.bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED,
+	.bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL),
+	.bAssocTerminal = 0,
+};
+
+/* Input Terminal for USB_OUT */
+struct uac2_input_terminal_descriptor usb_out_it_desc = {
+	.bLength = sizeof usb_out_it_desc,
+	.bDescriptorType = USB_DT_CS_INTERFACE,
+
+	.bDescriptorSubtype = UAC_INPUT_TERMINAL,
+	.bTerminalID = USB_OUT_IT_ID,
+	.wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING),
+	.bAssocTerminal = 0,
+	.bCSourceID = USB_OUT_CLK_ID,
+	.iChannelNames = 0,
+	.bmControls = (CONTROL_RDWR << COPY_CTRL),
+};
+
+/* Input Terminal for I/O-In */
+struct uac2_input_terminal_descriptor io_in_it_desc = {
+	.bLength = sizeof io_in_it_desc,
+	.bDescriptorType = USB_DT_CS_INTERFACE,
+
+	.bDescriptorSubtype = UAC_INPUT_TERMINAL,
+	.bTerminalID = IO_IN_IT_ID,
+	.wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_UNDEFINED),
+	.bAssocTerminal = 0,
+	.bCSourceID = USB_IN_CLK_ID,
+	.iChannelNames = 0,
+	.bmControls = (CONTROL_RDWR << COPY_CTRL),
+};
+
+/* Ouput Terminal for USB_IN */
+struct uac2_output_terminal_descriptor usb_in_ot_desc = {
+	.bLength = sizeof usb_in_ot_desc,
+	.bDescriptorType = USB_DT_CS_INTERFACE,
+
+	.bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
+	.bTerminalID = USB_IN_OT_ID,
+	.wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING),
+	.bAssocTerminal = 0,
+	.bSourceID = IO_IN_IT_ID,
+	.bCSourceID = USB_IN_CLK_ID,
+	.bmControls = (CONTROL_RDWR << COPY_CTRL),
+};
+
+/* Ouput Terminal for I/O-Out */
+struct uac2_output_terminal_descriptor io_out_ot_desc = {
+	.bLength = sizeof io_out_ot_desc,
+	.bDescriptorType = USB_DT_CS_INTERFACE,
+
+	.bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
+	.bTerminalID = IO_OUT_OT_ID,
+	.wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_UNDEFINED),
+	.bAssocTerminal = 0,
+	.bSourceID = USB_OUT_IT_ID,
+	.bCSourceID = USB_OUT_CLK_ID,
+	.bmControls = (CONTROL_RDWR << COPY_CTRL),
+};
+
+struct uac2_ac_header_descriptor ac_hdr_desc = {
+	.bLength = sizeof ac_hdr_desc,
+	.bDescriptorType = USB_DT_CS_INTERFACE,
+
+	.bDescriptorSubtype = UAC_MS_HEADER,
+	.bcdADC = cpu_to_le16(0x200),
+	.bCategory = UAC2_FUNCTION_IO_BOX,
+	.wTotalLength = sizeof in_clk_src_desc + sizeof out_clk_src_desc
+			 + sizeof usb_out_it_desc + sizeof io_in_it_desc
+			+ sizeof usb_in_ot_desc + sizeof io_out_ot_desc,
+	.bmControls = 0,
+};
+
+/* Audio Streaming OUT Interface - Alt0 */
+static struct usb_interface_descriptor std_as_out_if0_desc = {
+	.bLength = sizeof std_as_out_if0_desc,
+	.bDescriptorType = USB_DT_INTERFACE,
+
+	.bAlternateSetting = 0,
+	.bNumEndpoints = 0,
+	.bInterfaceClass = USB_CLASS_AUDIO,
+	.bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+	.bInterfaceProtocol = UAC_VERSION_2,
+};
+
+/* Audio Streaming OUT Interface - Alt1 */
+static struct usb_interface_descriptor std_as_out_if1_desc = {
+	.bLength = sizeof std_as_out_if1_desc,
+	.bDescriptorType = USB_DT_INTERFACE,
+
+	.bAlternateSetting = 1,
+	.bNumEndpoints = 1,
+	.bInterfaceClass = USB_CLASS_AUDIO,
+	.bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+	.bInterfaceProtocol = UAC_VERSION_2,
+};
+
+/* Audio Stream OUT Intface Desc */
+struct uac2_as_header_descriptor as_out_hdr_desc = {
+	.bLength = sizeof as_out_hdr_desc,
+	.bDescriptorType = USB_DT_CS_INTERFACE,
+
+	.bDescriptorSubtype = UAC_AS_GENERAL,
+	.bTerminalLink = USB_OUT_IT_ID,
+	.bmControls = 0,
+	.bFormatType = UAC_FORMAT_TYPE_I,
+	.bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM),
+	.iChannelNames = 0,
+};
+
+/* Audio USB_OUT Format */
+struct uac2_format_type_i_descriptor as_out_fmt1_desc = {
+	.bLength = sizeof as_out_fmt1_desc,
+	.bDescriptorType = USB_DT_CS_INTERFACE,
+	.bDescriptorSubtype = UAC_FORMAT_TYPE,
+	.bFormatType = UAC_FORMAT_TYPE_I,
+};
+
+/* STD AS ISO OUT Endpoint */
+struct usb_endpoint_descriptor fs_epout_desc = {
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+
+	.bEndpointAddress = USB_DIR_OUT,
+	.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+	.bInterval = 1,
+};
+
+struct usb_endpoint_descriptor hs_epout_desc = {
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+
+	.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+	.bInterval = 4,
+};
+
+/* CS AS ISO OUT Endpoint */
+static struct uac2_iso_endpoint_descriptor as_iso_out_desc = {
+	.bLength = sizeof as_iso_out_desc,
+	.bDescriptorType = USB_DT_CS_ENDPOINT,
+
+	.bDescriptorSubtype = UAC_EP_GENERAL,
+	.bmAttributes = 0,
+	.bmControls = 0,
+	.bLockDelayUnits = 0,
+	.wLockDelay = 0,
+};
+
+/* Audio Streaming IN Interface - Alt0 */
+static struct usb_interface_descriptor std_as_in_if0_desc = {
+	.bLength = sizeof std_as_in_if0_desc,
+	.bDescriptorType = USB_DT_INTERFACE,
+
+	.bAlternateSetting = 0,
+	.bNumEndpoints = 0,
+	.bInterfaceClass = USB_CLASS_AUDIO,
+	.bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+	.bInterfaceProtocol = UAC_VERSION_2,
+};
+
+/* Audio Streaming IN Interface - Alt1 */
+static struct usb_interface_descriptor std_as_in_if1_desc = {
+	.bLength = sizeof std_as_in_if1_desc,
+	.bDescriptorType = USB_DT_INTERFACE,
+
+	.bAlternateSetting = 1,
+	.bNumEndpoints = 1,
+	.bInterfaceClass = USB_CLASS_AUDIO,
+	.bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+	.bInterfaceProtocol = UAC_VERSION_2,
+};
+
+/* Audio Stream IN Intface Desc */
+struct uac2_as_header_descriptor as_in_hdr_desc = {
+	.bLength = sizeof as_in_hdr_desc,
+	.bDescriptorType = USB_DT_CS_INTERFACE,
+
+	.bDescriptorSubtype = UAC_AS_GENERAL,
+	.bTerminalLink = USB_IN_OT_ID,
+	.bmControls = 0,
+	.bFormatType = UAC_FORMAT_TYPE_I,
+	.bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM),
+	.iChannelNames = 0,
+};
+
+/* Audio USB_IN Format */
+struct uac2_format_type_i_descriptor as_in_fmt1_desc = {
+	.bLength = sizeof as_in_fmt1_desc,
+	.bDescriptorType = USB_DT_CS_INTERFACE,
+	.bDescriptorSubtype = UAC_FORMAT_TYPE,
+	.bFormatType = UAC_FORMAT_TYPE_I,
+};
+
+/* STD AS ISO IN Endpoint */
+struct usb_endpoint_descriptor fs_epin_desc = {
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+	.bInterval = 1,
+};
+
+struct usb_endpoint_descriptor hs_epin_desc = {
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+
+	.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+	.bInterval = 4,
+};
+
+/* CS AS ISO IN Endpoint */
+static struct uac2_iso_endpoint_descriptor as_iso_in_desc = {
+	.bLength = sizeof as_iso_in_desc,
+	.bDescriptorType = USB_DT_CS_ENDPOINT,
+
+	.bDescriptorSubtype = UAC_EP_GENERAL,
+	.bmAttributes = 0,
+	.bmControls = 0,
+	.bLockDelayUnits = 0,
+	.wLockDelay = 0,
+};
+
+static struct usb_descriptor_header *fs_audio_desc[] = {
+	(struct usb_descriptor_header *)&iad_desc,
+	(struct usb_descriptor_header *)&std_ac_if_desc,
+
+	(struct usb_descriptor_header *)&ac_hdr_desc,
+	(struct usb_descriptor_header *)&in_clk_src_desc,
+	(struct usb_descriptor_header *)&out_clk_src_desc,
+	(struct usb_descriptor_header *)&usb_out_it_desc,
+	(struct usb_descriptor_header *)&io_in_it_desc,
+	(struct usb_descriptor_header *)&usb_in_ot_desc,
+	(struct usb_descriptor_header *)&io_out_ot_desc,
+
+	(struct usb_descriptor_header *)&std_as_out_if0_desc,
+	(struct usb_descriptor_header *)&std_as_out_if1_desc,
+
+	(struct usb_descriptor_header *)&as_out_hdr_desc,
+	(struct usb_descriptor_header *)&as_out_fmt1_desc,
+	(struct usb_descriptor_header *)&fs_epout_desc,
+	(struct usb_descriptor_header *)&as_iso_out_desc,
+
+	(struct usb_descriptor_header *)&std_as_in_if0_desc,
+	(struct usb_descriptor_header *)&std_as_in_if1_desc,
+
+	(struct usb_descriptor_header *)&as_in_hdr_desc,
+	(struct usb_descriptor_header *)&as_in_fmt1_desc,
+	(struct usb_descriptor_header *)&fs_epin_desc,
+	(struct usb_descriptor_header *)&as_iso_in_desc,
+	NULL,
+};
+
+static struct usb_descriptor_header *hs_audio_desc[] = {
+	(struct usb_descriptor_header *)&iad_desc,
+	(struct usb_descriptor_header *)&std_ac_if_desc,
+
+	(struct usb_descriptor_header *)&ac_hdr_desc,
+	(struct usb_descriptor_header *)&in_clk_src_desc,
+	(struct usb_descriptor_header *)&out_clk_src_desc,
+	(struct usb_descriptor_header *)&usb_out_it_desc,
+	(struct usb_descriptor_header *)&io_in_it_desc,
+	(struct usb_descriptor_header *)&usb_in_ot_desc,
+	(struct usb_descriptor_header *)&io_out_ot_desc,
+
+	(struct usb_descriptor_header *)&std_as_out_if0_desc,
+	(struct usb_descriptor_header *)&std_as_out_if1_desc,
+
+	(struct usb_descriptor_header *)&as_out_hdr_desc,
+	(struct usb_descriptor_header *)&as_out_fmt1_desc,
+	(struct usb_descriptor_header *)&hs_epout_desc,
+	(struct usb_descriptor_header *)&as_iso_out_desc,
+
+	(struct usb_descriptor_header *)&std_as_in_if0_desc,
+	(struct usb_descriptor_header *)&std_as_in_if1_desc,
+
+	(struct usb_descriptor_header *)&as_in_hdr_desc,
+	(struct usb_descriptor_header *)&as_in_fmt1_desc,
+	(struct usb_descriptor_header *)&hs_epin_desc,
+	(struct usb_descriptor_header *)&as_iso_in_desc,
+	NULL,
+};
+
+struct cntrl_cur_lay3 {
+	__u32	dCUR;
+};
+
+struct cntrl_range_lay3 {
+	__u16	wNumSubRanges;
+	__u32	dMIN;
+	__u32	dMAX;
+	__u32	dRES;
+} __packed;
+
+static inline void
+free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
+{
+	struct snd_uac2_chip *uac2 = prm_to_uac2(prm);
+	int i;
+
+	prm->ep_enabled = false;
+
+	for (i = 0; i < USB_XFERS; i++) {
+		if (prm->ureq[i].req) {
+			usb_ep_dequeue(ep, prm->ureq[i].req);
+			usb_ep_free_request(ep, prm->ureq[i].req);
+			prm->ureq[i].req = NULL;
+		}
+	}
+
+	if (usb_ep_disable(ep))
+		dev_err(&uac2->pdev.dev,
+			"%s:%d Error!\n", __func__, __LINE__);
+}
+
+static int __init
+afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
+{
+	struct audio_dev *agdev = func_to_agdev(fn);
+	struct snd_uac2_chip *uac2 = &agdev->uac2;
+	struct usb_composite_dev *cdev = cfg->cdev;
+	struct usb_gadget *gadget = cdev->gadget;
+	struct uac2_rtd_params *prm;
+	int ret;
+
+	ret = usb_interface_id(cfg, fn);
+	if (ret < 0) {
+		dev_err(&uac2->pdev.dev,
+			"%s:%d Error!\n", __func__, __LINE__);
+		return ret;
+	}
+	std_ac_if_desc.bInterfaceNumber = ret;
+	ALT_SET(agdev->ac_alt, 0);
+	INTF_SET(agdev->ac_alt, ret);
+
+	ret = usb_interface_id(cfg, fn);
+	if (ret < 0) {
+		dev_err(&uac2->pdev.dev,
+			"%s:%d Error!\n", __func__, __LINE__);
+		return ret;
+	}
+	std_as_out_if0_desc.bInterfaceNumber = ret;
+	std_as_out_if1_desc.bInterfaceNumber = ret;
+	ALT_SET(agdev->as_out_alt, 0);
+	INTF_SET(agdev->as_out_alt, ret);
+
+	ret = usb_interface_id(cfg, fn);
+	if (ret < 0) {
+		dev_err(&uac2->pdev.dev,
+			"%s:%d Error!\n", __func__, __LINE__);
+		return ret;
+	}
+	std_as_in_if0_desc.bInterfaceNumber = ret;
+	std_as_in_if1_desc.bInterfaceNumber = ret;
+	ALT_SET(agdev->as_in_alt, 0);
+	INTF_SET(agdev->as_in_alt, ret);
+
+	agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc);
+	if (!agdev->out_ep)
+		dev_err(&uac2->pdev.dev,
+			"%s:%d Error!\n", __func__, __LINE__);
+	agdev->out_ep->driver_data = agdev;
+
+	agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc);
+	if (!agdev->in_ep)
+		dev_err(&uac2->pdev.dev,
+			"%s:%d Error!\n", __func__, __LINE__);
+	agdev->in_ep->driver_data = agdev;
+
+	hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
+	hs_epout_desc.wMaxPacketSize = fs_epout_desc.wMaxPacketSize;
+	hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
+	hs_epin_desc.wMaxPacketSize = fs_epin_desc.wMaxPacketSize;
+
+	fn->descriptors = usb_copy_descriptors(fs_audio_desc);
+	if (gadget_is_dualspeed(gadget))
+		fn->hs_descriptors = usb_copy_descriptors(hs_audio_desc);
+
+	prm = &agdev->uac2.c_prm;
+	prm->max_psize = hs_epout_desc.wMaxPacketSize;
+	prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
+	if (!prm->rbuf) {
+		prm->max_psize = 0;
+		dev_err(&uac2->pdev.dev,
+			"%s:%d Error!\n", __func__, __LINE__);
+	}
+
+	prm = &agdev->uac2.p_prm;
+	prm->max_psize = hs_epin_desc.wMaxPacketSize;
+	prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
+	if (!prm->rbuf) {
+		prm->max_psize = 0;
+		dev_err(&uac2->pdev.dev,
+			"%s:%d Error!\n", __func__, __LINE__);
+	}
+
+	return alsa_uac2_init(agdev);
+}
+
+static void
+afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn)
+{
+	struct audio_dev *agdev = func_to_agdev(fn);
+	struct usb_composite_dev *cdev = cfg->cdev;
+	struct usb_gadget *gadget = cdev->gadget;
+	struct uac2_rtd_params *prm;
+
+	alsa_uac2_exit(agdev);
+
+	prm = &agdev->uac2.p_prm;
+	kfree(prm->rbuf);
+
+	prm = &agdev->uac2.c_prm;
+	kfree(prm->rbuf);
+
+	if (gadget_is_dualspeed(gadget))
+		usb_free_descriptors(fn->hs_descriptors);
+	usb_free_descriptors(fn->descriptors);
+
+	if (agdev->in_ep)
+		agdev->in_ep->driver_data = NULL;
+	if (agdev->out_ep)
+		agdev->out_ep->driver_data = NULL;
+}
+
+static int
+afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
+{
+	struct usb_composite_dev *cdev = fn->config->cdev;
+	struct audio_dev *agdev = func_to_agdev(fn);
+	struct snd_uac2_chip *uac2 = &agdev->uac2;
+	struct usb_gadget *gadget = cdev->gadget;
+	struct usb_request *req;
+	struct usb_ep *ep;
+	struct uac2_rtd_params *prm;
+	int i;
+
+	/* No i/f has more than 2 alt settings */
+	if (alt > 1) {
+		dev_err(&uac2->pdev.dev,
+			"%s:%d Error!\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (intf == INTF_GET(agdev->ac_alt)) {
+		/* Control I/f has only 1 AltSetting - 0 */
+		if (alt) {
+			dev_err(&uac2->pdev.dev,
+				"%s:%d Error!\n", __func__, __LINE__);
+			return -EINVAL;
+		}
+		return 0;
+	}
+
+	if (intf == INTF_GET(agdev->as_out_alt)) {
+		ep = agdev->out_ep;
+		prm = &uac2->c_prm;
+		config_ep_by_speed(gadget, fn, ep);
+		ALT_SET(agdev->as_out_alt, alt);
+	} else if (intf == INTF_GET(agdev->as_in_alt)) {
+		ep = agdev->in_ep;
+		prm = &uac2->p_prm;
+		config_ep_by_speed(gadget, fn, ep);
+		ALT_SET(agdev->as_in_alt, alt);
+	} else {
+		dev_err(&uac2->pdev.dev,
+			"%s:%d Error!\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (alt == 0) {
+		free_ep(prm, ep);
+		return 0;
+	}
+
+	prm->ep_enabled = true;
+	usb_ep_enable(ep);
+
+	for (i = 0; i < USB_XFERS; i++) {
+		if (prm->ureq[i].req) {
+			if (usb_ep_queue(ep, prm->ureq[i].req, GFP_ATOMIC))
+				dev_err(&uac2->pdev.dev, "%d Error!\n",
+					__LINE__);
+			continue;
+		}
+
+		req = usb_ep_alloc_request(ep, GFP_ATOMIC);
+		if (req == NULL) {
+			dev_err(&uac2->pdev.dev,
+				"%s:%d Error!\n", __func__, __LINE__);
+			return -EINVAL;
+		}
+
+		prm->ureq[i].req = req;
+		prm->ureq[i].pp = prm;
+
+		req->zero = 0;
+		req->dma = DMA_ADDR_INVALID;
+		req->context = &prm->ureq[i];
+		req->length = prm->max_psize;
+		req->complete =	agdev_iso_complete;
+		req->buf = prm->rbuf + i * req->length;
+
+		if (usb_ep_queue(ep, req, GFP_ATOMIC))
+			dev_err(&uac2->pdev.dev, "%d Error!\n", __LINE__);
+	}
+
+	return 0;
+}
+
+static int
+afunc_get_alt(struct usb_function *fn, unsigned intf)
+{
+	struct audio_dev *agdev = func_to_agdev(fn);
+	struct snd_uac2_chip *uac2 = &agdev->uac2;
+
+	if (intf == INTF_GET(agdev->ac_alt))
+		return ALT_GET(agdev->ac_alt);
+	else if (intf == INTF_GET(agdev->as_out_alt))
+		return ALT_GET(agdev->as_out_alt);
+	else if (intf == INTF_GET(agdev->as_in_alt))
+		return ALT_GET(agdev->as_in_alt);
+	else
+		dev_err(&uac2->pdev.dev,
+			"%s:%d Invalid Interface %d!\n",
+			__func__, __LINE__, intf);
+
+	return -EINVAL;
+}
+
+static void
+afunc_disable(struct usb_function *fn)
+{
+	struct audio_dev *agdev = func_to_agdev(fn);
+	struct snd_uac2_chip *uac2 = &agdev->uac2;
+
+	free_ep(&uac2->p_prm, agdev->in_ep);
+	ALT_SET(agdev->as_in_alt, 0);
+
+	free_ep(&uac2->c_prm, agdev->out_ep);
+	ALT_SET(agdev->as_out_alt, 0);
+}
+
+static int
+in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr)
+{
+	struct usb_request *req = fn->config->cdev->req;
+	struct audio_dev *agdev = func_to_agdev(fn);
+	struct snd_uac2_chip *uac2 = &agdev->uac2;
+	u16 w_length = le16_to_cpu(cr->wLength);
+	u16 w_index = le16_to_cpu(cr->wIndex);
+	u16 w_value = le16_to_cpu(cr->wValue);
+	u8 entity_id = (w_index >> 8) & 0xff;
+	u8 control_selector = w_value >> 8;
+	int value = -EOPNOTSUPP;
+
+	if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
+		struct cntrl_cur_lay3 c;
+
+		if (entity_id == USB_IN_CLK_ID)
+			c.dCUR = p_srate;
+		else if (entity_id == USB_OUT_CLK_ID)
+			c.dCUR = c_srate;
+
+		value = min_t(unsigned, w_length, sizeof c);
+		memcpy(req->buf, &c, value);
+	} else if (control_selector == UAC2_CS_CONTROL_CLOCK_VALID) {
+		*(u8 *)req->buf = 1;
+		value = min_t(unsigned, w_length, 1);
+	} else {
+		dev_err(&uac2->pdev.dev,
+			"%s:%d control_selector=%d TODO!\n",
+			__func__, __LINE__, control_selector);
+	}
+
+	return value;
+}
+
+static int
+in_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr)
+{
+	struct usb_request *req = fn->config->cdev->req;
+	struct audio_dev *agdev = func_to_agdev(fn);
+	struct snd_uac2_chip *uac2 = &agdev->uac2;
+	u16 w_length = le16_to_cpu(cr->wLength);
+	u16 w_index = le16_to_cpu(cr->wIndex);
+	u16 w_value = le16_to_cpu(cr->wValue);
+	u8 entity_id = (w_index >> 8) & 0xff;
+	u8 control_selector = w_value >> 8;
+	struct cntrl_range_lay3 r;
+	int value = -EOPNOTSUPP;
+
+	if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
+		if (entity_id == USB_IN_CLK_ID)
+			r.dMIN = p_srate;
+		else if (entity_id == USB_OUT_CLK_ID)
+			r.dMIN = c_srate;
+		else
+			return -EOPNOTSUPP;
+
+		r.dMAX = r.dMIN;
+		r.dRES = 0;
+		r.wNumSubRanges = 1;
+
+		value = min_t(unsigned, w_length, sizeof r);
+		memcpy(req->buf, &r, value);
+	} else {
+		dev_err(&uac2->pdev.dev,
+			"%s:%d control_selector=%d TODO!\n",
+			__func__, __LINE__, control_selector);
+	}
+
+	return value;
+}
+
+static int
+ac_rq_in(struct usb_function *fn, const struct usb_ctrlrequest *cr)
+{
+	if (cr->bRequest == UAC2_CS_CUR)
+		return in_rq_cur(fn, cr);
+	else if (cr->bRequest == UAC2_CS_RANGE)
+		return in_rq_range(fn, cr);
+	else
+		return -EOPNOTSUPP;
+}
+
+static int
+out_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr)
+{
+	u16 w_length = le16_to_cpu(cr->wLength);
+	u16 w_value = le16_to_cpu(cr->wValue);
+	u8 control_selector = w_value >> 8;
+
+	if (control_selector == UAC2_CS_CONTROL_SAM_FREQ)
+		return w_length;
+
+	return -EOPNOTSUPP;
+}
+
+static int
+setup_rq_inf(struct usb_function *fn, const struct usb_ctrlrequest *cr)
+{
+	struct audio_dev *agdev = func_to_agdev(fn);
+	struct snd_uac2_chip *uac2 = &agdev->uac2;
+	u16 w_index = le16_to_cpu(cr->wIndex);
+	u8 intf = w_index & 0xff;
+
+	if (intf != INTF_GET(agdev->ac_alt)) {
+		dev_err(&uac2->pdev.dev,
+			"%s:%d Error!\n", __func__, __LINE__);
+		return -EOPNOTSUPP;
+	}
+
+	if (cr->bRequestType & USB_DIR_IN)
+		return ac_rq_in(fn, cr);
+	else if (cr->bRequest == UAC2_CS_CUR)
+		return out_rq_cur(fn, cr);
+
+	return -EOPNOTSUPP;
+}
+
+static int
+afunc_setup(struct usb_function *fn, const struct usb_ctrlrequest *cr)
+{
+	struct usb_composite_dev *cdev = fn->config->cdev;
+	struct audio_dev *agdev = func_to_agdev(fn);
+	struct snd_uac2_chip *uac2 = &agdev->uac2;
+	struct usb_request *req = cdev->req;
+	u16 w_length = le16_to_cpu(cr->wLength);
+	int value = -EOPNOTSUPP;
+
+	/* Only Class specific requests are supposed to reach here */
+	if ((cr->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS)
+		return -EOPNOTSUPP;
+
+	if ((cr->bRequestType & USB_RECIP_MASK) == USB_RECIP_INTERFACE)
+		value = setup_rq_inf(fn, cr);
+	else
+		dev_err(&uac2->pdev.dev, "%s:%d Error!\n", __func__, __LINE__);
+
+	if (value >= 0) {
+		req->length = value;
+		req->zero = value < w_length;
+		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+		if (value < 0) {
+			dev_err(&uac2->pdev.dev,
+				"%s:%d Error!\n", __func__, __LINE__);
+			req->status = 0;
+		}
+	}
+
+	return value;
+}
+
+static int audio_bind_config(struct usb_configuration *cfg)
+{
+	int id, res;
+
+	agdev_g = kzalloc(sizeof *agdev_g, GFP_KERNEL);
+	if (agdev_g == NULL) {
+		printk(KERN_ERR "Unable to allocate audio gadget\n");
+		return -ENOMEM;
+	}
+
+	id = usb_string_id(cfg->cdev);
+	if (id < 0)
+		return id;
+
+	strings_fn[STR_ASSOC].id = id;
+	iad_desc.iFunction = id,
+
+	id = usb_string_id(cfg->cdev);
+	if (id < 0)
+		return id;
+
+	strings_fn[STR_IF_CTRL].id = id;
+	std_ac_if_desc.iInterface = id,
+
+	id = usb_string_id(cfg->cdev);
+	if (id < 0)
+		return id;
+
+	strings_fn[STR_CLKSRC_IN].id = id;
+	in_clk_src_desc.iClockSource = id,
+
+	id = usb_string_id(cfg->cdev);
+	if (id < 0)
+		return id;
+
+	strings_fn[STR_CLKSRC_OUT].id = id;
+	out_clk_src_desc.iClockSource = id,
+
+	id = usb_string_id(cfg->cdev);
+	if (id < 0)
+		return id;
+
+	strings_fn[STR_USB_IT].id = id;
+	usb_out_it_desc.iTerminal = id,
+
+	id = usb_string_id(cfg->cdev);
+	if (id < 0)
+		return id;
+
+	strings_fn[STR_IO_IT].id = id;
+	io_in_it_desc.iTerminal = id;
+
+	id = usb_string_id(cfg->cdev);
+	if (id < 0)
+		return id;
+
+	strings_fn[STR_USB_OT].id = id;
+	usb_in_ot_desc.iTerminal = id;
+
+	id = usb_string_id(cfg->cdev);
+	if (id < 0)
+		return id;
+
+	strings_fn[STR_IO_OT].id = id;
+	io_out_ot_desc.iTerminal = id;
+
+	id = usb_string_id(cfg->cdev);
+	if (id < 0)
+		return id;
+
+	strings_fn[STR_AS_OUT_ALT0].id = id;
+	std_as_out_if0_desc.iInterface = id;
+
+	id = usb_string_id(cfg->cdev);
+	if (id < 0)
+		return id;
+
+	strings_fn[STR_AS_OUT_ALT1].id = id;
+	std_as_out_if1_desc.iInterface = id;
+
+	id = usb_string_id(cfg->cdev);
+	if (id < 0)
+		return id;
+
+	strings_fn[STR_AS_IN_ALT0].id = id;
+	std_as_in_if0_desc.iInterface = id;
+
+	id = usb_string_id(cfg->cdev);
+	if (id < 0)
+		return id;
+
+	strings_fn[STR_AS_IN_ALT1].id = id;
+	std_as_in_if1_desc.iInterface = id;
+
+	agdev_g->func.name = "uac2_func";
+	agdev_g->func.strings = fn_strings;
+	agdev_g->func.bind = afunc_bind;
+	agdev_g->func.unbind = afunc_unbind;
+	agdev_g->func.set_alt = afunc_set_alt;
+	agdev_g->func.get_alt = afunc_get_alt;
+	agdev_g->func.disable = afunc_disable;
+	agdev_g->func.setup = afunc_setup;
+
+	/* Initialize the configurable parameters */
+	usb_out_it_desc.bNrChannels = num_channels(c_chmask);
+	usb_out_it_desc.bmChannelConfig = cpu_to_le32(c_chmask);
+	io_in_it_desc.bNrChannels = num_channels(p_chmask);
+	io_in_it_desc.bmChannelConfig = cpu_to_le32(p_chmask);
+	as_out_hdr_desc.bNrChannels = num_channels(c_chmask);
+	as_out_hdr_desc.bmChannelConfig = cpu_to_le32(c_chmask);
+	as_in_hdr_desc.bNrChannels = num_channels(p_chmask);
+	as_in_hdr_desc.bmChannelConfig = cpu_to_le32(p_chmask);
+	as_out_fmt1_desc.bSubslotSize = c_ssize;
+	as_out_fmt1_desc.bBitResolution = c_ssize * 8;
+	as_in_fmt1_desc.bSubslotSize = p_ssize;
+	as_in_fmt1_desc.bBitResolution = p_ssize * 8;
+
+	snprintf(clksrc_in, sizeof(clksrc_in), "%uHz", p_srate);
+	snprintf(clksrc_out, sizeof(clksrc_out), "%uHz", c_srate);
+
+	res = usb_add_function(cfg, &agdev_g->func);
+	if (res < 0)
+		kfree(agdev_g);
+
+	return res;
+}
+
+static void
+uac2_unbind_config(struct usb_configuration *cfg)
+{
+	kfree(agdev_g);
+	agdev_g = NULL;
+}
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 47766f0..4fac569 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -855,7 +855,7 @@
 	if (transport_is_bbb()) {
 		switch (ctrl->bRequest) {
 
-		case USB_BULK_RESET_REQUEST:
+		case US_BULK_RESET_REQUEST:
 			if (ctrl->bRequestType != (USB_DIR_OUT |
 					USB_TYPE_CLASS | USB_RECIP_INTERFACE))
 				break;
@@ -871,7 +871,7 @@
 			value = DELAYED_STATUS;
 			break;
 
-		case USB_BULK_GET_MAX_LUN_REQUEST:
+		case US_BULK_GET_MAX_LUN:
 			if (ctrl->bRequestType != (USB_DIR_IN |
 					USB_TYPE_CLASS | USB_RECIP_INTERFACE))
 				break;
@@ -2125,7 +2125,7 @@
 	struct fsg_lun		*curlun = fsg->curlun;
 	struct fsg_buffhd	*bh;
 	int			rc;
-	u8			status = USB_STATUS_PASS;
+	u8			status = US_BULK_STAT_OK;
 	u32			sd, sdinfo = 0;
 
 	/* Wait for the next buffer to become available */
@@ -2146,11 +2146,11 @@
 
 	if (fsg->phase_error) {
 		DBG(fsg, "sending phase-error status\n");
-		status = USB_STATUS_PHASE_ERROR;
+		status = US_BULK_STAT_PHASE;
 		sd = SS_INVALID_COMMAND;
 	} else if (sd != SS_NO_SENSE) {
 		DBG(fsg, "sending command-failure status\n");
-		status = USB_STATUS_FAIL;
+		status = US_BULK_STAT_FAIL;
 		VDBG(fsg, "  sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
 				"  info x%x\n",
 				SK(sd), ASC(sd), ASCQ(sd), sdinfo);
@@ -2160,12 +2160,12 @@
 		struct bulk_cs_wrap	*csw = bh->buf;
 
 		/* Store and send the Bulk-only CSW */
-		csw->Signature = cpu_to_le32(USB_BULK_CS_SIG);
+		csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
 		csw->Tag = fsg->tag;
 		csw->Residue = cpu_to_le32(fsg->residue);
 		csw->Status = status;
 
-		bh->inreq->length = USB_BULK_CS_WRAP_LEN;
+		bh->inreq->length = US_BULK_CS_WRAP_LEN;
 		bh->inreq->zero = 0;
 		start_transfer(fsg, fsg->bulk_in, bh->inreq,
 				&bh->inreq_busy, &bh->state);
@@ -2609,16 +2609,16 @@
 static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 {
 	struct usb_request		*req = bh->outreq;
-	struct fsg_bulk_cb_wrap	*cbw = req->buf;
+	struct bulk_cb_wrap	*cbw = req->buf;
 
 	/* Was this a real packet?  Should it be ignored? */
 	if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
 		return -EINVAL;
 
 	/* Is the CBW valid? */
-	if (req->actual != USB_BULK_CB_WRAP_LEN ||
+	if (req->actual != US_BULK_CB_WRAP_LEN ||
 			cbw->Signature != cpu_to_le32(
-				USB_BULK_CB_SIG)) {
+				US_BULK_CB_SIGN)) {
 		DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
 				req->actual,
 				le32_to_cpu(cbw->Signature));
@@ -2638,7 +2638,7 @@
 	}
 
 	/* Is the CBW meaningful? */
-	if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
+	if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
 			cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
 		DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
 				"cmdlen %u\n",
@@ -2656,7 +2656,7 @@
 	/* Save the command for later */
 	fsg->cmnd_size = cbw->Length;
 	memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size);
-	if (cbw->Flags & USB_BULK_IN_FLAG)
+	if (cbw->Flags & US_BULK_FLAG_IN)
 		fsg->data_dir = DATA_DIR_TO_HOST;
 	else
 		fsg->data_dir = DATA_DIR_FROM_HOST;
@@ -2685,7 +2685,7 @@
 		}
 
 		/* Queue a request to read a Bulk-only CBW */
-		set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
+		set_bulk_out_req_length(fsg, bh, US_BULK_CB_WRAP_LEN);
 		start_transfer(fsg, fsg->bulk_out, bh->outreq,
 				&bh->outreq_busy, &bh->state);
 
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index b95697c..877a2c4 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -1638,6 +1638,7 @@
 	/* Nuke all pending requests (does flush) */
 	nuke(ep, -ESHUTDOWN);
 	ep->desc = NULL;
+	ep->ep.desc = NULL;
 	ep->stopped = 1;
 	ep->tx_req = NULL;
 	qe_ep_reset(udc, ep->epnum);
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index b04712f..b30e21f 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -659,6 +659,7 @@
 	nuke(ep, -ESHUTDOWN);
 
 	ep->desc = NULL;
+	ep->ep.desc = NULL;
 	ep->stopped = 1;
 	spin_unlock_irqrestore(&udc->lock, flags);
 
@@ -768,7 +769,7 @@
  * @is_last: return flag if it is the last dTD of the request
  * return: pointer to the built dTD */
 static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
-		dma_addr_t *dma, int *is_last)
+		dma_addr_t *dma, int *is_last, gfp_t gfp_flags)
 {
 	u32 swap_temp;
 	struct ep_td_struct *dtd;
@@ -777,7 +778,7 @@
 	*length = min(req->req.length - req->req.actual,
 			(unsigned)EP_MAX_LENGTH_TRANSFER);
 
-	dtd = dma_pool_alloc(udc_controller->td_pool, GFP_KERNEL, dma);
+	dtd = dma_pool_alloc(udc_controller->td_pool, gfp_flags, dma);
 	if (dtd == NULL)
 		return dtd;
 
@@ -827,7 +828,7 @@
 }
 
 /* Generate dtd chain for a request */
-static int fsl_req_to_dtd(struct fsl_req *req)
+static int fsl_req_to_dtd(struct fsl_req *req, gfp_t gfp_flags)
 {
 	unsigned	count;
 	int		is_last;
@@ -836,7 +837,7 @@
 	dma_addr_t dma;
 
 	do {
-		dtd = fsl_build_dtd(req, &count, &dma, &is_last);
+		dtd = fsl_build_dtd(req, &count, &dma, &is_last, gfp_flags);
 		if (dtd == NULL)
 			return -ENOMEM;
 
@@ -910,13 +911,11 @@
 	req->req.actual = 0;
 	req->dtd_count = 0;
 
-	spin_lock_irqsave(&udc->lock, flags);
-
 	/* build dtds and push them to device queue */
-	if (!fsl_req_to_dtd(req)) {
+	if (!fsl_req_to_dtd(req, gfp_flags)) {
+		spin_lock_irqsave(&udc->lock, flags);
 		fsl_queue_td(ep, req);
 	} else {
-		spin_unlock_irqrestore(&udc->lock, flags);
 		return -ENOMEM;
 	}
 
@@ -1217,7 +1216,7 @@
 
 	udc = container_of(gadget, struct fsl_udc, gadget);
 	if (udc->transceiver)
-		return otg_set_power(udc->transceiver, mA);
+		return usb_phy_set_power(udc->transceiver, mA);
 	return -ENOTSUPP;
 }
 
@@ -1295,7 +1294,7 @@
 			ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 	req->mapped = 1;
 
-	if (fsl_req_to_dtd(req) == 0)
+	if (fsl_req_to_dtd(req, GFP_ATOMIC) == 0)
 		fsl_queue_td(ep, req);
 	else
 		return -ENOMEM;
@@ -1379,7 +1378,7 @@
 	req->mapped = 1;
 
 	/* prime the data phase */
-	if ((fsl_req_to_dtd(req) == 0))
+	if ((fsl_req_to_dtd(req, GFP_ATOMIC) == 0))
 		fsl_queue_td(ep, req);
 	else			/* no mem */
 		goto stall;
@@ -1966,7 +1965,8 @@
 
 		/* connect to bus through transceiver */
 		if (udc_controller->transceiver) {
-			retval = otg_set_peripheral(udc_controller->transceiver,
+			retval = otg_set_peripheral(
+					udc_controller->transceiver->otg,
 						    &udc_controller->gadget);
 			if (retval < 0) {
 				ERR("can't bind to transceiver\n");
@@ -2006,7 +2006,7 @@
 		return -EINVAL;
 
 	if (udc_controller->transceiver)
-		otg_set_peripheral(udc_controller->transceiver, NULL);
+		otg_set_peripheral(udc_controller->transceiver->otg, NULL);
 
 	/* stop DR, disable intr */
 	dr_controller_stop(udc_controller);
@@ -2430,7 +2430,7 @@
 
 #ifdef CONFIG_USB_OTG
 	if (pdata->operating_mode == FSL_USB2_DR_OTG) {
-		udc_controller->transceiver = otg_get_transceiver();
+		udc_controller->transceiver = usb_get_transceiver();
 		if (!udc_controller->transceiver) {
 			ERR("Can't find OTG driver!\n");
 			ret = -ENODEV;
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index f781f5d..e651469 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -471,7 +471,7 @@
 
 	struct usb_ctrlrequest local_setup_buff;
 	spinlock_t lock;
-	struct otg_transceiver *transceiver;
+	struct usb_phy *transceiver;
 	unsigned softconnect:1;
 	unsigned vbus_active:1;
 	unsigned stopped:1;
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index 0519d77..331cd67 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -2,7 +2,7 @@
  * g_ffs.c -- user mode file system API for USB composite function controllers
  *
  * Copyright (C) 2010 Samsung Electronics
- * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ * Author: Michal Nazarewicz <mina86@mina86.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
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 5af70fc..e1dfd32 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -235,6 +235,7 @@
 
 	ep->ep.maxpacket = MAX_FIFO_SIZE;
 	ep->desc = NULL;
+	ep->ep.desc = NULL;
 	ep->stopped = 1;
 	ep->irqs = 0;
 	ep->dma = 0;
@@ -310,12 +311,9 @@
 		status = req->req.status;
 
 	dev = ep->dev;
-	if (req->mapped) {
-		pci_unmap_single(dev->pdev, req->req.dma, req->req.length,
-			ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-		req->req.dma = DMA_ADDR_INVALID;
-		req->mapped = 0;
-	}
+
+	if (ep->dma)
+		usb_gadget_unmap_request(&dev->gadget, &req->req, ep->is_in);
 
 #ifndef USB_TRACE
 	if (status && status != -ESHUTDOWN)
@@ -736,10 +734,11 @@
 		return -EBUSY;
 
 	/* set up dma mapping in case the caller didn't */
-	if (ep->dma && _req->dma == DMA_ADDR_INVALID) {
-		_req->dma = pci_map_single(dev->pdev, _req->buf, _req->length,
-			ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-		req->mapped = 1;
+	if (ep->dma) {
+		status = usb_gadget_map_request(&dev->gadget, &req->req,
+				ep->is_in);
+		if (status)
+			return status;
 	}
 
 #ifdef USB_TRACE
diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c
index f888c3e..3493adf 100644
--- a/drivers/usb/gadget/hid.c
+++ b/drivers/usb/gadget/hid.c
@@ -60,9 +60,9 @@
 	/* .bDeviceClass =		USB_CLASS_COMM, */
 	/* .bDeviceSubClass =	0, */
 	/* .bDeviceProtocol =	0, */
-	.bDeviceClass =		0xEF,
-	.bDeviceSubClass =	2,
-	.bDeviceProtocol =	1,
+	.bDeviceClass =		USB_CLASS_PER_INTERFACE,
+	.bDeviceSubClass =	0,
+	.bDeviceProtocol =	0,
 	/* .bMaxPacketSize0 = f(hardware) */
 
 	/* Vendor and product id can be overridden by module parameters.  */
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index ae04266..4f18a0e 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -1043,6 +1043,8 @@
 // FIXME don't call this with the spinlock held ...
 				if (copy_to_user (buf, dev->req->buf, len))
 					retval = -EFAULT;
+				else
+					retval = len;
 				clean_req (dev->gadget->ep0, dev->req);
 				/* NOTE userspace can't yet choose to stall */
 			}
diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c
index e2293c1..edd52d9 100644
--- a/drivers/usb/gadget/langwell_udc.c
+++ b/drivers/usb/gadget/langwell_udc.c
@@ -401,16 +401,7 @@
 		dma_pool_free(dev->dtd_pool, curr_dtd, curr_dtd->dtd_dma);
 	}
 
-	if (req->mapped) {
-		dma_unmap_single(&dev->pdev->dev,
-			req->req.dma, req->req.length,
-			is_in(ep) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-		req->req.dma = DMA_ADDR_INVALID;
-		req->mapped = 0;
-	} else
-		dma_sync_single_for_cpu(&dev->pdev->dev, req->req.dma,
-				req->req.length,
-				is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+	usb_gadget_unmap_request(&dev->gadget, &req->req, is_in(ep));
 
 	if (status != -ESHUTDOWN)
 		dev_dbg(&dev->pdev->dev,
@@ -487,6 +478,7 @@
 	nuke(ep, -ESHUTDOWN);
 
 	ep->desc = NULL;
+	ep->ep.desc = NULL;
 	ep->stopped = 1;
 
 	spin_unlock_irqrestore(&dev->lock, flags);
@@ -749,7 +741,8 @@
 	struct langwell_ep	*ep;
 	struct langwell_udc	*dev;
 	unsigned long		flags;
-	int			is_iso = 0, zlflag = 0;
+	int			is_iso = 0;
+	int			ret;
 
 	/* always require a cpu-view buffer */
 	req = container_of(_req, struct langwell_request, req);
@@ -776,33 +769,10 @@
 	if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN))
 		return -ESHUTDOWN;
 
-	/* set up dma mapping in case the caller didn't */
-	if (_req->dma == DMA_ADDR_INVALID) {
-		/* WORKAROUND: WARN_ON(size == 0) */
-		if (_req->length == 0) {
-			dev_vdbg(&dev->pdev->dev, "req->length: 0->1\n");
-			zlflag = 1;
-			_req->length++;
-		}
-
-		_req->dma = dma_map_single(&dev->pdev->dev,
-				_req->buf, _req->length,
-				is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-		if (zlflag && (_req->length == 1)) {
-			dev_vdbg(&dev->pdev->dev, "req->length: 1->0\n");
-			zlflag = 0;
-			_req->length = 0;
-		}
-
-		req->mapped = 1;
-		dev_vdbg(&dev->pdev->dev, "req->mapped = 1\n");
-	} else {
-		dma_sync_single_for_device(&dev->pdev->dev,
-				_req->dma, _req->length,
-				is_in(ep) ?  DMA_TO_DEVICE : DMA_FROM_DEVICE);
-		req->mapped = 0;
-		dev_vdbg(&dev->pdev->dev, "req->mapped = 0\n");
-	}
+	/* set up dma mapping */
+	ret = usb_gadget_map_request(&dev->gadget, &req->req, is_in(ep));
+	if (ret)
+		return ret;
 
 	dev_dbg(&dev->pdev->dev,
 			"%s queue req %p, len %u, buf %p, dma 0x%08x\n",
@@ -1261,9 +1231,9 @@
 	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
 	if (dev->transceiver) {
-		dev_vdbg(&dev->pdev->dev, "otg_set_power\n");
+		dev_vdbg(&dev->pdev->dev, "usb_phy_set_power\n");
 		dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-		return otg_set_power(dev->transceiver, mA);
+		return usb_phy_set_power(dev->transceiver, mA);
 	}
 
 	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
@@ -1906,7 +1876,7 @@
 
 	/* unbind OTG transceiver */
 	if (dev->transceiver)
-		(void)otg_set_peripheral(dev->transceiver, 0);
+		(void)otg_set_peripheral(dev->transceiver->otg, 0);
 
 	/* disable interrupt and set controller to stop state */
 	langwell_udc_stop(dev);
diff --git a/drivers/usb/gadget/langwell_udc.h b/drivers/usb/gadget/langwell_udc.h
index d6e78ac..8c8087a 100644
--- a/drivers/usb/gadget/langwell_udc.h
+++ b/drivers/usb/gadget/langwell_udc.h
@@ -162,7 +162,7 @@
 	spinlock_t		lock;	/* device lock */
 	struct langwell_ep	*ep;
 	struct usb_gadget_driver	*driver;
-	struct otg_transceiver	*transceiver;
+	struct usb_phy		*transceiver;
 	u8			dev_addr;
 	u32			usb_state;
 	u32			resume_state;
diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
index e24f72f..1f376eb 100644
--- a/drivers/usb/gadget/mass_storage.c
+++ b/drivers/usb/gadget/mass_storage.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2003-2008 Alan Stern
  * Copyright (C) 2009 Samsung Electronics
- *                    Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ *                    Author: Michal Nazarewicz <mina86@mina86.com>
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index 7e7f515..c37fb33 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -4,7 +4,7 @@
  * Copyright (C) 2008 David Brownell
  * Copyright (C) 2008 Nokia Corporation
  * Copyright (C) 2009 Samsung Electronics
- * Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
+ * Author: Michal Nazarewicz (mina86@mina86.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
diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h
index 34aadfa..e2be951 100644
--- a/drivers/usb/gadget/mv_udc.h
+++ b/drivers/usb/gadget/mv_udc.h
@@ -217,7 +217,7 @@
 	struct work_struct	vbus_work;
 	struct workqueue_struct *qwork;
 
-	struct otg_transceiver	*transceiver;
+	struct usb_phy		*transceiver;
 
 	struct mv_usb_platform_data     *pdata;
 
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index f97e737..19bbe80 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -608,6 +608,7 @@
 	nuke(ep, -ESHUTDOWN);
 
 	ep->desc = NULL;
+	ep->ep.desc = NULL;
 	ep->stopped = 1;
 
 	spin_unlock_irqrestore(&udc->lock, flags);
@@ -771,8 +772,7 @@
 		udc->ep0_state = DATA_STATE_XMIT;
 
 	/* irq handler advances the queue */
-	if (req != NULL)
-		list_add_tail(&req->queue, &ep->queue);
+	list_add_tail(&req->queue, &ep->queue);
 	spin_unlock_irqrestore(&udc->lock, flags);
 
 	return 0;
@@ -1384,7 +1384,8 @@
 	}
 
 	if (udc->transceiver) {
-		retval = otg_set_peripheral(udc->transceiver, &udc->gadget);
+		retval = otg_set_peripheral(udc->transceiver->otg,
+					&udc->gadget);
 		if (retval) {
 			dev_err(&udc->dev->dev,
 				"unable to register peripheral to otg\n");
@@ -2181,7 +2182,7 @@
 
 #ifdef CONFIG_USB_OTG_UTILS
 	if (pdata->mode == MV_USB_MODE_OTG)
-		udc->transceiver = otg_get_transceiver();
+		udc->transceiver = usb_get_transceiver();
 #endif
 
 	udc->clknum = pdata->clknum;
diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c
index 7322d29..01ae56f 100644
--- a/drivers/usb/gadget/net2272.c
+++ b/drivers/usb/gadget/net2272.c
@@ -385,12 +385,9 @@
 		status = req->req.status;
 
 	dev = ep->dev;
-	if (use_dma && req->mapped) {
-		dma_unmap_single(dev->dev, req->req.dma, req->req.length,
-			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-		req->req.dma = DMA_ADDR_INVALID;
-		req->mapped = 0;
-	}
+	if (use_dma && ep->dma)
+		usb_gadget_unmap_request(&dev->gadget, &req->req,
+				ep->is_in);
 
 	if (status && status != -ESHUTDOWN)
 		dev_vdbg(dev->dev, "complete %s req %p stat %d len %u/%u buf %p\n",
@@ -850,10 +847,11 @@
 		return -ESHUTDOWN;
 
 	/* set up dma mapping in case the caller didn't */
-	if (use_dma && ep->dma && _req->dma == DMA_ADDR_INVALID) {
-		_req->dma = dma_map_single(dev->dev, _req->buf, _req->length,
-			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-		req->mapped = 1;
+	if (use_dma && ep->dma) {
+		status = usb_gadget_map_request(&dev->gadget, _req,
+				ep->is_in);
+		if (status)
+			return status;
 	}
 
 	dev_vdbg(dev->dev, "%s queue req %p, len %d buf %p dma %08llx %s\n",
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index cdedd13..a5ccabc 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -806,12 +806,8 @@
 		status = req->req.status;
 
 	dev = ep->dev;
-	if (req->mapped) {
-		pci_unmap_single (dev->pdev, req->req.dma, req->req.length,
-			ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-		req->req.dma = DMA_ADDR_INVALID;
-		req->mapped = 0;
-	}
+	if (ep->dma)
+		usb_gadget_unmap_request(&dev->gadget, &req->req, ep->is_in);
 
 	if (status && status != -ESHUTDOWN)
 		VDEBUG (dev, "complete %s req %p stat %d len %u/%u\n",
@@ -857,10 +853,13 @@
 		return -EOPNOTSUPP;
 
 	/* set up dma mapping in case the caller didn't */
-	if (ep->dma && _req->dma == DMA_ADDR_INVALID) {
-		_req->dma = pci_map_single (dev->pdev, _req->buf, _req->length,
-			ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-		req->mapped = 1;
+	if (ep->dma) {
+		int ret;
+
+		ret = usb_gadget_map_request(&dev->gadget, _req,
+				ep->is_in);
+		if (ret)
+			return ret;
 	}
 
 #if 0
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 576cd85..b44830d 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -251,6 +251,7 @@
 
 	spin_lock_irqsave(&ep->udc->lock, flags);
 	ep->desc = NULL;
+	ep->ep.desc = NULL;
 	nuke (ep, -ESHUTDOWN);
 	ep->ep.maxpacket = ep->maxpacket;
 	ep->has_dma = 0;
@@ -1213,7 +1214,7 @@
 	/* NOTE:  non-OTG systems may use SRP TOO... */
 	} else if (!(udc->devstat & UDC_ATT)) {
 		if (udc->transceiver)
-			retval = otg_start_srp(udc->transceiver);
+			retval = otg_start_srp(udc->transceiver->otg);
 	}
 	spin_unlock_irqrestore(&udc->lock, flags);
 
@@ -1345,7 +1346,7 @@
 
 	udc = container_of(gadget, struct omap_udc, gadget);
 	if (udc->transceiver)
-		return otg_set_power(udc->transceiver, mA);
+		return usb_phy_set_power(udc->transceiver, mA);
 	return -EOPNOTSUPP;
 }
 
@@ -1839,11 +1840,13 @@
 					spin_lock(&udc->lock);
 				}
 				if (udc->transceiver)
-					otg_set_suspend(udc->transceiver, 1);
+					usb_phy_set_suspend(
+							udc->transceiver, 1);
 			} else {
 				VDBG("resume\n");
 				if (udc->transceiver)
-					otg_set_suspend(udc->transceiver, 0);
+					usb_phy_set_suspend(
+							udc->transceiver, 0);
 				if (udc->gadget.speed == USB_SPEED_FULL
 						&& udc->driver->resume) {
 					spin_unlock(&udc->lock);
@@ -2154,7 +2157,8 @@
 
 	/* connect to bus through transceiver */
 	if (udc->transceiver) {
-		status = otg_set_peripheral(udc->transceiver, &udc->gadget);
+		status = otg_set_peripheral(udc->transceiver->otg,
+						&udc->gadget);
 		if (status < 0) {
 			ERR("can't bind to transceiver\n");
 			if (driver->unbind) {
@@ -2200,7 +2204,7 @@
 		omap_vbus_session(&udc->gadget, 0);
 
 	if (udc->transceiver)
-		(void) otg_set_peripheral(udc->transceiver, NULL);
+		(void) otg_set_peripheral(udc->transceiver->otg, NULL);
 	else
 		pullup_disable(udc);
 
@@ -2650,7 +2654,7 @@
 }
 
 static int __init
-omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
+omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
 {
 	unsigned	tmp, buf;
 
@@ -2790,7 +2794,7 @@
 {
 	int			status = -ENODEV;
 	int			hmc;
-	struct otg_transceiver	*xceiv = NULL;
+	struct usb_phy		*xceiv = NULL;
 	const char		*type = NULL;
 	struct omap_usb_config	*config = pdev->dev.platform_data;
 	struct clk		*dc_clk;
@@ -2863,7 +2867,7 @@
 		 * use it.  Except for OTG, we don't _need_ to talk to one;
 		 * but not having one probably means no VBUS detection.
 		 */
-		xceiv = otg_get_transceiver();
+		xceiv = usb_get_transceiver();
 		if (xceiv)
 			type = xceiv->label;
 		else if (config->otg) {
@@ -3009,7 +3013,7 @@
 
 cleanup0:
 	if (xceiv)
-		otg_put_transceiver(xceiv);
+		usb_put_transceiver(xceiv);
 
 	if (cpu_is_omap16xx() || cpu_is_omap24xx() || cpu_is_omap7xx()) {
 		clk_disable(hhc_clk);
@@ -3039,7 +3043,7 @@
 
 	pullup_disable(udc);
 	if (udc->transceiver) {
-		otg_put_transceiver(udc->transceiver);
+		usb_put_transceiver(udc->transceiver);
 		udc->transceiver = NULL;
 	}
 	omap_writew(0, UDC_SYSCON1);
diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h
index 29edc51..59d3b22 100644
--- a/drivers/usb/gadget/omap_udc.h
+++ b/drivers/usb/gadget/omap_udc.h
@@ -164,7 +164,7 @@
 	struct omap_ep			ep[32];
 	u16				devstat;
 	u16				clr_halt;
-	struct otg_transceiver		*transceiver;
+	struct usb_phy			*transceiver;
 	struct list_head		iso;
 	unsigned			softconnect:1;
 	unsigned			vbus_active:1;
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index a3fcaae..6530706 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -15,6 +15,14 @@
 #include <linux/interrupt.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+
+/* GPIO port for VBUS detecting */
+static int vbus_gpio_port = -1;		/* GPIO port number (-1:Not used) */
+
+#define PCH_VBUS_PERIOD		3000	/* VBUS polling period (msec) */
+#define PCH_VBUS_INTERVAL	10	/* VBUS polling interval (msec) */
 
 /* Address offset of Registers */
 #define UDC_EP_REG_SHIFT	0x20	/* Offset to next EP */
@@ -296,6 +304,21 @@
 };
 
 /**
+ * struct pch_vbus_gpio_data - Structure holding GPIO informaton
+ *					for detecting VBUS
+ * @port:		gpio port number
+ * @intr:		gpio interrupt number
+ * @irq_work_fall	Structure for WorkQueue
+ * @irq_work_rise	Structure for WorkQueue
+ */
+struct pch_vbus_gpio_data {
+	int			port;
+	int			intr;
+	struct work_struct	irq_work_fall;
+	struct work_struct	irq_work_rise;
+};
+
+/**
  * struct pch_udc_dev - Structure holding complete information
  *			of the PCH USB device
  * @gadget:		gadget driver data
@@ -311,6 +334,7 @@
  * @registered:		driver regsitered with system
  * @suspended:		driver in suspended state
  * @connected:		gadget driver associated
+ * @vbus_session:	required vbus_session state
  * @set_cfg_not_acked:	pending acknowledgement 4 setup
  * @waiting_zlp_ack:	pending acknowledgement 4 ZLP
  * @data_requests:	DMA pool for data requests
@@ -322,6 +346,7 @@
  * @base_addr:		for mapped device memory
  * @irq:		IRQ line for the device
  * @cfg_data:		current cfg, intf, and alt in use
+ * @vbus_gpio:		GPIO informaton for detecting VBUS
  */
 struct pch_udc_dev {
 	struct usb_gadget		gadget;
@@ -337,6 +362,7 @@
 			registered:1,
 			suspended:1,
 			connected:1,
+			vbus_session:1,
 			set_cfg_not_acked:1,
 			waiting_zlp_ack:1;
 	struct pci_pool		*data_requests;
@@ -347,7 +373,8 @@
 	unsigned long			phys_addr;
 	void __iomem			*base_addr;
 	unsigned			irq;
-	struct pch_udc_cfg_data	cfg_data;
+	struct pch_udc_cfg_data		cfg_data;
+	struct pch_vbus_gpio_data	vbus_gpio;
 };
 
 #define PCH_UDC_PCI_BAR			1
@@ -554,6 +581,29 @@
 }
 
 /**
+ * pch_udc_reconnect() - This API initializes usb device controller,
+ *						and clear the disconnect status.
+ * @dev:		Reference to pch_udc_regs structure
+ */
+static void pch_udc_init(struct pch_udc_dev *dev);
+static void pch_udc_reconnect(struct pch_udc_dev *dev)
+{
+	pch_udc_init(dev);
+
+	/* enable device interrupts */
+	/* pch_udc_enable_interrupts() */
+	pch_udc_bit_clr(dev, UDC_DEVIRQMSK_ADDR,
+			UDC_DEVINT_UR | UDC_DEVINT_ENUM);
+
+	/* Clear the disconnect */
+	pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
+	pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_SD);
+	mdelay(1);
+	/* Resume USB signalling */
+	pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
+}
+
+/**
  * pch_udc_vbus_session() - set or clearr the disconnect status.
  * @dev:	Reference to pch_udc_regs structure
  * @is_active:	Parameter specifying the action
@@ -563,10 +613,18 @@
 static inline void pch_udc_vbus_session(struct pch_udc_dev *dev,
 					  int is_active)
 {
-	if (is_active)
-		pch_udc_clear_disconnect(dev);
-	else
+	if (is_active) {
+		pch_udc_reconnect(dev);
+		dev->vbus_session = 1;
+	} else {
+		if (dev->driver && dev->driver->disconnect) {
+			spin_unlock(&dev->lock);
+			dev->driver->disconnect(&dev->gadget);
+			spin_lock(&dev->lock);
+		}
 		pch_udc_set_disconnect(dev);
+		dev->vbus_session = 0;
+	}
 }
 
 /**
@@ -1126,7 +1184,17 @@
 	if (!gadget)
 		return -EINVAL;
 	dev = container_of(gadget, struct pch_udc_dev, gadget);
-	pch_udc_vbus_session(dev, is_on);
+	if (is_on) {
+		pch_udc_reconnect(dev);
+	} else {
+		if (dev->driver && dev->driver->disconnect) {
+			spin_unlock(&dev->lock);
+			dev->driver->disconnect(&dev->gadget);
+			spin_lock(&dev->lock);
+		}
+		pch_udc_set_disconnect(dev);
+	}
+
 	return 0;
 }
 
@@ -1183,6 +1251,188 @@
 };
 
 /**
+ * pch_vbus_gpio_get_value() - This API gets value of GPIO port as VBUS status.
+ * @dev:	Reference to the driver structure
+ *
+ * Return value:
+ *	1: VBUS is high
+ *	0: VBUS is low
+ *     -1: It is not enable to detect VBUS using GPIO
+ */
+static int pch_vbus_gpio_get_value(struct pch_udc_dev *dev)
+{
+	int vbus = 0;
+
+	if (dev->vbus_gpio.port)
+		vbus = gpio_get_value(dev->vbus_gpio.port) ? 1 : 0;
+	else
+		vbus = -1;
+
+	return vbus;
+}
+
+/**
+ * pch_vbus_gpio_work_fall() - This API keeps watch on VBUS becoming Low.
+ *                             If VBUS is Low, disconnect is processed
+ * @irq_work:	Structure for WorkQueue
+ *
+ */
+static void pch_vbus_gpio_work_fall(struct work_struct *irq_work)
+{
+	struct pch_vbus_gpio_data *vbus_gpio = container_of(irq_work,
+		struct pch_vbus_gpio_data, irq_work_fall);
+	struct pch_udc_dev *dev =
+		container_of(vbus_gpio, struct pch_udc_dev, vbus_gpio);
+	int vbus_saved = -1;
+	int vbus;
+	int count;
+
+	if (!dev->vbus_gpio.port)
+		return;
+
+	for (count = 0; count < (PCH_VBUS_PERIOD / PCH_VBUS_INTERVAL);
+		count++) {
+		vbus = pch_vbus_gpio_get_value(dev);
+
+		if ((vbus_saved == vbus) && (vbus == 0)) {
+			dev_dbg(&dev->pdev->dev, "VBUS fell");
+			if (dev->driver
+				&& dev->driver->disconnect) {
+				dev->driver->disconnect(
+					&dev->gadget);
+			}
+			if (dev->vbus_gpio.intr)
+				pch_udc_init(dev);
+			else
+				pch_udc_reconnect(dev);
+			return;
+		}
+		vbus_saved = vbus;
+		mdelay(PCH_VBUS_INTERVAL);
+	}
+}
+
+/**
+ * pch_vbus_gpio_work_rise() - This API checks VBUS is High.
+ *                             If VBUS is High, connect is processed
+ * @irq_work:	Structure for WorkQueue
+ *
+ */
+static void pch_vbus_gpio_work_rise(struct work_struct *irq_work)
+{
+	struct pch_vbus_gpio_data *vbus_gpio = container_of(irq_work,
+		struct pch_vbus_gpio_data, irq_work_rise);
+	struct pch_udc_dev *dev =
+		container_of(vbus_gpio, struct pch_udc_dev, vbus_gpio);
+	int vbus;
+
+	if (!dev->vbus_gpio.port)
+		return;
+
+	mdelay(PCH_VBUS_INTERVAL);
+	vbus = pch_vbus_gpio_get_value(dev);
+
+	if (vbus == 1) {
+		dev_dbg(&dev->pdev->dev, "VBUS rose");
+		pch_udc_reconnect(dev);
+		return;
+	}
+}
+
+/**
+ * pch_vbus_gpio_irq() - IRQ handler for GPIO intrerrupt for changing VBUS
+ * @irq:	Interrupt request number
+ * @dev:	Reference to the device structure
+ *
+ * Return codes:
+ *	0: Success
+ *	-EINVAL: GPIO port is invalid or can't be initialized.
+ */
+static irqreturn_t pch_vbus_gpio_irq(int irq, void *data)
+{
+	struct pch_udc_dev *dev = (struct pch_udc_dev *)data;
+
+	if (!dev->vbus_gpio.port || !dev->vbus_gpio.intr)
+		return IRQ_NONE;
+
+	if (pch_vbus_gpio_get_value(dev))
+		schedule_work(&dev->vbus_gpio.irq_work_rise);
+	else
+		schedule_work(&dev->vbus_gpio.irq_work_fall);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * pch_vbus_gpio_init() - This API initializes GPIO port detecting VBUS.
+ * @dev:	Reference to the driver structure
+ * @vbus_gpio	Number of GPIO port to detect gpio
+ *
+ * Return codes:
+ *	0: Success
+ *	-EINVAL: GPIO port is invalid or can't be initialized.
+ */
+static int pch_vbus_gpio_init(struct pch_udc_dev *dev, int vbus_gpio_port)
+{
+	int err;
+	int irq_num = 0;
+
+	dev->vbus_gpio.port = 0;
+	dev->vbus_gpio.intr = 0;
+
+	if (vbus_gpio_port <= -1)
+		return -EINVAL;
+
+	err = gpio_is_valid(vbus_gpio_port);
+	if (!err) {
+		pr_err("%s: gpio port %d is invalid\n",
+			__func__, vbus_gpio_port);
+		return -EINVAL;
+	}
+
+	err = gpio_request(vbus_gpio_port, "pch_vbus");
+	if (err) {
+		pr_err("%s: can't request gpio port %d, err: %d\n",
+			__func__, vbus_gpio_port, err);
+		return -EINVAL;
+	}
+
+	dev->vbus_gpio.port = vbus_gpio_port;
+	gpio_direction_input(vbus_gpio_port);
+	INIT_WORK(&dev->vbus_gpio.irq_work_fall, pch_vbus_gpio_work_fall);
+
+	irq_num = gpio_to_irq(vbus_gpio_port);
+	if (irq_num > 0) {
+		irq_set_irq_type(irq_num, IRQ_TYPE_EDGE_BOTH);
+		err = request_irq(irq_num, pch_vbus_gpio_irq, 0,
+			"vbus_detect", dev);
+		if (!err) {
+			dev->vbus_gpio.intr = irq_num;
+			INIT_WORK(&dev->vbus_gpio.irq_work_rise,
+				pch_vbus_gpio_work_rise);
+		} else {
+			pr_err("%s: can't request irq %d, err: %d\n",
+				__func__, irq_num, err);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * pch_vbus_gpio_free() - This API frees resources of GPIO port
+ * @dev:	Reference to the driver structure
+ */
+static void pch_vbus_gpio_free(struct pch_udc_dev *dev)
+{
+	if (dev->vbus_gpio.intr)
+		free_irq(dev->vbus_gpio.intr, dev);
+
+	if (dev->vbus_gpio.port)
+		gpio_free(dev->vbus_gpio.port);
+}
+
+/**
  * complete_req() - This API is invoked from the driver when processing
  *			of a request is complete
  * @ep:		Reference to the endpoint structure
@@ -1493,6 +1743,7 @@
 	pch_udc_ep_disable(ep);
 	pch_udc_disable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
 	ep->desc = NULL;
+	ep->ep.desc = NULL;
 	INIT_LIST_HEAD(&ep->queue);
 	spin_unlock_irqrestore(&ep->dev->lock, iflags);
 	return 0;
@@ -2335,8 +2586,11 @@
 		/* Complete request queue */
 		empty_req_queue(ep);
 	}
-	if (dev->driver && dev->driver->disconnect)
+	if (dev->driver && dev->driver->disconnect) {
+		spin_unlock(&dev->lock);
 		dev->driver->disconnect(&dev->gadget);
+		spin_lock(&dev->lock);
+	}
 }
 
 /**
@@ -2371,6 +2625,11 @@
 	pch_udc_set_dma(dev, DMA_DIR_TX);
 	pch_udc_set_dma(dev, DMA_DIR_RX);
 	pch_udc_ep_set_rrdy(&(dev->ep[UDC_EP0OUT_IDX]));
+
+	/* enable device interrupts */
+	pch_udc_enable_interrupts(dev, UDC_DEVINT_UR | UDC_DEVINT_US |
+					UDC_DEVINT_ES | UDC_DEVINT_ENUM |
+					UDC_DEVINT_SI | UDC_DEVINT_SC);
 }
 
 /**
@@ -2459,12 +2718,18 @@
  */
 static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
 {
+	int vbus;
+
 	/* USB Reset Interrupt */
-	if (dev_intr & UDC_DEVINT_UR)
+	if (dev_intr & UDC_DEVINT_UR) {
 		pch_udc_svc_ur_interrupt(dev);
+		dev_dbg(&dev->pdev->dev, "USB_RESET\n");
+	}
 	/* Enumeration Done Interrupt */
-	if (dev_intr & UDC_DEVINT_ENUM)
+	if (dev_intr & UDC_DEVINT_ENUM) {
 		pch_udc_svc_enum_interrupt(dev);
+		dev_dbg(&dev->pdev->dev, "USB_ENUM\n");
+	}
 	/* Set Interface Interrupt */
 	if (dev_intr & UDC_DEVINT_SI)
 		pch_udc_svc_intf_interrupt(dev);
@@ -2472,8 +2737,30 @@
 	if (dev_intr & UDC_DEVINT_SC)
 		pch_udc_svc_cfg_interrupt(dev);
 	/* USB Suspend interrupt */
-	if (dev_intr & UDC_DEVINT_US)
+	if (dev_intr & UDC_DEVINT_US) {
+		if (dev->driver
+			&& dev->driver->suspend) {
+			spin_unlock(&dev->lock);
+			dev->driver->suspend(&dev->gadget);
+			spin_lock(&dev->lock);
+		}
+
+		vbus = pch_vbus_gpio_get_value(dev);
+		if ((dev->vbus_session == 0)
+			&& (vbus != 1)) {
+			if (dev->driver && dev->driver->disconnect) {
+				spin_unlock(&dev->lock);
+				dev->driver->disconnect(&dev->gadget);
+				spin_lock(&dev->lock);
+			}
+			pch_udc_reconnect(dev);
+		} else if ((dev->vbus_session == 0)
+			&& (vbus == 1)
+			&& !dev->vbus_gpio.intr)
+			schedule_work(&dev->vbus_gpio.irq_work_fall);
+
 		dev_dbg(&dev->pdev->dev, "USB_SUSPEND\n");
+	}
 	/* Clear the SOF interrupt, if enabled */
 	if (dev_intr & UDC_DEVINT_SOF)
 		dev_dbg(&dev->pdev->dev, "SOF\n");
@@ -2499,6 +2786,14 @@
 	dev_intr = pch_udc_read_device_interrupts(dev);
 	ep_intr = pch_udc_read_ep_interrupts(dev);
 
+	/* For a hot plug, this find that the controller is hung up. */
+	if (dev_intr == ep_intr)
+		if (dev_intr == pch_udc_readl(dev, UDC_DEVCFG_ADDR)) {
+			dev_dbg(&dev->pdev->dev, "UDC: Hung up\n");
+			/* The controller is reset */
+			pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR);
+			return IRQ_HANDLED;
+		}
 	if (dev_intr)
 		/* Clear device interrupts */
 		pch_udc_write_device_interrupts(dev, dev_intr);
@@ -2625,6 +2920,7 @@
 {
 	pch_udc_init(dev);
 	pch_udc_pcd_reinit(dev);
+	pch_vbus_gpio_init(dev, vbus_gpio_port);
 	return 0;
 }
 
@@ -2725,7 +3021,8 @@
 	pch_udc_setup_ep0(dev);
 
 	/* clear SD */
-	pch_udc_clear_disconnect(dev);
+	if ((pch_vbus_gpio_get_value(dev) != 0) || !dev->vbus_gpio.intr)
+		pch_udc_clear_disconnect(dev);
 
 	dev->connected = 1;
 	return 0;
@@ -2803,6 +3100,8 @@
 				 UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE);
 	kfree(dev->ep0out_buf);
 
+	pch_vbus_gpio_free(dev);
+
 	pch_udc_exit(dev);
 
 	if (dev->irq_registered)
@@ -2912,8 +3211,10 @@
 	}
 	pch_udc = dev;
 	/* initialize the hardware */
-	if (pch_udc_pcd_init(dev))
+	if (pch_udc_pcd_init(dev)) {
+		retval = -ENODEV;
 		goto finished;
+	}
 	if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME,
 			dev)) {
 		dev_err(&pdev->dev, "%s: request_irq(%d) fail\n", __func__,
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index dd47063..1b33634 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -283,6 +283,7 @@
 	pxa25x_ep_fifo_flush (_ep);
 
 	ep->desc = NULL;
+	ep->ep.desc = NULL;
 	ep->stopped = 1;
 
 	local_irq_restore(flags);
@@ -995,7 +996,7 @@
 	udc = container_of(_gadget, struct pxa25x_udc, gadget);
 
 	if (udc->transceiver)
-		return otg_set_power(udc->transceiver, mA);
+		return usb_phy_set_power(udc->transceiver, mA);
 	return -EOPNOTSUPP;
 }
 
@@ -1192,6 +1193,7 @@
 			list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
 
 		ep->desc = NULL;
+		ep->ep.desc = NULL;
 		ep->stopped = 0;
 		INIT_LIST_HEAD (&ep->queue);
 		ep->pio_irqs = 0;
@@ -1301,7 +1303,8 @@
 
 	/* connect to bus through transceiver */
 	if (dev->transceiver) {
-		retval = otg_set_peripheral(dev->transceiver, &dev->gadget);
+		retval = otg_set_peripheral(dev->transceiver->otg,
+						&dev->gadget);
 		if (retval) {
 			DMSG("can't bind to transceiver\n");
 			if (driver->unbind)
@@ -1360,7 +1363,7 @@
 	local_irq_enable();
 
 	if (dev->transceiver)
-		(void) otg_set_peripheral(dev->transceiver, NULL);
+		(void) otg_set_peripheral(dev->transceiver->otg, NULL);
 
 	driver->unbind(&dev->gadget);
 	dev->gadget.dev.driver = NULL;
@@ -2159,7 +2162,7 @@
 	dev->dev = &pdev->dev;
 	dev->mach = pdev->dev.platform_data;
 
-	dev->transceiver = otg_get_transceiver();
+	dev->transceiver = usb_get_transceiver();
 
 	if (gpio_is_valid(dev->mach->gpio_pullup)) {
 		if ((retval = gpio_request(dev->mach->gpio_pullup,
@@ -2238,7 +2241,7 @@
 		gpio_free(dev->mach->gpio_pullup);
  err_gpio_pullup:
 	if (dev->transceiver) {
-		otg_put_transceiver(dev->transceiver);
+		usb_put_transceiver(dev->transceiver);
 		dev->transceiver = NULL;
 	}
 	clk_put(dev->clk);
@@ -2280,7 +2283,7 @@
 	clk_put(dev->clk);
 
 	if (dev->transceiver) {
-		otg_put_transceiver(dev->transceiver);
+		usb_put_transceiver(dev->transceiver);
 		dev->transceiver = NULL;
 	}
 
diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/pxa25x_udc.h
index 8eaf4e4..893e917 100644
--- a/drivers/usb/gadget/pxa25x_udc.h
+++ b/drivers/usb/gadget/pxa25x_udc.h
@@ -119,7 +119,7 @@
 	struct device				*dev;
 	struct clk				*clk;
 	struct pxa2xx_udc_mach_info		*mach;
-	struct otg_transceiver			*transceiver;
+	struct usb_phy				*transceiver;
 	u64					dma_mask;
 	struct pxa25x_ep			ep [PXA_UDC_NUM_ENDPOINTS];
 
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index f4c44eb..98acb3a 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -1666,7 +1666,7 @@
 
 	udc = to_gadget_udc(_gadget);
 	if (udc->transceiver)
-		return otg_set_power(udc->transceiver, mA);
+		return usb_phy_set_power(udc->transceiver, mA);
 	return -EOPNOTSUPP;
 }
 
@@ -1835,7 +1835,8 @@
 		driver->driver.name);
 
 	if (udc->transceiver) {
-		retval = otg_set_peripheral(udc->transceiver, &udc->gadget);
+		retval = otg_set_peripheral(udc->transceiver->otg,
+						&udc->gadget);
 		if (retval) {
 			dev_err(udc->dev, "can't bind to transceiver\n");
 			goto transceiver_fail;
@@ -1908,7 +1909,7 @@
 		 driver->driver.name);
 
 	if (udc->transceiver)
-		return otg_set_peripheral(udc->transceiver, NULL);
+		return otg_set_peripheral(udc->transceiver->otg, NULL);
 	return 0;
 }
 
@@ -2463,7 +2464,7 @@
 
 	udc->dev = &pdev->dev;
 	udc->mach = pdev->dev.platform_data;
-	udc->transceiver = otg_get_transceiver();
+	udc->transceiver = usb_get_transceiver();
 
 	gpio = udc->mach->gpio_pullup;
 	if (gpio_is_valid(gpio)) {
@@ -2542,7 +2543,7 @@
 	if (gpio_is_valid(gpio))
 		gpio_free(gpio);
 
-	otg_put_transceiver(udc->transceiver);
+	usb_put_transceiver(udc->transceiver);
 
 	udc->transceiver = NULL;
 	platform_set_drvdata(_dev, NULL);
diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h
index 7f4e8f4..a1d268c 100644
--- a/drivers/usb/gadget/pxa27x_udc.h
+++ b/drivers/usb/gadget/pxa27x_udc.h
@@ -447,7 +447,7 @@
 	struct usb_gadget_driver		*driver;
 	struct device				*dev;
 	struct pxa2xx_udc_mach_info		*mach;
-	struct otg_transceiver			*transceiver;
+	struct usb_phy				*transceiver;
 
 	enum ep0_state				ep0state;
 	struct udc_stats			stats;
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index f5b8d21..c4401e7 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -663,11 +663,7 @@
 	ep->fifoctr = D0FIFOCTR;
 
 	/* dma mapping */
-	req->req.dma = dma_map_single(r8a66597_to_dev(ep->r8a66597),
-				req->req.buf, req->req.length,
-				dma->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-
-	return 0;
+	return usb_gadget_map_request(&r8a66597->gadget, &req->req, dma->dir);
 }
 
 static void sudmac_free_channel(struct r8a66597 *r8a66597,
@@ -677,9 +673,7 @@
 	if (!r8a66597_is_sudmac(r8a66597))
 		return;
 
-	dma_unmap_single(r8a66597_to_dev(ep->r8a66597),
-			 req->req.dma, req->req.length,
-			 ep->dma->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+	usb_gadget_unmap_request(&r8a66597->gadget, &req->req, ep->dma->dir);
 
 	r8a66597_bclr(r8a66597, DREQE, ep->fifosel);
 	r8a66597_change_curpipe(r8a66597, 0, 0, ep->fifosel);
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index df8661d..cef9b82 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -30,6 +30,7 @@
 #include <linux/prefetch.h>
 #include <linux/platform_data/s3c-hsudc.h>
 #include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
 
 #include <mach/regs-s3c2443-clock.h>
 
@@ -145,7 +146,7 @@
 	struct usb_gadget_driver *driver;
 	struct device *dev;
 	struct s3c24xx_hsudc_platdata *pd;
-	struct otg_transceiver *transceiver;
+	struct usb_phy *transceiver;
 	struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)];
 	spinlock_t lock;
 	void __iomem *regs;
@@ -759,7 +760,7 @@
 	unsigned long flags;
 	u32 ecr = 0;
 
-	hsep = container_of(_ep, struct s3c_hsudc_ep, ep);
+	hsep = our_ep(_ep);
 	if (!_ep || !desc || hsep->desc || _ep->name == ep0name
 		|| desc->bDescriptorType != USB_DT_ENDPOINT
 		|| hsep->bEndpointAddress != desc->bEndpointAddress
@@ -816,6 +817,7 @@
 	s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN);
 
 	hsep->desc = 0;
+	hsep->ep.desc = NULL;
 	hsep->stopped = 1;
 
 	spin_unlock_irqrestore(&hsudc->lock, flags);
@@ -853,7 +855,7 @@
 {
 	struct s3c_hsudc_req *hsreq;
 
-	hsreq = container_of(_req, struct s3c_hsudc_req, req);
+	hsreq = our_req(_req);
 	WARN_ON(!list_empty(&hsreq->queue));
 	kfree(hsreq);
 }
@@ -876,12 +878,12 @@
 	u32 offset;
 	u32 csr;
 
-	hsreq = container_of(_req, struct s3c_hsudc_req, req);
+	hsreq = our_req(_req);
 	if ((!_req || !_req->complete || !_req->buf ||
 		!list_empty(&hsreq->queue)))
 		return -EINVAL;
 
-	hsep = container_of(_ep, struct s3c_hsudc_ep, ep);
+	hsep = our_ep(_ep);
 	hsudc = hsep->dev;
 	if (!hsudc->driver || hsudc->gadget.speed == USB_SPEED_UNKNOWN)
 		return -ESHUTDOWN;
@@ -935,7 +937,7 @@
 	struct s3c_hsudc_req *hsreq;
 	unsigned long flags;
 
-	hsep = container_of(_ep, struct s3c_hsudc_ep, ep);
+	hsep = our_ep(_ep);
 	if (!_ep || hsep->ep.name == ep0name)
 		return -EINVAL;
 
@@ -1005,6 +1007,7 @@
 	hsep->ep.ops = &s3c_hsudc_ep_ops;
 	hsep->fifo = hsudc->regs + S3C_BR(epnum);
 	hsep->desc = 0;
+	hsep->ep.desc = NULL;
 	hsep->stopped = 0;
 	hsep->wedge = 0;
 
@@ -1166,7 +1169,8 @@
 
 	/* connect to bus through transceiver */
 	if (hsudc->transceiver) {
-		ret = otg_set_peripheral(hsudc->transceiver, &hsudc->gadget);
+		ret = otg_set_peripheral(hsudc->transceiver->otg,
+					&hsudc->gadget);
 		if (ret) {
 			dev_err(hsudc->dev, "%s: can't bind to transceiver\n",
 					hsudc->gadget.name);
@@ -1178,6 +1182,9 @@
 	dev_info(hsudc->dev, "bound driver %s\n", driver->driver.name);
 
 	s3c_hsudc_reconfig(hsudc);
+
+	pm_runtime_get_sync(hsudc->dev);
+
 	s3c_hsudc_init_phy();
 	if (hsudc->pd->gpio_init)
 		hsudc->pd->gpio_init();
@@ -1208,13 +1215,16 @@
 	hsudc->gadget.dev.driver = NULL;
 	hsudc->gadget.speed = USB_SPEED_UNKNOWN;
 	s3c_hsudc_uninit_phy();
+
+	pm_runtime_put(hsudc->dev);
+
 	if (hsudc->pd->gpio_uninit)
 		hsudc->pd->gpio_uninit();
 	s3c_hsudc_stop_activity(hsudc);
 	spin_unlock_irqrestore(&hsudc->lock, flags);
 
 	if (hsudc->transceiver)
-		(void) otg_set_peripheral(hsudc->transceiver, NULL);
+		(void) otg_set_peripheral(hsudc->transceiver->otg, NULL);
 
 	disable_irq(hsudc->irq);
 
@@ -1243,7 +1253,7 @@
 		return -ENODEV;
 
 	if (hsudc->transceiver)
-		return otg_set_power(hsudc->transceiver, mA);
+		return usb_phy_set_power(hsudc->transceiver, mA);
 
 	return -EOPNOTSUPP;
 }
@@ -1275,7 +1285,7 @@
 	hsudc->dev = dev;
 	hsudc->pd = pdev->dev.platform_data;
 
-	hsudc->transceiver = otg_get_transceiver();
+	hsudc->transceiver = usb_get_transceiver();
 
 	for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
 		hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
@@ -1362,6 +1372,8 @@
 	if (ret)
 		goto err_add_udc;
 
+	pm_runtime_enable(dev);
+
 	return 0;
 err_add_udc:
 	device_unregister(&hsudc->gadget.dev);
@@ -1377,7 +1389,7 @@
 	release_mem_region(res->start, resource_size(res));
 err_res:
 	if (hsudc->transceiver)
-		otg_put_transceiver(hsudc->transceiver);
+		usb_put_transceiver(hsudc->transceiver);
 
 	regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
 err_supplies:
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 3f87cb9..ab9c65e 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -1148,6 +1148,7 @@
 	dprintk(DEBUG_NORMAL, "ep_disable: %s\n", _ep->name);
 
 	ep->desc = NULL;
+	ep->ep.desc = NULL;
 	ep->halted = 1;
 
 	s3c2410_udc_nuke (ep->dev, ep, -ESHUTDOWN);
@@ -1630,6 +1631,7 @@
 
 		ep->dev = dev;
 		ep->desc = NULL;
+		ep->ep.desc = NULL;
 		ep->halted = 0;
 		INIT_LIST_HEAD (&ep->queue);
 	}
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index ad9e5b2..665c074 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -242,7 +242,7 @@
 	.name		= "g_serial",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
-	.max_speed	= USB_SPEED_HIGH,
+	.max_speed	= USB_SPEED_SUPER,
 };
 
 static int __init init(void)
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index 85ea14e..8081ca3 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2003-2008 Alan Stern
  * Copyeight (C) 2009 Samsung Electronics
- * Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
+ * Author: Michal Nazarewicz (mina86@mina86.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
@@ -145,48 +145,8 @@
 
 #endif /* DUMP_MSGS */
 
-
-
-
-
 /*-------------------------------------------------------------------------*/
 
-/* Bulk-only data structures */
-
-/* Command Block Wrapper */
-struct fsg_bulk_cb_wrap {
-	__le32	Signature;		/* Contains 'USBC' */
-	u32	Tag;			/* Unique per command id */
-	__le32	DataTransferLength;	/* Size of the data */
-	u8	Flags;			/* Direction in bit 7 */
-	u8	Lun;			/* LUN (normally 0) */
-	u8	Length;			/* Of the CDB, <= MAX_COMMAND_SIZE */
-	u8	CDB[16];		/* Command Data Block */
-};
-
-#define USB_BULK_CB_WRAP_LEN	31
-#define USB_BULK_CB_SIG		0x43425355	/* Spells out USBC */
-#define USB_BULK_IN_FLAG	0x80
-
-/* Command Status Wrapper */
-struct bulk_cs_wrap {
-	__le32	Signature;		/* Should = 'USBS' */
-	u32	Tag;			/* Same as original command */
-	__le32	Residue;		/* Amount not transferred */
-	u8	Status;			/* See below */
-};
-
-#define USB_BULK_CS_WRAP_LEN	13
-#define USB_BULK_CS_SIG		0x53425355	/* Spells out 'USBS' */
-#define USB_STATUS_PASS		0
-#define USB_STATUS_FAIL		1
-#define USB_STATUS_PHASE_ERROR	2
-
-/* Bulk-only class specific requests */
-#define USB_BULK_RESET_REQUEST		0xff
-#define USB_BULK_GET_MAX_LUN_REQUEST	0xfe
-
-
 /* CBI Interrupt data structure */
 struct interrupt_data {
 	u8	bType;
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 6597a68..6c23938 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -725,9 +725,6 @@
 	struct gs_port	*port;
 	int		status;
 
-	if (port_num < 0 || port_num >= n_ports)
-		return -ENXIO;
-
 	do {
 		mutex_lock(&ports[port_num].lock);
 		port = ports[port_num].port;
@@ -1087,7 +1084,6 @@
 	if (!gs_tty_driver)
 		return -ENOMEM;
 
-	gs_tty_driver->owner = THIS_MODULE;
 	gs_tty_driver->driver_name = "g_serial";
 	gs_tty_driver->name = PREFIX;
 	/* uses dynamically assigned dev_t values */
diff --git a/drivers/usb/gadget/u_audio.c b/drivers/usb/gadget/u_uac1.c
similarity index 98%
rename from drivers/usb/gadget/u_audio.c
rename to drivers/usb/gadget/u_uac1.c
index 59ffe1e..af98989 100644
--- a/drivers/usb/gadget/u_audio.c
+++ b/drivers/usb/gadget/u_uac1.c
@@ -1,5 +1,5 @@
 /*
- * u_audio.c -- ALSA audio utilities for Gadget stack
+ * u_uac1.c -- ALSA audio utilities for Gadget stack
  *
  * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
  * Copyright (C) 2008 Analog Devices, Inc
@@ -17,7 +17,7 @@
 #include <linux/random.h>
 #include <linux/syscalls.h>
 
-#include "u_audio.h"
+#include "u_uac1.h"
 
 /*
  * This component encapsulates the ALSA devices for USB audio gadget
diff --git a/drivers/usb/gadget/u_audio.h b/drivers/usb/gadget/u_uac1.h
similarity index 94%
rename from drivers/usb/gadget/u_audio.h
rename to drivers/usb/gadget/u_uac1.h
index 08ffce3..18c2e72 100644
--- a/drivers/usb/gadget/u_audio.h
+++ b/drivers/usb/gadget/u_uac1.h
@@ -1,5 +1,5 @@
 /*
- * u_audio.h -- interface to USB gadget "ALSA AUDIO" utilities
+ * u_uac1.h -- interface to USB gadget "ALSA AUDIO" utilities
  *
  * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
  * Copyright (C) 2008 Analog Devices, Inc
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index 0b0d12c..56da49f 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -22,6 +22,7 @@
 #include <linux/device.h>
 #include <linux/list.h>
 #include <linux/err.h>
+#include <linux/dma-mapping.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -49,6 +50,57 @@
 
 /* ------------------------------------------------------------------------- */
 
+int usb_gadget_map_request(struct usb_gadget *gadget,
+		struct usb_request *req, int is_in)
+{
+	if (req->length == 0)
+		return 0;
+
+	if (req->num_sgs) {
+		int     mapped;
+
+		mapped = dma_map_sg(&gadget->dev, req->sg, req->num_sgs,
+				is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		if (mapped == 0) {
+			dev_err(&gadget->dev, "failed to map SGs\n");
+			return -EFAULT;
+		}
+
+		req->num_mapped_sgs = mapped;
+	} else {
+		req->dma = dma_map_single(&gadget->dev, req->buf, req->length,
+				is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+		if (dma_mapping_error(&gadget->dev, req->dma)) {
+			dev_err(&gadget->dev, "failed to map buffer\n");
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_map_request);
+
+void usb_gadget_unmap_request(struct usb_gadget *gadget,
+		struct usb_request *req, int is_in)
+{
+	if (req->length == 0)
+		return;
+
+	if (req->num_mapped_sgs) {
+		dma_unmap_sg(&gadget->dev, req->sg, req->num_mapped_sgs,
+				is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+		req->num_mapped_sgs = 0;
+	} else {
+		dma_unmap_single(&gadget->dev, req->dma, req->length,
+				is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+	}
+}
+EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
+
+/* ------------------------------------------------------------------------- */
+
 /**
  * usb_gadget_start - tells usb device controller to start up
  * @gadget: The gadget we want to get started
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 353cdd4..f788eb8 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -27,6 +27,10 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called xhci-hcd.
 
+config USB_XHCI_PLATFORM
+	tristate
+	depends on USB_XHCI_HCD
+
 config USB_XHCI_HCD_DEBUGGING
 	bool "Debugging for the xHCI host controller"
 	depends on USB_XHCI_HCD
@@ -196,7 +200,7 @@
 
 config USB_EHCI_MV
 	bool "EHCI support for Marvell on-chip controller"
-	depends on USB_EHCI_HCD
+	depends on USB_EHCI_HCD && (ARCH_PXA || ARCH_MMP)
 	select USB_EHCI_ROOT_HUB_TT
 	---help---
 	  Enables support for Marvell (including PXA and MMP series) on-chip
@@ -218,11 +222,15 @@
 	  support.
 
 config USB_EHCI_ATH79
-	bool "EHCI support for AR7XXX/AR9XXX SoCs"
+	bool "EHCI support for AR7XXX/AR9XXX SoCs (DEPRECATED)"
 	depends on USB_EHCI_HCD && (SOC_AR71XX || SOC_AR724X || SOC_AR913X || SOC_AR933X)
 	select USB_EHCI_ROOT_HUB_TT
+	select USB_EHCI_HCD_PLATFORM
 	default y
 	---help---
+	  This option is deprecated now and the driver was removed, use
+	  USB_EHCI_HCD_PLATFORM instead.
+
 	  Enables support for the built-in EHCI controller present
 	  on the Atheros AR7XXX/AR9XXX SoCs.
 
@@ -312,10 +320,14 @@
 	  OMAP3 and later chips.
 
 config USB_OHCI_ATH79
-	bool "USB OHCI support for the Atheros AR71XX/AR7240 SoCs"
+	bool "USB OHCI support for the Atheros AR71XX/AR7240 SoCs (DEPRECATED)"
 	depends on USB_OHCI_HCD && (SOC_AR71XX || SOC_AR724X)
+	select USB_OHCI_HCD_PLATFORM
 	default y
 	help
+	  This option is deprecated now and the driver was removed, use
+	  USB_OHCI_HCD_PLATFORM instead.
+
 	  Enables support for the built-in OHCI controller present on the
 	  Atheros AR71XX/AR7240 SoCs.
 
@@ -393,6 +405,26 @@
 	  Enable support for the CNS3XXX SOC's on-chip OHCI controller.
 	  It is needed for low-speed USB 1.0 device support.
 
+config USB_OHCI_HCD_PLATFORM
+	bool "Generic OHCI driver for a platform device"
+	depends on USB_OHCI_HCD && EXPERIMENTAL
+	default n
+	---help---
+	  Adds an OHCI host driver for a generic platform device, which
+	  provieds a memory space and an irq.
+
+	  If unsure, say N.
+
+config USB_EHCI_HCD_PLATFORM
+	bool "Generic EHCI driver for a platform device"
+	depends on USB_EHCI_HCD && EXPERIMENTAL
+	default n
+	---help---
+	  Adds an EHCI host driver for a generic platform device, which
+	  provieds a memory space and an irq.
+
+	  If unsure, say N.
+
 config USB_OHCI_BIG_ENDIAN_DESC
 	bool
 	depends on USB_OHCI_HCD
@@ -606,10 +638,3 @@
 config USB_OCTEON2_COMMON
 	bool
 	default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI
-
-config USB_PXA168_EHCI
-	bool "Marvell PXA168 on-chip EHCI HCD support"
-	depends on USB_EHCI_HCD && ARCH_MMP
-	help
-	  Enable support for Marvell PXA168 SoC's on-chip EHCI
-	  host controller
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 7ca290f..0982bcc 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -15,6 +15,10 @@
 xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
 xhci-hcd-$(CONFIG_PCI)	+= xhci-pci.o
 
+ifneq ($(CONFIG_USB_XHCI_PLATFORM), )
+	xhci-hcd-y		+= xhci-plat.o
+endif
+
 obj-$(CONFIG_USB_WHCI_HCD)	+= whci/
 
 obj-$(CONFIG_PCI)		+= pci-quirks.o
diff --git a/drivers/usb/host/ehci-ath79.c b/drivers/usb/host/ehci-ath79.c
deleted file mode 100644
index f1424f9..0000000
--- a/drivers/usb/host/ehci-ath79.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- *  Bus Glue for Atheros AR7XXX/AR9XXX built-in EHCI controller.
- *
- *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
- *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
- *
- *  Parts of this file are based on Atheros' 2.6.15 BSP
- *	Copyright (C) 2007 Atheros 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.
- */
-
-#include <linux/platform_device.h>
-
-enum {
-	EHCI_ATH79_IP_V1 = 0,
-	EHCI_ATH79_IP_V2,
-};
-
-static const struct platform_device_id ehci_ath79_id_table[] = {
-	{
-		.name		= "ar71xx-ehci",
-		.driver_data	= EHCI_ATH79_IP_V1,
-	},
-	{
-		.name		= "ar724x-ehci",
-		.driver_data	= EHCI_ATH79_IP_V2,
-	},
-	{
-		.name		= "ar913x-ehci",
-		.driver_data	= EHCI_ATH79_IP_V2,
-	},
-	{
-		.name		= "ar933x-ehci",
-		.driver_data	= EHCI_ATH79_IP_V2,
-	},
-	{
-		/* terminating entry */
-	},
-};
-
-MODULE_DEVICE_TABLE(platform, ehci_ath79_id_table);
-
-static int ehci_ath79_init(struct usb_hcd *hcd)
-{
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-	struct platform_device *pdev = to_platform_device(hcd->self.controller);
-	const struct platform_device_id *id;
-	int ret;
-
-	id = platform_get_device_id(pdev);
-	if (!id) {
-		dev_err(hcd->self.controller, "missing device id\n");
-		return -EINVAL;
-	}
-
-	switch (id->driver_data) {
-	case EHCI_ATH79_IP_V1:
-		ehci->has_synopsys_hc_bug = 1;
-
-		ehci->caps = hcd->regs;
-		ehci->regs = hcd->regs +
-			HC_LENGTH(ehci,
-				  ehci_readl(ehci, &ehci->caps->hc_capbase));
-		break;
-
-	case EHCI_ATH79_IP_V2:
-		hcd->has_tt = 1;
-
-		ehci->caps = hcd->regs + 0x100;
-		ehci->regs = hcd->regs + 0x100 +
-			HC_LENGTH(ehci,
-				  ehci_readl(ehci, &ehci->caps->hc_capbase));
-		break;
-
-	default:
-		BUG();
-	}
-
-	dbg_hcs_params(ehci, "reset");
-	dbg_hcc_params(ehci, "reset");
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-	ehci->sbrn = 0x20;
-
-	ehci_reset(ehci);
-
-	ret = ehci_init(hcd);
-	if (ret)
-		return ret;
-
-	ehci_port_power(ehci, 0);
-
-	return 0;
-}
-
-static const struct hc_driver ehci_ath79_hc_driver = {
-	.description		= hcd_name,
-	.product_desc		= "Atheros built-in EHCI controller",
-	.hcd_priv_size		= sizeof(struct ehci_hcd),
-	.irq			= ehci_irq,
-	.flags			= HCD_MEMORY | HCD_USB2,
-
-	.reset			= ehci_ath79_init,
-	.start			= ehci_run,
-	.stop			= ehci_stop,
-	.shutdown		= ehci_shutdown,
-
-	.urb_enqueue		= ehci_urb_enqueue,
-	.urb_dequeue		= ehci_urb_dequeue,
-	.endpoint_disable	= ehci_endpoint_disable,
-	.endpoint_reset		= ehci_endpoint_reset,
-
-	.get_frame_number	= ehci_get_frame,
-
-	.hub_status_data	= ehci_hub_status_data,
-	.hub_control		= ehci_hub_control,
-
-	.relinquish_port	= ehci_relinquish_port,
-	.port_handed_over	= ehci_port_handed_over,
-
-	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-};
-
-static int ehci_ath79_probe(struct platform_device *pdev)
-{
-	struct usb_hcd *hcd;
-	struct resource *res;
-	int irq;
-	int ret;
-
-	if (usb_disabled())
-		return -ENODEV;
-
-	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (!res) {
-		dev_dbg(&pdev->dev, "no IRQ specified\n");
-		return -ENODEV;
-	}
-	irq = res->start;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_dbg(&pdev->dev, "no base address specified\n");
-		return -ENODEV;
-	}
-
-	hcd = usb_create_hcd(&ehci_ath79_hc_driver, &pdev->dev,
-			     dev_name(&pdev->dev));
-	if (!hcd)
-		return -ENOMEM;
-
-	hcd->rsrc_start	= res->start;
-	hcd->rsrc_len	= resource_size(res);
-
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		dev_dbg(&pdev->dev, "controller already in use\n");
-		ret = -EBUSY;
-		goto err_put_hcd;
-	}
-
-	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
-	if (!hcd->regs) {
-		dev_dbg(&pdev->dev, "error mapping memory\n");
-		ret = -EFAULT;
-		goto err_release_region;
-	}
-
-	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
-	if (ret)
-		goto err_iounmap;
-
-	return 0;
-
-err_iounmap:
-	iounmap(hcd->regs);
-
-err_release_region:
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_put_hcd:
-	usb_put_hcd(hcd);
-	return ret;
-}
-
-static int ehci_ath79_remove(struct platform_device *pdev)
-{
-	struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
-	usb_remove_hcd(hcd);
-	iounmap(hcd->regs);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-	usb_put_hcd(hcd);
-
-	return 0;
-}
-
-static struct platform_driver ehci_ath79_driver = {
-	.probe		= ehci_ath79_probe,
-	.remove		= ehci_ath79_remove,
-	.id_table	= ehci_ath79_id_table,
-	.driver = {
-		.owner	= THIS_MODULE,
-		.name	= "ath79-ehci",
-	}
-};
-
-MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ath79-ehci");
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index d6d74d2..fd9109d 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -107,7 +107,7 @@
 			HCC_PER_PORT_CHANGE_EVENT(params) ? " ppce" : "",
 			HCC_HW_PREFETCH(params) ? " hw prefetch" : "",
 			HCC_32FRAME_PERIODIC_LIST(params) ?
-				" 32 peridic list" : "");
+				" 32 periodic list" : "");
 	}
 }
 #else
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index b556a72..3e73451 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -142,12 +142,12 @@
 	if (pdata->operating_mode == FSL_USB2_DR_OTG) {
 		struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 
-		ehci->transceiver = otg_get_transceiver();
+		ehci->transceiver = usb_get_transceiver();
 		dev_dbg(&pdev->dev, "hcd=0x%p  ehci=0x%p, transceiver=0x%p\n",
 			hcd, ehci, ehci->transceiver);
 
 		if (ehci->transceiver) {
-			retval = otg_set_host(ehci->transceiver,
+			retval = otg_set_host(ehci->transceiver->otg,
 					      &ehci_to_hcd(ehci)->self);
 			if (retval) {
 				if (ehci->transceiver)
@@ -194,7 +194,7 @@
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 
 	if (ehci->transceiver) {
-		otg_set_host(ehci->transceiver, NULL);
+		otg_set_host(ehci->transceiver->otg, NULL);
 		put_device(ehci->transceiver->dev);
 	}
 
@@ -216,6 +216,8 @@
 			       unsigned int port_offset)
 {
 	u32 portsc;
+	struct usb_hcd *hcd = ehci_to_hcd(ehci);
+	void __iomem *non_ehci = hcd->regs;
 
 	portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
 	portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
@@ -231,6 +233,8 @@
 		portsc |= PORT_PTS_PTW;
 		/* fall through */
 	case FSL_USB2_PHY_UTMI:
+		/* enable UTMI PHY */
+		setbits32(non_ehci + FSL_SOC_USB_CTRL, CTRL_UTMI_PHY_EN);
 		portsc |= PORT_PTS_UTMI;
 		break;
 	case FSL_USB2_PHY_NONE:
@@ -252,22 +256,19 @@
 	if (pdata->have_sysif_regs) {
 		temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
 		out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
-		out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
+
+		/*
+		* Turn on cache snooping hardware, since some PowerPC platforms
+		* wholly rely on hardware to deal with cache coherent
+		*/
+
+		/* Setup Snooping for all the 4GB space */
+		/* SNOOP1 starts from 0x0, size 2G */
+		out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0 | SNOOP_SIZE_2GB);
+		/* SNOOP2 starts from 0x80000000, size 2G */
+		out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB);
 	}
 
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-	/*
-	 * Turn on cache snooping hardware, since some PowerPC platforms
-	 * wholly rely on hardware to deal with cache coherent
-	 */
-
-	/* Setup Snooping for all the 4GB space */
-	/* SNOOP1 starts from 0x0, size 2G */
-	out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0 | SNOOP_SIZE_2GB);
-	/* SNOOP2 starts from 0x80000000, size 2G */
-	out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB);
-#endif
-
 	if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
 			(pdata->operating_mode == FSL_USB2_DR_OTG))
 		ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
@@ -316,7 +317,9 @@
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	int retval;
 	struct fsl_usb2_platform_data *pdata;
+	struct device *dev;
 
+	dev = hcd->self.controller;
 	pdata = hcd->self.controller->platform_data;
 	ehci->big_endian_desc = pdata->big_endian_desc;
 	ehci->big_endian_mmio = pdata->big_endian_mmio;
@@ -346,6 +349,16 @@
 
 	ehci_reset(ehci);
 
+	if (of_device_is_compatible(dev->parent->of_node,
+				    "fsl,mpc5121-usb2-dr")) {
+		/*
+		 * set SBUSCFG:AHBBRST so that control msgs don't
+		 * fail when doing heavy PATA writes.
+		 */
+		ehci_writel(ehci, SBUSCFG_INCR8,
+			    hcd->regs + FSL_SOC_USB_SBUSCFG);
+	}
+
 	retval = ehci_fsl_reinit(ehci);
 	return retval;
 }
@@ -469,6 +482,8 @@
 	ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE,
 		    hcd->regs + FSL_SOC_USB_ISIPHYCTRL);
 
+	ehci_writel(ehci, SBUSCFG_INCR8, hcd->regs + FSL_SOC_USB_SBUSCFG);
+
 	/* restore EHCI registers */
 	ehci_writel(ehci, pdata->pm_command, &ehci->regs->command);
 	ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable);
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
index 4918062..863fb0c 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -19,6 +19,8 @@
 #define _EHCI_FSL_H
 
 /* offsets for the non-ehci registers in the FSL SOC USB controller */
+#define FSL_SOC_USB_SBUSCFG	0x90
+#define SBUSCFG_INCR8		0x02	/* INCR8, specified */
 #define FSL_SOC_USB_ULPIVP	0x170
 #define FSL_SOC_USB_PORTSC1	0x184
 #define PORT_PTS_MSK		(3<<30)
@@ -45,5 +47,7 @@
 #define FSL_SOC_USB_PRICTRL	0x40c	/* NOTE: big-endian */
 #define FSL_SOC_USB_SICTRL	0x410	/* NOTE: big-endian */
 #define FSL_SOC_USB_CTRL	0x500	/* NOTE: big-endian */
+#define CTRL_UTMI_PHY_EN	(1<<9)
+#define CTRL_PHY_CLK_VALID	(1 << 17)
 #define SNOOP_SIZE_2GB		0x1e
 #endif				/* _EHCI_FSL_H */
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index a007a9f..aede637 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1351,21 +1351,11 @@
 #define PLATFORM_DRIVER		s5p_ehci_driver
 #endif
 
-#ifdef CONFIG_USB_EHCI_ATH79
-#include "ehci-ath79.c"
-#define PLATFORM_DRIVER		ehci_ath79_driver
-#endif
-
 #ifdef CONFIG_SPARC_LEON
 #include "ehci-grlib.c"
 #define PLATFORM_DRIVER		ehci_grlib_driver
 #endif
 
-#ifdef CONFIG_USB_PXA168_EHCI
-#include "ehci-pxa168.c"
-#define PLATFORM_DRIVER		ehci_pxa168_driver
-#endif
-
 #ifdef CONFIG_CPU_XLR
 #include "ehci-xls.c"
 #define PLATFORM_DRIVER		ehci_xls_driver
@@ -1376,6 +1366,16 @@
 #define        PLATFORM_DRIVER         ehci_mv_driver
 #endif
 
+#ifdef CONFIG_MACH_LOONGSON1
+#include "ehci-ls1x.c"
+#define PLATFORM_DRIVER		ehci_ls1x_driver
+#endif
+
+#ifdef CONFIG_USB_EHCI_HCD_PLATFORM
+#include "ehci-platform.c"
+#define PLATFORM_DRIVER		ehci_platform_driver
+#endif
+
 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
     !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
     !defined(XILINX_OF_PLATFORM_DRIVER)
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 77bbb23..256fbd4 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -107,7 +107,7 @@
 	ehci->owned_ports = 0;
 }
 
-static int ehci_port_change(struct ehci_hcd *ehci)
+static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci)
 {
 	int i = HCS_N_PORTS(ehci->hcs_params);
 
@@ -727,7 +727,7 @@
 #ifdef CONFIG_USB_OTG
 			if ((hcd->self.otg_port == (wIndex + 1))
 			    && hcd->self.b_hnp_enable) {
-				otg_start_hnp(ehci->transceiver);
+				otg_start_hnp(ehci->transceiver->otg);
 				break;
 			}
 #endif
@@ -1076,7 +1076,8 @@
 	return retval;
 }
 
-static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)
+static void __maybe_unused ehci_relinquish_port(struct usb_hcd *hcd,
+		int portnum)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
 
@@ -1085,7 +1086,8 @@
 	set_owner(ehci, --portnum, PORT_OWNER);
 }
 
-static int ehci_port_handed_over(struct usb_hcd *hcd, int portnum)
+static int __maybe_unused ehci_port_handed_over(struct usb_hcd *hcd,
+		int portnum)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
 	u32 __iomem		*reg;
diff --git a/drivers/usb/host/ehci-ls1x.c b/drivers/usb/host/ehci-ls1x.c
new file mode 100644
index 0000000..a283e59
--- /dev/null
+++ b/drivers/usb/host/ehci-ls1x.c
@@ -0,0 +1,159 @@
+/*
+ *  Bus Glue for Loongson LS1X built-in EHCI controller.
+ *
+ *  Copyright (c) 2012 Zhang, Keguang <keguang.zhang@gmail.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.
+ */
+
+
+#include <linux/platform_device.h>
+
+static int ehci_ls1x_reset(struct usb_hcd *hcd)
+{
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	int ret;
+
+	ehci->caps = hcd->regs;
+
+	ret = ehci_setup(hcd);
+	if (ret)
+		return ret;
+
+	ehci_port_power(ehci, 0);
+
+	return 0;
+}
+
+static const struct hc_driver ehci_ls1x_hc_driver = {
+	.description		= hcd_name,
+	.product_desc		= "LOONGSON1 EHCI",
+	.hcd_priv_size		= sizeof(struct ehci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq			= ehci_irq,
+	.flags			= HCD_MEMORY | HCD_USB2,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset			= ehci_ls1x_reset,
+	.start			= ehci_run,
+	.stop			= ehci_stop,
+	.shutdown		= ehci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue		= ehci_urb_enqueue,
+	.urb_dequeue		= ehci_urb_dequeue,
+	.endpoint_disable	= ehci_endpoint_disable,
+	.endpoint_reset		= ehci_endpoint_reset,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number	= ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data	= ehci_hub_status_data,
+	.hub_control		= ehci_hub_control,
+	.relinquish_port	= ehci_relinquish_port,
+	.port_handed_over	= ehci_port_handed_over,
+
+	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,
+};
+
+static int ehci_hcd_ls1x_probe(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd;
+	struct resource *res;
+	int irq;
+	int ret;
+
+	pr_debug("initializing loongson1 ehci USB Controller\n");
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(&pdev->dev,
+			"Found HC with no IRQ. Check %s setup!\n",
+			dev_name(&pdev->dev));
+		return -ENODEV;
+	}
+	irq = res->start;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev,
+			"Found HC with no register addr. Check %s setup!\n",
+			dev_name(&pdev->dev));
+		return -ENODEV;
+	}
+
+	hcd = usb_create_hcd(&ehci_ls1x_hc_driver, &pdev->dev,
+				dev_name(&pdev->dev));
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start	= res->start;
+	hcd->rsrc_len	= resource_size(res);
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		dev_dbg(&pdev->dev, "controller already in use\n");
+		ret = -EBUSY;
+		goto err_put_hcd;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (hcd->regs == NULL) {
+		dev_dbg(&pdev->dev, "error mapping memory\n");
+		ret = -EFAULT;
+		goto err_release_region;
+	}
+
+	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+	if (ret)
+		goto err_iounmap;
+
+	return ret;
+
+err_iounmap:
+	iounmap(hcd->regs);
+err_release_region:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_put_hcd:
+	usb_put_hcd(hcd);
+	return ret;
+}
+
+static int ehci_hcd_ls1x_remove(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+
+	return 0;
+}
+
+static struct platform_driver ehci_ls1x_driver = {
+	.probe = ehci_hcd_ls1x_probe,
+	.remove = ehci_hcd_ls1x_remove,
+	.shutdown = usb_hcd_platform_shutdown,
+	.driver = {
+		.name = "ls1x-ehci",
+		.owner	= THIS_MODULE,
+	},
+};
+
+MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ls1x-ehci");
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 592d5f7..9803a55 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -32,7 +32,7 @@
 
 #define MSM_USB_BASE (hcd->regs)
 
-static struct otg_transceiver *otg;
+static struct usb_phy *phy;
 
 static int ehci_msm_reset(struct usb_hcd *hcd)
 {
@@ -145,14 +145,14 @@
 	 * powering up VBUS, mapping of registers address space and power
 	 * management.
 	 */
-	otg = otg_get_transceiver();
-	if (!otg) {
+	phy = usb_get_transceiver();
+	if (!phy) {
 		dev_err(&pdev->dev, "unable to find transceiver\n");
 		ret = -ENODEV;
 		goto unmap;
 	}
 
-	ret = otg_set_host(otg, &hcd->self);
+	ret = otg_set_host(phy->otg, &hcd->self);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "unable to register with transceiver\n");
 		goto put_transceiver;
@@ -169,7 +169,7 @@
 	return 0;
 
 put_transceiver:
-	otg_put_transceiver(otg);
+	usb_put_transceiver(phy);
 unmap:
 	iounmap(hcd->regs);
 put_hcd:
@@ -186,8 +186,8 @@
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
 
-	otg_set_host(otg, NULL);
-	otg_put_transceiver(otg);
+	otg_set_host(phy->otg, NULL);
+	usb_put_transceiver(phy);
 
 	usb_put_hcd(hcd);
 
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index 52a604f..a936bbc 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -28,7 +28,7 @@
 	void __iomem *cap_regs;
 	void __iomem *op_regs;
 
-	struct otg_transceiver *otg;
+	struct usb_phy *otg;
 
 	struct mv_usb_platform_data *pdata;
 
@@ -253,7 +253,7 @@
 	ehci_mv->mode = pdata->mode;
 	if (ehci_mv->mode == MV_USB_MODE_OTG) {
 #ifdef CONFIG_USB_OTG_UTILS
-		ehci_mv->otg = otg_get_transceiver();
+		ehci_mv->otg = usb_get_transceiver();
 		if (!ehci_mv->otg) {
 			dev_err(&pdev->dev,
 				"unable to find transceiver\n");
@@ -261,7 +261,7 @@
 			goto err_disable_clk;
 		}
 
-		retval = otg_set_host(ehci_mv->otg, &hcd->self);
+		retval = otg_set_host(ehci_mv->otg->otg, &hcd->self);
 		if (retval < 0) {
 			dev_err(&pdev->dev,
 				"unable to register with transceiver\n");
@@ -303,7 +303,7 @@
 #ifdef CONFIG_USB_OTG_UTILS
 err_put_transceiver:
 	if (ehci_mv->otg)
-		otg_put_transceiver(ehci_mv->otg);
+		usb_put_transceiver(ehci_mv->otg);
 #endif
 err_disable_clk:
 	mv_ehci_disable(ehci_mv);
@@ -332,8 +332,8 @@
 		usb_remove_hcd(hcd);
 
 	if (ehci_mv->otg) {
-		otg_set_host(ehci_mv->otg, NULL);
-		otg_put_transceiver(ehci_mv->otg);
+		otg_set_host(ehci_mv->otg->otg, NULL);
+		usb_put_transceiver(ehci_mv->otg);
 	}
 
 	if (ehci_mv->mode == MV_USB_MODE_HOST) {
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index 55978fc..a797d51 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -220,13 +220,13 @@
 	/* Initialize the transceiver */
 	if (pdata->otg) {
 		pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;
-		ret = otg_init(pdata->otg);
+		ret = usb_phy_init(pdata->otg);
 		if (ret) {
 			dev_err(dev, "unable to init transceiver, probably missing\n");
 			ret = -ENODEV;
 			goto err_add;
 		}
-		ret = otg_set_vbus(pdata->otg, 1);
+		ret = otg_set_vbus(pdata->otg->otg, 1);
 		if (ret) {
 			dev_err(dev, "unable to enable vbus on transceiver\n");
 			goto err_add;
@@ -247,9 +247,11 @@
 		 * It's in violation of USB specs
 		 */
 		if (machine_is_mx51_efikamx() || machine_is_mx51_efikasb()) {
-			flags = otg_io_read(pdata->otg, ULPI_OTG_CTRL);
+			flags = usb_phy_io_read(pdata->otg,
+							ULPI_OTG_CTRL);
 			flags |= ULPI_OTG_CTRL_CHRGVBUS;
-			ret = otg_io_write(pdata->otg, flags, ULPI_OTG_CTRL);
+			ret = usb_phy_io_write(pdata->otg, flags,
+							ULPI_OTG_CTRL);
 			if (ret) {
 				dev_err(dev, "unable to set CHRVBUS\n");
 				goto err_add;
@@ -297,7 +299,7 @@
 		pdata->exit(pdev);
 
 	if (pdata->otg)
-		otg_shutdown(pdata->otg);
+		usb_phy_shutdown(pdata->otg);
 
 	usb_remove_hcd(hcd);
 	iounmap(hcd->regs);
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
new file mode 100644
index 0000000..d238b4e2
--- /dev/null
+++ b/drivers/usb/host/ehci-platform.c
@@ -0,0 +1,198 @@
+/*
+ * Generic platform ehci driver
+ *
+ * Copyright 2007 Steven Brown <sbrown@cortland.com>
+ * Copyright 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Derived from the ohci-ssb driver
+ * Copyright 2007 Michael Buesch <m@bues.ch>
+ *
+ * Derived from the EHCI-PCI driver
+ * Copyright (c) 2000-2004 by David Brownell
+ *
+ * Derived from the ohci-pci driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/platform_device.h>
+#include <linux/usb/ehci_pdriver.h>
+
+static int ehci_platform_reset(struct usb_hcd *hcd)
+{
+	struct platform_device *pdev = to_platform_device(hcd->self.controller);
+	struct usb_ehci_pdata *pdata = pdev->dev.platform_data;
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	int retval;
+
+	hcd->has_tt = pdata->has_tt;
+	ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug;
+	ehci->big_endian_desc = pdata->big_endian_desc;
+	ehci->big_endian_mmio = pdata->big_endian_mmio;
+
+	ehci->caps = hcd->regs + pdata->caps_offset;
+	retval = ehci_setup(hcd);
+	if (retval)
+		return retval;
+
+	if (pdata->port_power_on)
+		ehci_port_power(ehci, 1);
+	if (pdata->port_power_off)
+		ehci_port_power(ehci, 0);
+
+	return 0;
+}
+
+static const struct hc_driver ehci_platform_hc_driver = {
+	.description		= hcd_name,
+	.product_desc		= "Generic Platform EHCI Controller",
+	.hcd_priv_size		= sizeof(struct ehci_hcd),
+
+	.irq			= ehci_irq,
+	.flags			= HCD_MEMORY | HCD_USB2,
+
+	.reset			= ehci_platform_reset,
+	.start			= ehci_run,
+	.stop			= ehci_stop,
+	.shutdown		= ehci_shutdown,
+
+	.urb_enqueue		= ehci_urb_enqueue,
+	.urb_dequeue		= ehci_urb_dequeue,
+	.endpoint_disable	= ehci_endpoint_disable,
+	.endpoint_reset		= ehci_endpoint_reset,
+
+	.get_frame_number	= ehci_get_frame,
+
+	.hub_status_data	= ehci_hub_status_data,
+	.hub_control		= ehci_hub_control,
+#if defined(CONFIG_PM)
+	.bus_suspend		= ehci_bus_suspend,
+	.bus_resume		= ehci_bus_resume,
+#endif
+	.relinquish_port	= ehci_relinquish_port,
+	.port_handed_over	= ehci_port_handed_over,
+
+	.update_device		= ehci_update_device,
+
+	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static int __devinit ehci_platform_probe(struct platform_device *dev)
+{
+	struct usb_hcd *hcd;
+	struct resource *res_mem;
+	int irq;
+	int err = -ENOMEM;
+
+	BUG_ON(!dev->dev.platform_data);
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	irq = platform_get_irq(dev, 0);
+	if (irq < 0) {
+		pr_err("no irq provieded");
+		return irq;
+	}
+	res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	if (!res_mem) {
+		pr_err("no memory recourse provieded");
+		return -ENXIO;
+	}
+
+	hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
+			     dev_name(&dev->dev));
+	if (!hcd)
+		return -ENOMEM;
+
+	hcd->rsrc_start = res_mem->start;
+	hcd->rsrc_len = resource_size(res_mem);
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_err("controller already in use");
+		err = -EBUSY;
+		goto err_put_hcd;
+	}
+
+	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs)
+		goto err_release_region;
+	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
+	if (err)
+		goto err_iounmap;
+
+	platform_set_drvdata(dev, hcd);
+
+	return err;
+
+err_iounmap:
+	iounmap(hcd->regs);
+err_release_region:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_put_hcd:
+	usb_put_hcd(hcd);
+	return err;
+}
+
+static int __devexit ehci_platform_remove(struct platform_device *dev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(dev);
+
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+	platform_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int ehci_platform_suspend(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	bool wakeup = device_may_wakeup(dev);
+
+	ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), wakeup);
+	return 0;
+}
+
+static int ehci_platform_resume(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
+	return 0;
+}
+
+#else /* !CONFIG_PM */
+#define ehci_platform_suspend	NULL
+#define ehci_platform_resume	NULL
+#endif /* CONFIG_PM */
+
+static const struct platform_device_id ehci_platform_table[] = {
+	{ "ehci-platform", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, ehci_platform_table);
+
+static const struct dev_pm_ops ehci_platform_pm_ops = {
+	.suspend	= ehci_platform_suspend,
+	.resume		= ehci_platform_resume,
+};
+
+static struct platform_driver ehci_platform_driver = {
+	.id_table	= ehci_platform_table,
+	.probe		= ehci_platform_probe,
+	.remove		= __devexit_p(ehci_platform_remove),
+	.shutdown	= usb_hcd_platform_shutdown,
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "ehci-platform",
+		.pm	= &ehci_platform_pm_ops,
+	}
+};
diff --git a/drivers/usb/host/ehci-pxa168.c b/drivers/usb/host/ehci-pxa168.c
deleted file mode 100644
index 8d0e7a2..0000000
--- a/drivers/usb/host/ehci-pxa168.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * drivers/usb/host/ehci-pxa168.c
- *
- * Tanmay Upadhyay <tanmay.upadhyay@einfochips.com>
- *
- * Based on drivers/usb/host/ehci-orion.c
- *
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <mach/pxa168.h>
-
-#define USB_PHY_CTRL_REG 0x4
-#define USB_PHY_PLL_REG  0x8
-#define USB_PHY_TX_REG   0xc
-
-#define FBDIV_SHIFT      4
-
-#define ICP_SHIFT        12
-#define ICP_15            2
-#define ICP_20            3
-#define ICP_25            4
-
-#define KVCO_SHIFT       15
-
-#define PLLCALI12_SHIFT  25
-#define CALI12_VDD        0
-#define CALI12_09         1
-#define CALI12_10         2
-#define CALI12_11         3
-
-#define PLLVDD12_SHIFT   27
-#define VDD12_VDD         0
-#define VDD12_10          1
-#define VDD12_11          2
-#define VDD12_12          3
-
-#define PLLVDD18_SHIFT   29
-#define VDD18_19          0
-#define VDD18_20          1
-#define VDD18_21          2
-#define VDD18_22          3
-
-
-#define PLL_READY        (1 << 23)
-#define VCOCAL_START     (1 << 21)
-#define REG_RCAL_START   (1 << 12)
-
-struct pxa168_usb_drv_data {
-	struct ehci_hcd ehci;
-	struct clk	*pxa168_usb_clk;
-	struct resource	*usb_phy_res;
-	void __iomem	*usb_phy_reg_base;
-};
-
-static int ehci_pxa168_setup(struct usb_hcd *hcd)
-{
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-	int retval;
-
-	ehci_reset(ehci);
-	retval = ehci_halt(ehci);
-	if (retval)
-		return retval;
-
-	/*
-	 * data structure init
-	 */
-	retval = ehci_init(hcd);
-	if (retval)
-		return retval;
-
-	hcd->has_tt = 1;
-
-	ehci_port_power(ehci, 0);
-
-	return retval;
-}
-
-static const struct hc_driver ehci_pxa168_hc_driver = {
-	.description = hcd_name,
-	.product_desc = "Marvell PXA168 EHCI",
-	.hcd_priv_size = sizeof(struct pxa168_usb_drv_data),
-
-	/*
-	 * generic hardware linkage
-	 */
-	.irq = ehci_irq,
-	.flags = HCD_MEMORY | HCD_USB2,
-
-	/*
-	 * basic lifecycle operations
-	 */
-	.reset = ehci_pxa168_setup,
-	.start = ehci_run,
-	.stop = ehci_stop,
-	.shutdown = ehci_shutdown,
-
-	/*
-	 * managing i/o requests and associated device resources
-	 */
-	.urb_enqueue = ehci_urb_enqueue,
-	.urb_dequeue = ehci_urb_dequeue,
-	.endpoint_disable = ehci_endpoint_disable,
-	.endpoint_reset = ehci_endpoint_reset,
-
-	/*
-	 * scheduling support
-	 */
-	.get_frame_number = ehci_get_frame,
-
-	/*
-	 * root hub support
-	 */
-	.hub_status_data = ehci_hub_status_data,
-	.hub_control = ehci_hub_control,
-	.bus_suspend = ehci_bus_suspend,
-	.bus_resume = ehci_bus_resume,
-	.relinquish_port = ehci_relinquish_port,
-	.port_handed_over = ehci_port_handed_over,
-
-	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-};
-
-static int pxa168_usb_phy_init(struct platform_device *pdev)
-{
-	struct resource *res;
-	void __iomem *usb_phy_reg_base;
-	struct pxa168_usb_pdata *pdata;
-	struct pxa168_usb_drv_data *drv_data;
-	struct usb_hcd *hcd = platform_get_drvdata(pdev);
-	unsigned long reg_val;
-	int pll_retry_cont = 10000, err = 0;
-
-	drv_data = (struct pxa168_usb_drv_data *)hcd->hcd_priv;
-	pdata = (struct pxa168_usb_pdata *)pdev->dev.platform_data;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (!res) {
-		dev_err(&pdev->dev,
-			"Found HC with no PHY register addr. Check %s setup!\n",
-			dev_name(&pdev->dev));
-		return -ENODEV;
-	}
-
-	if (!request_mem_region(res->start, resource_size(res),
-				ehci_pxa168_hc_driver.description)) {
-		dev_dbg(&pdev->dev, "controller already in use\n");
-		return -EBUSY;
-	}
-
-	usb_phy_reg_base = ioremap(res->start, resource_size(res));
-	if (usb_phy_reg_base == NULL) {
-		dev_dbg(&pdev->dev, "error mapping memory\n");
-		err = -EFAULT;
-		goto err1;
-	}
-	drv_data->usb_phy_reg_base = usb_phy_reg_base;
-	drv_data->usb_phy_res = res;
-
-	/* If someone wants to init USB phy in board specific way */
-	if (pdata && pdata->phy_init)
-		return pdata->phy_init(usb_phy_reg_base);
-
-	/* Power up the PHY and PLL */
-	writel(readl(usb_phy_reg_base + USB_PHY_CTRL_REG) | 0x3,
-		usb_phy_reg_base + USB_PHY_CTRL_REG);
-
-	/* Configure PHY PLL */
-	reg_val = readl(usb_phy_reg_base + USB_PHY_PLL_REG) & ~(0x7e03ffff);
-	reg_val |= (VDD18_22 << PLLVDD18_SHIFT | VDD12_12 << PLLVDD12_SHIFT |
-		CALI12_11 << PLLCALI12_SHIFT | 3 << KVCO_SHIFT |
-		ICP_15 << ICP_SHIFT | 0xee << FBDIV_SHIFT | 0xb);
-	writel(reg_val, usb_phy_reg_base + USB_PHY_PLL_REG);
-
-	/* Make sure PHY PLL is ready */
-	while (!(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & PLL_READY)) {
-		if (!(pll_retry_cont--)) {
-			dev_dbg(&pdev->dev, "USB PHY PLL not ready\n");
-			err = -EIO;
-			goto err2;
-		}
-	}
-
-	/* Toggle VCOCAL_START bit of U2PLL for PLL calibration */
-	udelay(200);
-	writel(readl(usb_phy_reg_base + USB_PHY_PLL_REG) | VCOCAL_START,
-		usb_phy_reg_base + USB_PHY_PLL_REG);
-	udelay(40);
-	writel(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & ~VCOCAL_START,
-		usb_phy_reg_base + USB_PHY_PLL_REG);
-
-	/* Toggle REG_RCAL_START bit of U2PTX for impedance calibration */
-	udelay(400);
-	writel(readl(usb_phy_reg_base + USB_PHY_TX_REG) | REG_RCAL_START,
-		usb_phy_reg_base + USB_PHY_TX_REG);
-	udelay(40);
-	writel(readl(usb_phy_reg_base + USB_PHY_TX_REG) & ~REG_RCAL_START,
-		usb_phy_reg_base + USB_PHY_TX_REG);
-
-	/* Make sure PHY PLL is ready again */
-	pll_retry_cont = 0;
-	while (!(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & PLL_READY)) {
-		if (!(pll_retry_cont--)) {
-			dev_dbg(&pdev->dev, "USB PHY PLL not ready\n");
-			err = -EIO;
-			goto err2;
-		}
-	}
-
-	return 0;
-err2:
-	iounmap(usb_phy_reg_base);
-err1:
-	release_mem_region(res->start, resource_size(res));
-	return err;
-}
-
-static int __devinit ehci_pxa168_drv_probe(struct platform_device *pdev)
-{
-	struct resource *res;
-	struct usb_hcd *hcd;
-	struct ehci_hcd *ehci;
-	struct pxa168_usb_drv_data *drv_data;
-	void __iomem *regs;
-	int irq, err = 0;
-
-	if (usb_disabled())
-		return -ENODEV;
-
-	pr_debug("Initializing pxa168-SoC USB Host Controller\n");
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq <= 0) {
-		dev_err(&pdev->dev,
-			"Found HC with no IRQ. Check %s setup!\n",
-			dev_name(&pdev->dev));
-		err = -ENODEV;
-		goto err1;
-	}
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev,
-			"Found HC with no register addr. Check %s setup!\n",
-			dev_name(&pdev->dev));
-		err = -ENODEV;
-		goto err1;
-	}
-
-	if (!request_mem_region(res->start, resource_size(res),
-				ehci_pxa168_hc_driver.description)) {
-		dev_dbg(&pdev->dev, "controller already in use\n");
-		err = -EBUSY;
-		goto err1;
-	}
-
-	regs = ioremap(res->start, resource_size(res));
-	if (regs == NULL) {
-		dev_dbg(&pdev->dev, "error mapping memory\n");
-		err = -EFAULT;
-		goto err2;
-	}
-
-	hcd = usb_create_hcd(&ehci_pxa168_hc_driver,
-			&pdev->dev, dev_name(&pdev->dev));
-	if (!hcd) {
-		err = -ENOMEM;
-		goto err3;
-	}
-
-	drv_data = (struct pxa168_usb_drv_data *)hcd->hcd_priv;
-
-	/* Enable USB clock */
-	drv_data->pxa168_usb_clk = clk_get(&pdev->dev, "PXA168-USBCLK");
-	if (IS_ERR(drv_data->pxa168_usb_clk)) {
-		dev_err(&pdev->dev, "Couldn't get USB clock\n");
-		err = PTR_ERR(drv_data->pxa168_usb_clk);
-		goto err4;
-	}
-	clk_enable(drv_data->pxa168_usb_clk);
-
-	err = pxa168_usb_phy_init(pdev);
-	if (err) {
-		dev_err(&pdev->dev, "USB PHY initialization failed\n");
-		goto err5;
-	}
-
-	hcd->rsrc_start = res->start;
-	hcd->rsrc_len = resource_size(res);
-	hcd->regs = regs;
-
-	ehci = hcd_to_ehci(hcd);
-	ehci->caps = hcd->regs + 0x100;
-	ehci->regs = hcd->regs + 0x100 +
-		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-	hcd->has_tt = 1;
-	ehci->sbrn = 0x20;
-
-	err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
-	if (err)
-		goto err5;
-
-	return 0;
-
-err5:
-	clk_disable(drv_data->pxa168_usb_clk);
-	clk_put(drv_data->pxa168_usb_clk);
-err4:
-	usb_put_hcd(hcd);
-err3:
-	iounmap(regs);
-err2:
-	release_mem_region(res->start, resource_size(res));
-err1:
-	dev_err(&pdev->dev, "init %s fail, %d\n",
-		dev_name(&pdev->dev), err);
-
-	return err;
-}
-
-static int __exit ehci_pxa168_drv_remove(struct platform_device *pdev)
-{
-	struct usb_hcd *hcd = platform_get_drvdata(pdev);
-	struct pxa168_usb_drv_data *drv_data =
-		(struct pxa168_usb_drv_data *)hcd->hcd_priv;
-
-	usb_remove_hcd(hcd);
-
-	/* Power down PHY & PLL */
-	writel(readl(drv_data->usb_phy_reg_base + USB_PHY_CTRL_REG) & (~0x3),
-		drv_data->usb_phy_reg_base + USB_PHY_CTRL_REG);
-
-	clk_disable(drv_data->pxa168_usb_clk);
-	clk_put(drv_data->pxa168_usb_clk);
-
-	iounmap(hcd->regs);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-
-	iounmap(drv_data->usb_phy_reg_base);
-	release_mem_region(drv_data->usb_phy_res->start,
-			resource_size(drv_data->usb_phy_res));
-
-	usb_put_hcd(hcd);
-
-	return 0;
-}
-
-MODULE_ALIAS("platform:pxa168-ehci");
-
-static struct platform_driver ehci_pxa168_driver = {
-	.probe		= ehci_pxa168_drv_probe,
-	.remove		= __exit_p(ehci_pxa168_drv_remove),
-	.shutdown	= usb_hcd_platform_shutdown,
-	.driver.name	= "pxa168-ehci",
-};
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index 293f741..f098e2a 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -17,6 +17,15 @@
 #include <plat/ehci.h>
 #include <plat/usb-phy.h>
 
+#define EHCI_INSNREG00(base)			(base + 0x90)
+#define EHCI_INSNREG00_ENA_INCR16		(0x1 << 25)
+#define EHCI_INSNREG00_ENA_INCR8		(0x1 << 24)
+#define EHCI_INSNREG00_ENA_INCR4		(0x1 << 23)
+#define EHCI_INSNREG00_ENA_INCRX_ALIGN		(0x1 << 22)
+#define EHCI_INSNREG00_ENABLE_DMA_BURST	\
+	(EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 |	\
+	 EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN)
+
 struct s5p_ehci_hcd {
 	struct device *dev;
 	struct usb_hcd *hcd;
@@ -128,6 +137,9 @@
 	ehci->regs = hcd->regs +
 		HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
 
+	/* DMA burst Enable */
+	writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
+
 	dbg_hcs_params(ehci, "reset");
 	dbg_hcc_params(ehci, "reset");
 
@@ -234,6 +246,9 @@
 	if (pdata && pdata->phy_init)
 		pdata->phy_init(pdev, S5P_USB_PHY_HOST);
 
+	/* DMA burst Enable */
+	writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
+
 	if (time_before(jiffies, ehci->next_statechange))
 		msleep(100);
 
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c
index b115b0b..6e92855 100644
--- a/drivers/usb/host/ehci-spear.c
+++ b/drivers/usb/host/ehci-spear.c
@@ -11,8 +11,10 @@
 * more details.
 */
 
-#include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
 
 struct spear_ehci {
 	struct ehci_hcd ehci;
@@ -90,6 +92,82 @@
 	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,
 };
 
+#ifdef CONFIG_PM
+static int ehci_spear_drv_suspend(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	unsigned long flags;
+	int rc = 0;
+
+	if (time_before(jiffies, ehci->next_statechange))
+		msleep(10);
+
+	/*
+	 * Root hub was already suspended. Disable irq emission and mark HW
+	 * unaccessible. The PM and USB cores make sure that the root hub is
+	 * either suspended or stopped.
+	 */
+	spin_lock_irqsave(&ehci->lock, flags);
+	ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+	ehci_readl(ehci, &ehci->regs->intr_enable);
+	spin_unlock_irqrestore(&ehci->lock, flags);
+
+	return rc;
+}
+
+static int ehci_spear_drv_resume(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+	if (time_before(jiffies, ehci->next_statechange))
+		msleep(100);
+
+	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
+		int mask = INTR_MASK;
+
+		ehci_prepare_ports_for_controller_resume(ehci);
+
+		if (!hcd->self.root_hub->do_remote_wakeup)
+			mask &= ~STS_PCD;
+
+		ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+		ehci_readl(ehci, &ehci->regs->intr_enable);
+		return 0;
+	}
+
+	usb_root_hub_lost_power(hcd->self.root_hub);
+
+	/*
+	 * Else reset, to cope with power loss or flush-to-storage style
+	 * "resume" having let BIOS kick in during reboot.
+	 */
+	ehci_halt(ehci);
+	ehci_reset(ehci);
+
+	/* emptying the schedule aborts any urbs */
+	spin_lock_irq(&ehci->lock);
+	if (ehci->reclaim)
+		end_unlink_async(ehci);
+
+	ehci_work(ehci);
+	spin_unlock_irq(&ehci->lock);
+
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
+	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
+
+	/* here we "know" root ports should always stay powered */
+	ehci_port_power(ehci, 1);
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend,
+		ehci_spear_drv_resume);
+
 static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd ;
@@ -205,7 +283,8 @@
 	.shutdown	= usb_hcd_platform_shutdown,
 	.driver		= {
 		.name = "spear-ehci",
-		.bus = &platform_bus_type
+		.bus = &platform_bus_type,
+		.pm = &ehci_spear_pm_ops,
 	}
 };
 
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index dbc7fe8..3de48a2 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -35,7 +35,7 @@
 	struct tegra_usb_phy *phy;
 	struct clk *clk;
 	struct clk *emc_clk;
-	struct otg_transceiver *transceiver;
+	struct usb_phy *transceiver;
 	int host_resumed;
 	int bus_suspended;
 	int port_resuming;
@@ -733,9 +733,9 @@
 
 #ifdef CONFIG_USB_OTG_UTILS
 	if (pdata->operating_mode == TEGRA_USB_OTG) {
-		tegra->transceiver = otg_get_transceiver();
+		tegra->transceiver = usb_get_transceiver();
 		if (tegra->transceiver)
-			otg_set_host(tegra->transceiver, &hcd->self);
+			otg_set_host(tegra->transceiver->otg, &hcd->self);
 	}
 #endif
 
@@ -750,8 +750,8 @@
 fail:
 #ifdef CONFIG_USB_OTG_UTILS
 	if (tegra->transceiver) {
-		otg_set_host(tegra->transceiver, NULL);
-		otg_put_transceiver(tegra->transceiver);
+		otg_set_host(tegra->transceiver->otg, NULL);
+		usb_put_transceiver(tegra->transceiver);
 	}
 #endif
 	tegra_usb_phy_close(tegra->phy);
@@ -808,8 +808,8 @@
 
 #ifdef CONFIG_USB_OTG_UTILS
 	if (tegra->transceiver) {
-		otg_set_host(tegra->transceiver, NULL);
-		otg_put_transceiver(tegra->transceiver);
+		otg_set_host(tegra->transceiver->otg, NULL);
+		usb_put_transceiver(tegra->transceiver);
 	}
 #endif
 
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 0a5fda7..8f9acbc 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -176,7 +176,7 @@
 	/*
 	 * OTG controllers and transceivers need software interaction
 	 */
-	struct otg_transceiver	*transceiver;
+	struct usb_phy	*transceiver;
 };
 
 /* convert between an HCD pointer and the corresponding EHCI_HCD */
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index 7916e56..ab333ac 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -94,7 +94,6 @@
 	pdev->dev.parent = &ofdev->dev;
 
 	pdev->dev.coherent_dma_mask = ofdev->dev.coherent_dma_mask;
-	pdev->dev.dma_mask = &pdev->archdata.dma_mask;
 	*pdev->dev.dma_mask = *ofdev->dev.dma_mask;
 
 	retval = platform_device_add_data(pdev, pdata, sizeof(*pdata));
diff --git a/drivers/usb/host/imx21-dbg.c b/drivers/usb/host/imx21-dbg.c
index 6d75334..ec98ece 100644
--- a/drivers/usb/host/imx21-dbg.c
+++ b/drivers/usb/host/imx21-dbg.c
@@ -239,7 +239,7 @@
 		"ETDs allocated: %d/%d (max=%d)\n"
 		"ETDs in use sw: %d\n"
 		"ETDs in use hw: %d\n"
-		"DMEM alocated: %d/%d (max=%d)\n"
+		"DMEM allocated: %d/%d (max=%d)\n"
 		"DMEM blocks: %d\n"
 		"Queued waiting for ETD: %d\n"
 		"Queued waiting for DMEM: %d\n",
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index d91e5f2..9248800 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -1569,6 +1569,9 @@
 	int ret = 0;
 	unsigned long irqflags;
 
+	if (usb_disabled())
+		return -ENODEV;
+
 	if (pdev->num_resources < 3) {
 		ret = -ENODEV;
 		goto err1;
@@ -1708,22 +1711,4 @@
 	},
 };
 
-/*-----------------------------------------------------------------*/
-
-static int __init isp116x_init(void)
-{
-	if (usb_disabled())
-		return -ENODEV;
-
-	INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION);
-	return platform_driver_register(&isp116x_driver);
-}
-
-module_init(isp116x_init);
-
-static void __exit isp116x_cleanup(void)
-{
-	platform_driver_unregister(&isp116x_driver);
-}
-
-module_exit(isp116x_cleanup);
+module_platform_driver(isp116x_driver);
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index e5fd8aa..9e63cdf 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -2693,6 +2693,9 @@
 	struct resource *irq_res;
 	unsigned int irq_flags = 0;
 
+	if (usb_disabled())
+		return -ENODEV;
+
 	/* basic sanity checks first.  board-specific init logic should
 	 * have initialized this the three resources and probably board
 	 * specific platform_data.  we don't probe for IRQs, and do only
@@ -2864,19 +2867,4 @@
 	},
 };
 
-/*-------------------------------------------------------------------------*/
-
-static int __init isp1362_init(void)
-{
-	if (usb_disabled())
-		return -ENODEV;
-	pr_info("driver %s, %s\n", hcd_name, DRIVER_VERSION);
-	return platform_driver_register(&isp1362_driver);
-}
-module_init(isp1362_init);
-
-static void __exit isp1362_cleanup(void)
-{
-	platform_driver_unregister(&isp1362_driver);
-}
-module_exit(isp1362_cleanup);
+module_platform_driver(isp1362_driver);
diff --git a/drivers/usb/host/ohci-ath79.c b/drivers/usb/host/ohci-ath79.c
deleted file mode 100644
index 18d574d..0000000
--- a/drivers/usb/host/ohci-ath79.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- *  OHCI HCD (Host Controller Driver) for USB.
- *
- *  Bus Glue for Atheros AR71XX/AR724X built-in OHCI controller.
- *
- *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
- *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
- *
- *  Parts of this file are based on Atheros' 2.6.15 BSP
- *	Copyright (C) 2007 Atheros 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.
- */
-
-#include <linux/platform_device.h>
-
-static int __devinit ohci_ath79_start(struct usb_hcd *hcd)
-{
-	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
-	int ret;
-
-	ret = ohci_init(ohci);
-	if (ret < 0)
-		return ret;
-
-	ret = ohci_run(ohci);
-	if (ret < 0)
-		goto err;
-
-	return 0;
-
-err:
-	ohci_stop(hcd);
-	return ret;
-}
-
-static const struct hc_driver ohci_ath79_hc_driver = {
-	.description		= hcd_name,
-	.product_desc		= "Atheros built-in OHCI controller",
-	.hcd_priv_size		= sizeof(struct ohci_hcd),
-
-	.irq			= ohci_irq,
-	.flags			= HCD_USB11 | HCD_MEMORY,
-
-	.start			= ohci_ath79_start,
-	.stop			= ohci_stop,
-	.shutdown		= ohci_shutdown,
-
-	.urb_enqueue		= ohci_urb_enqueue,
-	.urb_dequeue		= ohci_urb_dequeue,
-	.endpoint_disable	= ohci_endpoint_disable,
-
-	/*
-	 * scheduling support
-	 */
-	.get_frame_number	= ohci_get_frame,
-
-	/*
-	 * root hub support
-	 */
-	.hub_status_data	= ohci_hub_status_data,
-	.hub_control		= ohci_hub_control,
-	.start_port_reset	= ohci_start_port_reset,
-};
-
-static int ohci_ath79_probe(struct platform_device *pdev)
-{
-	struct usb_hcd *hcd;
-	struct resource *res;
-	int irq;
-	int ret;
-
-	if (usb_disabled())
-		return -ENODEV;
-
-	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (!res) {
-		dev_dbg(&pdev->dev, "no IRQ specified\n");
-		return -ENODEV;
-	}
-	irq = res->start;
-
-	hcd = usb_create_hcd(&ohci_ath79_hc_driver, &pdev->dev,
-			     dev_name(&pdev->dev));
-	if (!hcd)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_dbg(&pdev->dev, "no base address specified\n");
-		ret = -ENODEV;
-		goto err_put_hcd;
-	}
-	hcd->rsrc_start = res->start;
-	hcd->rsrc_len = resource_size(res);
-
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		dev_dbg(&pdev->dev, "controller already in use\n");
-		ret = -EBUSY;
-		goto err_put_hcd;
-	}
-
-	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
-	if (!hcd->regs) {
-		dev_dbg(&pdev->dev, "error mapping memory\n");
-		ret = -EFAULT;
-		goto err_release_region;
-	}
-
-	ohci_hcd_init(hcd_to_ohci(hcd));
-
-	ret = usb_add_hcd(hcd, irq, 0);
-	if (ret)
-		goto err_stop_hcd;
-
-	return 0;
-
-err_stop_hcd:
-	iounmap(hcd->regs);
-err_release_region:
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_put_hcd:
-	usb_put_hcd(hcd);
-	return ret;
-}
-
-static int ohci_ath79_remove(struct platform_device *pdev)
-{
-	struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
-	usb_remove_hcd(hcd);
-	iounmap(hcd->regs);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-	usb_put_hcd(hcd);
-
-	return 0;
-}
-
-static struct platform_driver ohci_hcd_ath79_driver = {
-	.probe		= ohci_ath79_probe,
-	.remove		= ohci_ath79_remove,
-	.shutdown	= usb_hcd_platform_shutdown,
-	.driver		= {
-		.name	= "ath79-ohci",
-		.owner	= THIS_MODULE,
-	},
-};
-
-MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ath79-ohci");
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index 55aa35a..37bb20e 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -212,12 +212,10 @@
 	 * mark HW unaccessible, bail out if RH has been resumed. Use
 	 * the spinlock to properly synchronize with possible pending
 	 * RH suspend or resume activity.
-	 *
-	 * This is still racy as hcd->state is manipulated outside of
-	 * any locks =P But that will be a different fix.
 	 */
 	spin_lock_irqsave(&ohci->lock, flags);
-	if (hcd->state != HC_STATE_SUSPENDED && hcd->state != HC_STATE_HALT) {
+	if (ohci->rh_state != OHCI_RH_SUSPENDED &&
+			ohci->rh_state != OHCI_RH_HALTED) {
 		rc = -EINVAL;
 		goto fail;
 	}
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 34b9edd..cd5e382 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -899,7 +899,7 @@
 	ohci_usb_reset (ohci);
 	ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
 	free_irq(hcd->irq, hcd);
-	hcd->irq = -1;
+	hcd->irq = 0;
 
 	if (quirk_zfmicro(ohci))
 		del_timer(&ohci->unlink_watchdog);
@@ -1050,9 +1050,9 @@
 #define PLATFORM_DRIVER		ohci_hcd_at91_driver
 #endif
 
-#ifdef CONFIG_ARCH_PNX4008
-#include "ohci-pnx4008.c"
-#define PLATFORM_DRIVER		usb_hcd_pnx4008_driver
+#if defined(CONFIG_ARCH_PNX4008) || defined(CONFIG_ARCH_LPC32XX)
+#include "ohci-nxp.c"
+#define PLATFORM_DRIVER		usb_hcd_nxp_driver
 #endif
 
 #ifdef CONFIG_ARCH_DAVINCI_DA8XX
@@ -1111,16 +1111,16 @@
 #define PLATFORM_DRIVER		ohci_hcd_cns3xxx_driver
 #endif
 
-#ifdef CONFIG_USB_OHCI_ATH79
-#include "ohci-ath79.c"
-#define PLATFORM_DRIVER		ohci_hcd_ath79_driver
-#endif
-
 #ifdef CONFIG_CPU_XLR
 #include "ohci-xls.c"
 #define PLATFORM_DRIVER		ohci_xls_driver
 #endif
 
+#ifdef CONFIG_USB_OHCI_HCD_PLATFORM
+#include "ohci-platform.c"
+#define PLATFORM_DRIVER		ohci_platform_driver
+#endif
+
 #if	!defined(PCI_DRIVER) &&		\
 	!defined(PLATFORM_DRIVER) &&	\
 	!defined(OMAP1_PLATFORM_DRIVER) &&	\
diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c
new file mode 100644
index 0000000..6618de1
--- /dev/null
+++ b/drivers/usb/host/ohci-nxp.c
@@ -0,0 +1,528 @@
+/*
+ * driver for NXP USB Host devices
+ *
+ * Currently supported OHCI host devices:
+ * - Philips PNX4008
+ * - NXP LPC32xx
+ *
+ * Authors: Dmitry Chigirev <source@mvista.com>
+ *	    Vitaly Wool <vitalywool@gmail.com>
+ *
+ * register initialization is based on code examples provided by Philips
+ * Copyright (c) 2005 Koninklijke Philips Electronics N.V.
+ *
+ * NOTE: This driver does not have suspend/resume functionality
+ * This driver is intended for engineering development purposes only
+ *
+ * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/io.h>
+
+#include <mach/platform.h>
+#include <mach/irqs.h>
+#include <asm/gpio.h>
+
+#define USB_CONFIG_BASE		0x31020000
+#define PWRMAN_BASE		0x40004000
+
+#define USB_CTRL		IO_ADDRESS(PWRMAN_BASE + 0x64)
+
+/* USB_CTRL bit defines */
+#define USB_SLAVE_HCLK_EN	(1 << 24)
+#define USB_HOST_NEED_CLK_EN	(1 << 21)
+
+#define USB_OTG_CLK_CTRL	IO_ADDRESS(USB_CONFIG_BASE + 0xFF4)
+#define USB_OTG_CLK_STAT	IO_ADDRESS(USB_CONFIG_BASE + 0xFF8)
+
+/* USB_OTG_CLK_CTRL bit defines */
+#define AHB_M_CLOCK_ON		(1 << 4)
+#define OTG_CLOCK_ON		(1 << 3)
+#define I2C_CLOCK_ON		(1 << 2)
+#define DEV_CLOCK_ON		(1 << 1)
+#define HOST_CLOCK_ON		(1 << 0)
+
+#define USB_OTG_STAT_CONTROL	IO_ADDRESS(USB_CONFIG_BASE + 0x110)
+
+/* USB_OTG_STAT_CONTROL bit defines */
+#define TRANSPARENT_I2C_EN	(1 << 7)
+#define HOST_EN			(1 << 0)
+
+/* ISP1301 USB transceiver I2C registers */
+#define	ISP1301_MODE_CONTROL_1		0x04	/* u8 read, set, +1 clear */
+
+#define	MC1_SPEED_REG		(1 << 0)
+#define	MC1_SUSPEND_REG		(1 << 1)
+#define	MC1_DAT_SE0		(1 << 2)
+#define	MC1_TRANSPARENT		(1 << 3)
+#define	MC1_BDIS_ACON_EN	(1 << 4)
+#define	MC1_OE_INT_EN		(1 << 5)
+#define	MC1_UART_EN		(1 << 6)
+#define	MC1_MASK		0x7f
+
+#define	ISP1301_MODE_CONTROL_2		0x12	/* u8 read, set, +1 clear */
+
+#define	MC2_GLOBAL_PWR_DN	(1 << 0)
+#define	MC2_SPD_SUSP_CTRL	(1 << 1)
+#define	MC2_BI_DI		(1 << 2)
+#define	MC2_TRANSP_BDIR0	(1 << 3)
+#define	MC2_TRANSP_BDIR1	(1 << 4)
+#define	MC2_AUDIO_EN		(1 << 5)
+#define	MC2_PSW_EN		(1 << 6)
+#define	MC2_EN2V7		(1 << 7)
+
+#define	ISP1301_OTG_CONTROL_1		0x06	/* u8 read, set, +1 clear */
+#	define	OTG1_DP_PULLUP		(1 << 0)
+#	define	OTG1_DM_PULLUP		(1 << 1)
+#	define	OTG1_DP_PULLDOWN	(1 << 2)
+#	define	OTG1_DM_PULLDOWN	(1 << 3)
+#	define	OTG1_ID_PULLDOWN	(1 << 4)
+#	define	OTG1_VBUS_DRV		(1 << 5)
+#	define	OTG1_VBUS_DISCHRG	(1 << 6)
+#	define	OTG1_VBUS_CHRG		(1 << 7)
+#define	ISP1301_OTG_STATUS		0x10	/* u8 readonly */
+#	define	OTG_B_SESS_END		(1 << 6)
+#	define	OTG_B_SESS_VLD		(1 << 7)
+
+#define ISP1301_I2C_ADDR 0x2C
+
+#define ISP1301_I2C_MODE_CONTROL_1 0x4
+#define ISP1301_I2C_MODE_CONTROL_2 0x12
+#define ISP1301_I2C_OTG_CONTROL_1 0x6
+#define ISP1301_I2C_OTG_CONTROL_2 0x10
+#define ISP1301_I2C_INTERRUPT_SOURCE 0x8
+#define ISP1301_I2C_INTERRUPT_LATCH 0xA
+#define ISP1301_I2C_INTERRUPT_FALLING 0xC
+#define ISP1301_I2C_INTERRUPT_RISING 0xE
+#define ISP1301_I2C_REG_CLEAR_ADDR 1
+
+/* On LPC32xx, those are undefined */
+#ifndef start_int_set_falling_edge
+#define start_int_set_falling_edge(irq)
+#define start_int_set_rising_edge(irq)
+#define start_int_ack(irq)
+#define start_int_mask(irq)
+#define start_int_umask(irq)
+#endif
+
+static struct i2c_driver isp1301_driver;
+static struct i2c_client *isp1301_i2c_client;
+
+extern int usb_disabled(void);
+extern int ocpi_enable(void);
+
+static struct clk *usb_clk;
+
+static const unsigned short normal_i2c[] =
+    { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END };
+
+static int isp1301_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	return 0;
+}
+
+static int isp1301_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static const struct i2c_device_id isp1301_id[] = {
+	{ "isp1301_nxp", 0 },
+	{ }
+};
+
+static struct i2c_driver isp1301_driver = {
+	.driver = {
+		.name = "isp1301_nxp",
+	},
+	.probe = isp1301_probe,
+	.remove = isp1301_remove,
+	.id_table = isp1301_id,
+};
+
+static void isp1301_configure_pnx4008(void)
+{
+	/* PNX4008 only supports DAT_SE0 USB mode */
+	/* PNX4008 R2A requires setting the MAX603 to output 3.6V */
+	/* Power up externel charge-pump */
+
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		ISP1301_I2C_MODE_CONTROL_1, MC1_DAT_SE0 | MC1_SPEED_REG);
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
+		~(MC1_DAT_SE0 | MC1_SPEED_REG));
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		ISP1301_I2C_MODE_CONTROL_2,
+		MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL);
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR,
+		~(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL));
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		ISP1301_I2C_OTG_CONTROL_1, OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN);
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
+		~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN));
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, 0xFF);
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR,
+		0xFF);
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR,
+		0xFF);
+}
+
+static void isp1301_configure_lpc32xx(void)
+{
+	/* LPC32XX only supports DAT_SE0 USB mode */
+	/* This sequence is important */
+
+	/* Disable transparent UART mode first */
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		(ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR),
+		MC1_UART_EN);
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		(ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR),
+		~MC1_SPEED_REG);
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+				  ISP1301_I2C_MODE_CONTROL_1, MC1_SPEED_REG);
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		  (ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR),
+		  ~0);
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		ISP1301_I2C_MODE_CONTROL_2,
+		(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL));
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		(ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0);
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		ISP1301_I2C_MODE_CONTROL_1, MC1_DAT_SE0);
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		ISP1301_I2C_OTG_CONTROL_1,
+		(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN));
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		(ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR),
+		(OTG1_DM_PULLUP | OTG1_DP_PULLUP));
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR,
+		~0);
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
+
+	/* Enable usb_need_clk clock after transceiver is initialized */
+	__raw_writel((__raw_readl(USB_CTRL) | (1 << 22)), USB_CTRL);
+
+	printk(KERN_INFO "ISP1301 Vendor ID  : 0x%04x\n",
+	      i2c_smbus_read_word_data(isp1301_i2c_client, 0x00));
+	printk(KERN_INFO "ISP1301 Product ID : 0x%04x\n",
+	      i2c_smbus_read_word_data(isp1301_i2c_client, 0x02));
+	printk(KERN_INFO "ISP1301 Version ID : 0x%04x\n",
+	      i2c_smbus_read_word_data(isp1301_i2c_client, 0x14));
+}
+
+static void isp1301_configure(void)
+{
+	if (machine_is_pnx4008())
+		isp1301_configure_pnx4008();
+	else
+		isp1301_configure_lpc32xx();
+}
+
+static inline void isp1301_vbus_on(void)
+{
+	i2c_smbus_write_byte_data(isp1301_i2c_client, ISP1301_I2C_OTG_CONTROL_1,
+				  OTG1_VBUS_DRV);
+}
+
+static inline void isp1301_vbus_off(void)
+{
+	i2c_smbus_write_byte_data(isp1301_i2c_client,
+		ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
+		OTG1_VBUS_DRV);
+}
+
+static void nxp_start_hc(void)
+{
+	unsigned long tmp = __raw_readl(USB_OTG_STAT_CONTROL) | HOST_EN;
+	__raw_writel(tmp, USB_OTG_STAT_CONTROL);
+	isp1301_vbus_on();
+}
+
+static void nxp_stop_hc(void)
+{
+	unsigned long tmp;
+	isp1301_vbus_off();
+	tmp = __raw_readl(USB_OTG_STAT_CONTROL) & ~HOST_EN;
+	__raw_writel(tmp, USB_OTG_STAT_CONTROL);
+}
+
+static int __devinit ohci_nxp_start(struct usb_hcd *hcd)
+{
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+	int ret;
+
+	if ((ret = ohci_init(ohci)) < 0)
+		return ret;
+
+	if ((ret = ohci_run(ohci)) < 0) {
+		dev_err(hcd->self.controller, "can't start\n");
+		ohci_stop(hcd);
+		return ret;
+	}
+	return 0;
+}
+
+static const struct hc_driver ohci_nxp_hc_driver = {
+	.description = hcd_name,
+	.product_desc =		"nxp OHCI",
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq = ohci_irq,
+	.flags = HCD_USB11 | HCD_MEMORY,
+
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+	/*
+	 * basic lifecycle operations
+	 */
+	.start = ohci_nxp_start,
+	.stop = ohci_stop,
+	.shutdown = ohci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue = ohci_urb_enqueue,
+	.urb_dequeue = ohci_urb_dequeue,
+	.endpoint_disable = ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number = ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data = ohci_hub_status_data,
+	.hub_control = ohci_hub_control,
+#ifdef	CONFIG_PM
+	.bus_suspend = ohci_bus_suspend,
+	.bus_resume = ohci_bus_resume,
+#endif
+	.start_port_reset = ohci_start_port_reset,
+};
+
+#define USB_CLOCK_MASK (AHB_M_CLOCK_ON| OTG_CLOCK_ON | HOST_CLOCK_ON | I2C_CLOCK_ON)
+
+static void nxp_set_usb_bits(void)
+{
+	if (machine_is_pnx4008()) {
+		start_int_set_falling_edge(SE_USB_OTG_ATX_INT_N);
+		start_int_ack(SE_USB_OTG_ATX_INT_N);
+		start_int_umask(SE_USB_OTG_ATX_INT_N);
+
+		start_int_set_rising_edge(SE_USB_OTG_TIMER_INT);
+		start_int_ack(SE_USB_OTG_TIMER_INT);
+		start_int_umask(SE_USB_OTG_TIMER_INT);
+
+		start_int_set_rising_edge(SE_USB_I2C_INT);
+		start_int_ack(SE_USB_I2C_INT);
+		start_int_umask(SE_USB_I2C_INT);
+
+		start_int_set_rising_edge(SE_USB_INT);
+		start_int_ack(SE_USB_INT);
+		start_int_umask(SE_USB_INT);
+
+		start_int_set_rising_edge(SE_USB_NEED_CLK_INT);
+		start_int_ack(SE_USB_NEED_CLK_INT);
+		start_int_umask(SE_USB_NEED_CLK_INT);
+
+		start_int_set_rising_edge(SE_USB_AHB_NEED_CLK_INT);
+		start_int_ack(SE_USB_AHB_NEED_CLK_INT);
+		start_int_umask(SE_USB_AHB_NEED_CLK_INT);
+	}
+}
+
+static void nxp_unset_usb_bits(void)
+{
+	if (machine_is_pnx4008()) {
+		start_int_mask(SE_USB_OTG_ATX_INT_N);
+		start_int_mask(SE_USB_OTG_TIMER_INT);
+		start_int_mask(SE_USB_I2C_INT);
+		start_int_mask(SE_USB_INT);
+		start_int_mask(SE_USB_NEED_CLK_INT);
+		start_int_mask(SE_USB_AHB_NEED_CLK_INT);
+	}
+}
+
+static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = 0;
+	struct ohci_hcd *ohci;
+	const struct hc_driver *driver = &ohci_nxp_hc_driver;
+	struct i2c_adapter *i2c_adap;
+	struct i2c_board_info i2c_info;
+
+	int ret = 0, irq;
+
+	dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name);
+	if (usb_disabled()) {
+		err("USB is disabled");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	if (pdev->num_resources != 2
+	    || pdev->resource[0].flags != IORESOURCE_MEM
+	    || pdev->resource[1].flags != IORESOURCE_IRQ) {
+		err("Invalid resource configuration");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* Enable AHB slave USB clock, needed for further USB clock control */
+	__raw_writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL);
+
+	ret = i2c_add_driver(&isp1301_driver);
+	if (ret < 0) {
+		err("failed to add ISP1301 driver");
+		goto out;
+	}
+	i2c_adap = i2c_get_adapter(2);
+	memset(&i2c_info, 0, sizeof(struct i2c_board_info));
+	strlcpy(i2c_info.type, "isp1301_nxp", I2C_NAME_SIZE);
+	isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
+						   normal_i2c, NULL);
+	i2c_put_adapter(i2c_adap);
+	if (!isp1301_i2c_client) {
+		err("failed to connect I2C to ISP1301 USB Transceiver");
+		ret = -ENODEV;
+		goto out_i2c_driver;
+	}
+
+	isp1301_configure();
+
+	/* Enable USB PLL */
+	usb_clk = clk_get(&pdev->dev, "ck_pll5");
+	if (IS_ERR(usb_clk)) {
+		err("failed to acquire USB PLL");
+		ret = PTR_ERR(usb_clk);
+		goto out1;
+	}
+
+	ret = clk_enable(usb_clk);
+	if (ret < 0) {
+		err("failed to start USB PLL");
+		goto out2;
+	}
+
+	ret = clk_set_rate(usb_clk, 48000);
+	if (ret < 0) {
+		err("failed to set USB clock rate");
+		goto out3;
+	}
+
+	__raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
+
+	/* Set to enable all needed USB clocks */
+	__raw_writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL);
+
+	while ((__raw_readl(USB_OTG_CLK_STAT) & USB_CLOCK_MASK) !=
+	       USB_CLOCK_MASK) ;
+
+	hcd = usb_create_hcd (driver, &pdev->dev, dev_name(&pdev->dev));
+	if (!hcd) {
+		err("Failed to allocate HC buffer");
+		ret = -ENOMEM;
+		goto out3;
+	}
+
+	/* Set all USB bits in the Start Enable register */
+	nxp_set_usb_bits();
+
+	hcd->rsrc_start = pdev->resource[0].start;
+	hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		dev_dbg(&pdev->dev, "request_mem_region failed\n");
+		ret =  -ENOMEM;
+		goto out4;
+	}
+	hcd->regs = (void __iomem *)pdev->resource[0].start;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		ret = -ENXIO;
+		goto out4;
+	}
+
+	nxp_start_hc();
+	platform_set_drvdata(pdev, hcd);
+	ohci = hcd_to_ohci(hcd);
+	ohci_hcd_init(ohci);
+
+	dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq);
+	ret = usb_add_hcd(hcd, irq, 0);
+	if (ret == 0)
+		return ret;
+
+	nxp_stop_hc();
+out4:
+	nxp_unset_usb_bits();
+	usb_put_hcd(hcd);
+out3:
+	clk_disable(usb_clk);
+out2:
+	clk_put(usb_clk);
+out1:
+	i2c_unregister_device(isp1301_i2c_client);
+	isp1301_i2c_client = NULL;
+out_i2c_driver:
+	i2c_del_driver(&isp1301_driver);
+out:
+	return ret;
+}
+
+static int usb_hcd_nxp_remove(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+	usb_remove_hcd(hcd);
+	nxp_stop_hc();
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+	nxp_unset_usb_bits();
+	clk_disable(usb_clk);
+	clk_put(usb_clk);
+	i2c_unregister_device(isp1301_i2c_client);
+	isp1301_i2c_client = NULL;
+	i2c_del_driver(&isp1301_driver);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:usb-ohci");
+
+static struct platform_driver usb_hcd_nxp_driver = {
+	.driver = {
+		.name = "usb-ohci",
+		.owner	= THIS_MODULE,
+	},
+	.probe = usb_hcd_nxp_probe,
+	.remove = usb_hcd_nxp_remove,
+};
+
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index db39686..96451e4 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -171,7 +171,7 @@
 	unsigned long	flags;
 	u32 l;
 
-	otg_start_hnp(ohci->transceiver);
+	otg_start_hnp(ohci->transceiver->otg);
 
 	local_irq_save(flags);
 	ohci->transceiver->state = OTG_STATE_A_SUSPEND;
@@ -210,9 +210,9 @@
 
 #ifdef	CONFIG_USB_OTG
 	if (need_transceiver) {
-		ohci->transceiver = otg_get_transceiver();
+		ohci->transceiver = usb_get_transceiver();
 		if (ohci->transceiver) {
-			int	status = otg_set_host(ohci->transceiver,
+			int	status = otg_set_host(ohci->transceiver->otg,
 						&ohci_to_hcd(ohci)->self);
 			dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n",
 					ohci->transceiver->label, status);
@@ -404,7 +404,7 @@
 
 	usb_remove_hcd(hcd);
 	if (ohci->transceiver) {
-		(void) otg_set_host(ohci->transceiver, 0);
+		(void) otg_set_host(ohci->transceiver->otg, 0);
 		put_device(ohci->transceiver->dev);
 	}
 	if (machine_is_omap_osk())
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
new file mode 100644
index 0000000..ec5c679
--- /dev/null
+++ b/drivers/usb/host/ohci-platform.c
@@ -0,0 +1,194 @@
+/*
+ * Generic platform ohci driver
+ *
+ * Copyright 2007 Michael Buesch <m@bues.ch>
+ * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Derived from the OCHI-SSB driver
+ * Derived from the OHCI-PCI driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/platform_device.h>
+#include <linux/usb/ohci_pdriver.h>
+
+static int ohci_platform_reset(struct usb_hcd *hcd)
+{
+	struct platform_device *pdev = to_platform_device(hcd->self.controller);
+	struct usb_ohci_pdata *pdata = pdev->dev.platform_data;
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+	int err;
+
+	if (pdata->big_endian_desc)
+		ohci->flags |= OHCI_QUIRK_BE_DESC;
+	if (pdata->big_endian_mmio)
+		ohci->flags |= OHCI_QUIRK_BE_MMIO;
+	if (pdata->no_big_frame_no)
+		ohci->flags |= OHCI_QUIRK_FRAME_NO;
+
+	ohci_hcd_init(ohci);
+	err = ohci_init(ohci);
+
+	return err;
+}
+
+static int ohci_platform_start(struct usb_hcd *hcd)
+{
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+	int err;
+
+	err = ohci_run(ohci);
+	if (err < 0) {
+		ohci_err(ohci, "can't start\n");
+		ohci_stop(hcd);
+	}
+
+	return err;
+}
+
+static const struct hc_driver ohci_platform_hc_driver = {
+	.description		= hcd_name,
+	.product_desc		= "Generic Platform OHCI Controller",
+	.hcd_priv_size		= sizeof(struct ohci_hcd),
+
+	.irq			= ohci_irq,
+	.flags			= HCD_MEMORY | HCD_USB11,
+
+	.reset			= ohci_platform_reset,
+	.start			= ohci_platform_start,
+	.stop			= ohci_stop,
+	.shutdown		= ohci_shutdown,
+
+	.urb_enqueue		= ohci_urb_enqueue,
+	.urb_dequeue		= ohci_urb_dequeue,
+	.endpoint_disable	= ohci_endpoint_disable,
+
+	.get_frame_number	= ohci_get_frame,
+
+	.hub_status_data	= ohci_hub_status_data,
+	.hub_control		= ohci_hub_control,
+#ifdef	CONFIG_PM
+	.bus_suspend		= ohci_bus_suspend,
+	.bus_resume		= ohci_bus_resume,
+#endif
+
+	.start_port_reset	= ohci_start_port_reset,
+};
+
+static int __devinit ohci_platform_probe(struct platform_device *dev)
+{
+	struct usb_hcd *hcd;
+	struct resource *res_mem;
+	int irq;
+	int err = -ENOMEM;
+
+	BUG_ON(!dev->dev.platform_data);
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	irq = platform_get_irq(dev, 0);
+	if (irq < 0) {
+		pr_err("no irq provieded");
+		return irq;
+	}
+
+	res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	if (!res_mem) {
+		pr_err("no memory recourse provieded");
+		return -ENXIO;
+	}
+
+	hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
+			dev_name(&dev->dev));
+	if (!hcd)
+		return -ENOMEM;
+
+	hcd->rsrc_start = res_mem->start;
+	hcd->rsrc_len = resource_size(res_mem);
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_err("controller already in use");
+		err = -EBUSY;
+		goto err_put_hcd;
+	}
+
+	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs)
+		goto err_release_region;
+	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
+	if (err)
+		goto err_iounmap;
+
+	platform_set_drvdata(dev, hcd);
+
+	return err;
+
+err_iounmap:
+	iounmap(hcd->regs);
+err_release_region:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_put_hcd:
+	usb_put_hcd(hcd);
+	return err;
+}
+
+static int __devexit ohci_platform_remove(struct platform_device *dev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(dev);
+
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+	platform_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int ohci_platform_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int ohci_platform_resume(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	ohci_finish_controller_resume(hcd);
+	return 0;
+}
+
+#else /* !CONFIG_PM */
+#define ohci_platform_suspend	NULL
+#define ohci_platform_resume	NULL
+#endif /* CONFIG_PM */
+
+static const struct platform_device_id ohci_platform_table[] = {
+	{ "ohci-platform", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, ohci_platform_table);
+
+static const struct dev_pm_ops ohci_platform_pm_ops = {
+	.suspend	= ohci_platform_suspend,
+	.resume		= ohci_platform_resume,
+};
+
+static struct platform_driver ohci_platform_driver = {
+	.id_table	= ohci_platform_table,
+	.probe		= ohci_platform_probe,
+	.remove		= __devexit_p(ohci_platform_remove),
+	.shutdown	= usb_hcd_platform_shutdown,
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "ohci-platform",
+		.pm	= &ohci_platform_pm_ops,
+	}
+};
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
deleted file mode 100644
index 0013db7..0000000
--- a/drivers/usb/host/ohci-pnx4008.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * drivers/usb/host/ohci-pnx4008.c
- *
- * driver for Philips PNX4008 USB Host
- *
- * Authors: Dmitry Chigirev <source@mvista.com>
- *	    Vitaly Wool <vitalywool@gmail.com>
- *
- * register initialization is based on code examples provided by Philips
- * Copyright (c) 2005 Koninklijke Philips Electronics N.V.
- *
- * NOTE: This driver does not have suspend/resume functionality
- * This driver is intended for engineering development purposes only
- *
- * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
-
-#include <mach/hardware.h>
-#include <asm/io.h>
-
-#include <mach/platform.h>
-#include <mach/irqs.h>
-#include <asm/gpio.h>
-
-#define USB_CTRL	IO_ADDRESS(PNX4008_PWRMAN_BASE + 0x64)
-
-/* USB_CTRL bit defines */
-#define USB_SLAVE_HCLK_EN	(1 << 24)
-#define USB_HOST_NEED_CLK_EN	(1 << 21)
-
-#define USB_OTG_CLK_CTRL	IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0xFF4)
-#define USB_OTG_CLK_STAT	IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0xFF8)
-
-/* USB_OTG_CLK_CTRL bit defines */
-#define AHB_M_CLOCK_ON		(1 << 4)
-#define OTG_CLOCK_ON		(1 << 3)
-#define I2C_CLOCK_ON		(1 << 2)
-#define DEV_CLOCK_ON		(1 << 1)
-#define HOST_CLOCK_ON		(1 << 0)
-
-#define USB_OTG_STAT_CONTROL	IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0x110)
-
-/* USB_OTG_STAT_CONTROL bit defines */
-#define TRANSPARENT_I2C_EN	(1 << 7)
-#define HOST_EN			(1 << 0)
-
-/* ISP1301 USB transceiver I2C registers */
-#define	ISP1301_MODE_CONTROL_1		0x04	/* u8 read, set, +1 clear */
-
-#define	MC1_SPEED_REG		(1 << 0)
-#define	MC1_SUSPEND_REG		(1 << 1)
-#define	MC1_DAT_SE0		(1 << 2)
-#define	MC1_TRANSPARENT		(1 << 3)
-#define	MC1_BDIS_ACON_EN	(1 << 4)
-#define	MC1_OE_INT_EN		(1 << 5)
-#define	MC1_UART_EN		(1 << 6)
-#define	MC1_MASK		0x7f
-
-#define	ISP1301_MODE_CONTROL_2		0x12	/* u8 read, set, +1 clear */
-
-#define	MC2_GLOBAL_PWR_DN	(1 << 0)
-#define	MC2_SPD_SUSP_CTRL	(1 << 1)
-#define	MC2_BI_DI		(1 << 2)
-#define	MC2_TRANSP_BDIR0	(1 << 3)
-#define	MC2_TRANSP_BDIR1	(1 << 4)
-#define	MC2_AUDIO_EN		(1 << 5)
-#define	MC2_PSW_EN		(1 << 6)
-#define	MC2_EN2V7		(1 << 7)
-
-#define	ISP1301_OTG_CONTROL_1		0x06	/* u8 read, set, +1 clear */
-#	define	OTG1_DP_PULLUP		(1 << 0)
-#	define	OTG1_DM_PULLUP		(1 << 1)
-#	define	OTG1_DP_PULLDOWN	(1 << 2)
-#	define	OTG1_DM_PULLDOWN	(1 << 3)
-#	define	OTG1_ID_PULLDOWN	(1 << 4)
-#	define	OTG1_VBUS_DRV		(1 << 5)
-#	define	OTG1_VBUS_DISCHRG	(1 << 6)
-#	define	OTG1_VBUS_CHRG		(1 << 7)
-#define	ISP1301_OTG_STATUS		0x10	/* u8 readonly */
-#	define	OTG_B_SESS_END		(1 << 6)
-#	define	OTG_B_SESS_VLD		(1 << 7)
-
-#define ISP1301_I2C_ADDR 0x2C
-
-#define ISP1301_I2C_MODE_CONTROL_1 0x4
-#define ISP1301_I2C_MODE_CONTROL_2 0x12
-#define ISP1301_I2C_OTG_CONTROL_1 0x6
-#define ISP1301_I2C_OTG_CONTROL_2 0x10
-#define ISP1301_I2C_INTERRUPT_SOURCE 0x8
-#define ISP1301_I2C_INTERRUPT_LATCH 0xA
-#define ISP1301_I2C_INTERRUPT_FALLING 0xC
-#define ISP1301_I2C_INTERRUPT_RISING 0xE
-#define ISP1301_I2C_REG_CLEAR_ADDR 1
-
-static struct i2c_driver isp1301_driver;
-static struct i2c_client *isp1301_i2c_client;
-
-extern int usb_disabled(void);
-extern int ocpi_enable(void);
-
-static struct clk *usb_clk;
-
-static const unsigned short normal_i2c[] =
-    { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END };
-
-static int isp1301_probe(struct i2c_client *client,
-			 const struct i2c_device_id *id)
-{
-	return 0;
-}
-
-static int isp1301_remove(struct i2c_client *client)
-{
-	return 0;
-}
-
-static const struct i2c_device_id isp1301_id[] = {
-	{ "isp1301_pnx", 0 },
-	{ }
-};
-
-static struct i2c_driver isp1301_driver = {
-	.driver = {
-		.name = "isp1301_pnx",
-	},
-	.probe = isp1301_probe,
-	.remove = isp1301_remove,
-	.id_table = isp1301_id,
-};
-
-static void i2c_write(u8 buf, u8 subaddr)
-{
-	char tmpbuf[2];
-
-	tmpbuf[0] = subaddr;	/*register number */
-	tmpbuf[1] = buf;	/*register data */
-	i2c_master_send(isp1301_i2c_client, &tmpbuf[0], 2);
-}
-
-static void isp1301_configure(void)
-{
-	/* PNX4008 only supports DAT_SE0 USB mode */
-	/* PNX4008 R2A requires setting the MAX603 to output 3.6V */
-	/* Power up externel charge-pump */
-
-	i2c_write(MC1_DAT_SE0 | MC1_SPEED_REG, ISP1301_I2C_MODE_CONTROL_1);
-	i2c_write(~(MC1_DAT_SE0 | MC1_SPEED_REG),
-		  ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
-	i2c_write(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL,
-		  ISP1301_I2C_MODE_CONTROL_2);
-	i2c_write(~(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL),
-		  ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR);
-	i2c_write(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN,
-		  ISP1301_I2C_OTG_CONTROL_1);
-	i2c_write(~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN),
-		  ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
-	i2c_write(0xFF,
-		  ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR);
-	i2c_write(0xFF,
-		  ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR);
-	i2c_write(0xFF,
-		  ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR);
-
-}
-
-static inline void isp1301_vbus_on(void)
-{
-	i2c_write(OTG1_VBUS_DRV, ISP1301_I2C_OTG_CONTROL_1);
-}
-
-static inline void isp1301_vbus_off(void)
-{
-	i2c_write(OTG1_VBUS_DRV,
-		  ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
-}
-
-static void pnx4008_start_hc(void)
-{
-	unsigned long tmp = __raw_readl(USB_OTG_STAT_CONTROL) | HOST_EN;
-	__raw_writel(tmp, USB_OTG_STAT_CONTROL);
-	isp1301_vbus_on();
-}
-
-static void pnx4008_stop_hc(void)
-{
-	unsigned long tmp;
-	isp1301_vbus_off();
-	tmp = __raw_readl(USB_OTG_STAT_CONTROL) & ~HOST_EN;
-	__raw_writel(tmp, USB_OTG_STAT_CONTROL);
-}
-
-static int __devinit ohci_pnx4008_start(struct usb_hcd *hcd)
-{
-	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
-	int ret;
-
-	if ((ret = ohci_init(ohci)) < 0)
-		return ret;
-
-	if ((ret = ohci_run(ohci)) < 0) {
-		dev_err(hcd->self.controller, "can't start\n");
-		ohci_stop(hcd);
-		return ret;
-	}
-	return 0;
-}
-
-static const struct hc_driver ohci_pnx4008_hc_driver = {
-	.description = hcd_name,
-	.product_desc =		"pnx4008 OHCI",
-
-	/*
-	 * generic hardware linkage
-	 */
-	.irq = ohci_irq,
-	.flags = HCD_USB11 | HCD_MEMORY,
-
-	.hcd_priv_size =	sizeof(struct ohci_hcd),
-	/*
-	 * basic lifecycle operations
-	 */
-	.start = ohci_pnx4008_start,
-	.stop = ohci_stop,
-	.shutdown = ohci_shutdown,
-
-	/*
-	 * managing i/o requests and associated device resources
-	 */
-	.urb_enqueue = ohci_urb_enqueue,
-	.urb_dequeue = ohci_urb_dequeue,
-	.endpoint_disable = ohci_endpoint_disable,
-
-	/*
-	 * scheduling support
-	 */
-	.get_frame_number = ohci_get_frame,
-
-	/*
-	 * root hub support
-	 */
-	.hub_status_data = ohci_hub_status_data,
-	.hub_control = ohci_hub_control,
-#ifdef	CONFIG_PM
-	.bus_suspend = ohci_bus_suspend,
-	.bus_resume = ohci_bus_resume,
-#endif
-	.start_port_reset = ohci_start_port_reset,
-};
-
-#define USB_CLOCK_MASK (AHB_M_CLOCK_ON| OTG_CLOCK_ON | HOST_CLOCK_ON | I2C_CLOCK_ON)
-
-static void pnx4008_set_usb_bits(void)
-{
-	start_int_set_falling_edge(SE_USB_OTG_ATX_INT_N);
-	start_int_ack(SE_USB_OTG_ATX_INT_N);
-	start_int_umask(SE_USB_OTG_ATX_INT_N);
-
-	start_int_set_rising_edge(SE_USB_OTG_TIMER_INT);
-	start_int_ack(SE_USB_OTG_TIMER_INT);
-	start_int_umask(SE_USB_OTG_TIMER_INT);
-
-	start_int_set_rising_edge(SE_USB_I2C_INT);
-	start_int_ack(SE_USB_I2C_INT);
-	start_int_umask(SE_USB_I2C_INT);
-
-	start_int_set_rising_edge(SE_USB_INT);
-	start_int_ack(SE_USB_INT);
-	start_int_umask(SE_USB_INT);
-
-	start_int_set_rising_edge(SE_USB_NEED_CLK_INT);
-	start_int_ack(SE_USB_NEED_CLK_INT);
-	start_int_umask(SE_USB_NEED_CLK_INT);
-
-	start_int_set_rising_edge(SE_USB_AHB_NEED_CLK_INT);
-	start_int_ack(SE_USB_AHB_NEED_CLK_INT);
-	start_int_umask(SE_USB_AHB_NEED_CLK_INT);
-}
-
-static void pnx4008_unset_usb_bits(void)
-{
-	start_int_mask(SE_USB_OTG_ATX_INT_N);
-	start_int_mask(SE_USB_OTG_TIMER_INT);
-	start_int_mask(SE_USB_I2C_INT);
-	start_int_mask(SE_USB_INT);
-	start_int_mask(SE_USB_NEED_CLK_INT);
-	start_int_mask(SE_USB_AHB_NEED_CLK_INT);
-}
-
-static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
-{
-	struct usb_hcd *hcd = 0;
-	struct ohci_hcd *ohci;
-	const struct hc_driver *driver = &ohci_pnx4008_hc_driver;
-	struct i2c_adapter *i2c_adap;
-	struct i2c_board_info i2c_info;
-
-	int ret = 0, irq;
-
-	dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (pnx4008)\n", hcd_name);
-	if (usb_disabled()) {
-		err("USB is disabled");
-		ret = -ENODEV;
-		goto out;
-	}
-
-	if (pdev->num_resources != 2
-	    || pdev->resource[0].flags != IORESOURCE_MEM
-	    || pdev->resource[1].flags != IORESOURCE_IRQ) {
-		err("Invalid resource configuration");
-		ret = -ENODEV;
-		goto out;
-	}
-
-	/* Enable AHB slave USB clock, needed for further USB clock control */
-	__raw_writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL);
-
-	ret = i2c_add_driver(&isp1301_driver);
-	if (ret < 0) {
-		err("failed to add ISP1301 driver");
-		goto out;
-	}
-	i2c_adap = i2c_get_adapter(2);
-	memset(&i2c_info, 0, sizeof(struct i2c_board_info));
-	strlcpy(i2c_info.type, "isp1301_pnx", I2C_NAME_SIZE);
-	isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
-						   normal_i2c, NULL);
-	i2c_put_adapter(i2c_adap);
-	if (!isp1301_i2c_client) {
-		err("failed to connect I2C to ISP1301 USB Transceiver");
-		ret = -ENODEV;
-		goto out_i2c_driver;
-	}
-
-	isp1301_configure();
-
-	/* Enable USB PLL */
-	usb_clk = clk_get(&pdev->dev, "ck_pll5");
-	if (IS_ERR(usb_clk)) {
-		err("failed to acquire USB PLL");
-		ret = PTR_ERR(usb_clk);
-		goto out1;
-	}
-
-	ret = clk_enable(usb_clk);
-	if (ret < 0) {
-		err("failed to start USB PLL");
-		goto out2;
-	}
-
-	ret = clk_set_rate(usb_clk, 48000);
-	if (ret < 0) {
-		err("failed to set USB clock rate");
-		goto out3;
-	}
-
-	__raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
-
-	/* Set to enable all needed USB clocks */
-	__raw_writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL);
-
-	while ((__raw_readl(USB_OTG_CLK_STAT) & USB_CLOCK_MASK) !=
-	       USB_CLOCK_MASK) ;
-
-	hcd = usb_create_hcd (driver, &pdev->dev, dev_name(&pdev->dev));
-	if (!hcd) {
-		err("Failed to allocate HC buffer");
-		ret = -ENOMEM;
-		goto out3;
-	}
-
-	/* Set all USB bits in the Start Enable register */
-	pnx4008_set_usb_bits();
-
-	hcd->rsrc_start = pdev->resource[0].start;
-	hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		dev_dbg(&pdev->dev, "request_mem_region failed\n");
-		ret =  -ENOMEM;
-		goto out4;
-	}
-	hcd->regs = (void __iomem *)pdev->resource[0].start;
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		ret = -ENXIO;
-		goto out4;
-	}
-
-	pnx4008_start_hc();
-	platform_set_drvdata(pdev, hcd);
-	ohci = hcd_to_ohci(hcd);
-	ohci_hcd_init(ohci);
-
-	dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq);
-	ret = usb_add_hcd(hcd, irq, 0);
-	if (ret == 0)
-		return ret;
-
-	pnx4008_stop_hc();
-out4:
-	pnx4008_unset_usb_bits();
-	usb_put_hcd(hcd);
-out3:
-	clk_disable(usb_clk);
-out2:
-	clk_put(usb_clk);
-out1:
-	i2c_unregister_device(isp1301_i2c_client);
-	isp1301_i2c_client = NULL;
-out_i2c_driver:
-	i2c_del_driver(&isp1301_driver);
-out:
-	return ret;
-}
-
-static int usb_hcd_pnx4008_remove(struct platform_device *pdev)
-{
-	struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
-	usb_remove_hcd(hcd);
-	pnx4008_stop_hc();
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-	usb_put_hcd(hcd);
-	pnx4008_unset_usb_bits();
-	clk_disable(usb_clk);
-	clk_put(usb_clk);
-	i2c_unregister_device(isp1301_i2c_client);
-	isp1301_i2c_client = NULL;
-	i2c_del_driver(&isp1301_driver);
-
-	platform_set_drvdata(pdev, NULL);
-
-	return 0;
-}
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:usb-ohci");
-
-static struct platform_driver usb_hcd_pnx4008_driver = {
-	.driver = {
-		.name = "usb-ohci",
-		.owner	= THIS_MODULE,
-	},
-	.probe = usb_hcd_pnx4008_probe,
-	.remove = usb_hcd_pnx4008_remove,
-};
-
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 6313e44..c31b281 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -23,6 +23,7 @@
 #include <linux/signal.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <mach/hardware.h>
 #include <mach/ohci.h>
 #include <mach/pxa3xx-u2d.h>
 
@@ -218,7 +219,7 @@
 
 	inf = dev->platform_data;
 
-	clk_enable(ohci->clk);
+	clk_prepare_enable(ohci->clk);
 
 	pxa27x_reset_hc(ohci);
 
@@ -268,7 +269,7 @@
 	__raw_writel(uhccoms, ohci->mmio_base + UHCCOMS);
 	udelay(10);
 
-	clk_disable(ohci->clk);
+	clk_disable_unprepare(ohci->clk);
 }
 
 
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 8ff6f7e..1b19aea 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -376,7 +376,7 @@
 	 * OTG controllers and transceivers need software interaction;
 	 * other external transceivers should be software-transparent
 	 */
-	struct otg_transceiver	*transceiver;
+	struct usb_phy	*transceiver;
 	void (*start_hnp)(struct ohci_hcd *ohci);
 
 	/*
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index e84ca19..2bf1320 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -2428,6 +2428,9 @@
 	int i;
 	unsigned long irq_trigger;
 
+	if (usb_disabled())
+		return -ENODEV;
+
 	if (pdev->dev.dma_mask) {
 		ret = -EINVAL;
 		dev_err(&pdev->dev, "dma not supported\n");
@@ -2552,20 +2555,4 @@
 	},
 };
 
-static int __init r8a66597_init(void)
-{
-	if (usb_disabled())
-		return -ENODEV;
-
-	printk(KERN_INFO KBUILD_MODNAME ": driver %s, %s\n", hcd_name,
-	       DRIVER_VERSION);
-	return platform_driver_register(&r8a66597_driver);
-}
-module_init(r8a66597_init);
-
-static void __exit r8a66597_cleanup(void)
-{
-	platform_driver_unregister(&r8a66597_driver);
-}
-module_exit(r8a66597_cleanup);
-
+module_platform_driver(r8a66597_driver);
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 961d663..2a2cce2 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1632,6 +1632,9 @@
 	u8			tmp, ioaddr = 0;
 	unsigned long		irqflags;
 
+	if (usb_disabled())
+		return -ENODEV;
+
 	/* basic sanity checks first.  board-specific init logic should
 	 * have initialized these three resources and probably board
 	 * specific platform_data.  we don't probe for IRQs, and do only
@@ -1817,20 +1820,4 @@
 };
 EXPORT_SYMBOL(sl811h_driver);
 
-/*-------------------------------------------------------------------------*/
-
-static int __init sl811h_init(void)
-{
-	if (usb_disabled())
-		return -ENODEV;
-
-	INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION);
-	return platform_driver_register(&sl811h_driver);
-}
-module_init(sl811h_init);
-
-static void __exit sl811h_cleanup(void)
-{
-	platform_driver_unregister(&sl811h_driver);
-}
-module_exit(sl811h_cleanup);
+module_platform_driver(sl811h_driver);
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 6b5eb10..e37dea8 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -565,6 +565,9 @@
 	struct dentry __maybe_unused *dentry;
 
 	hcd->uses_new_polling = 1;
+	/* Accept arbitrarily long scatter-gather lists */
+	if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+		hcd->self.sg_tablesize = ~0;
 
 	spin_lock_init(&uhci->lock);
 	setup_timer(&uhci->fsbr_timer, uhci_fsbr_timeout,
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 557b6f3..673ad12 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -422,6 +422,32 @@
 	xhci_writel(xhci, temp, port_array[port_id]);
 }
 
+void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
+		__le32 __iomem **port_array, int port_id, u16 wake_mask)
+{
+	u32 temp;
+
+	temp = xhci_readl(xhci, port_array[port_id]);
+	temp = xhci_port_state_to_neutral(temp);
+
+	if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_CONNECT)
+		temp |= PORT_WKCONN_E;
+	else
+		temp &= ~PORT_WKCONN_E;
+
+	if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT)
+		temp |= PORT_WKDISC_E;
+	else
+		temp &= ~PORT_WKDISC_E;
+
+	if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT)
+		temp |= PORT_WKOC_E;
+	else
+		temp &= ~PORT_WKOC_E;
+
+	xhci_writel(xhci, temp, port_array[port_id]);
+}
+
 /* Test and clear port RWC bit */
 void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
 				int port_id, u32 port_bit)
@@ -448,6 +474,7 @@
 	int slot_id;
 	struct xhci_bus_state *bus_state;
 	u16 link_state = 0;
+	u16 wake_mask = 0;
 
 	max_ports = xhci_get_ports(hcd, &port_array);
 	bus_state = &xhci->bus_state[hcd_index(hcd)];
@@ -593,6 +620,8 @@
 	case SetPortFeature:
 		if (wValue == USB_PORT_FEAT_LINK_STATE)
 			link_state = (wIndex & 0xff00) >> 3;
+		if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK)
+			wake_mask = wIndex & 0xff00;
 		wIndex &= 0xff;
 		if (!wIndex || wIndex > max_ports)
 			goto error;
@@ -703,6 +732,14 @@
 			temp = xhci_readl(xhci, port_array[wIndex]);
 			xhci_dbg(xhci, "set port reset, actual port %d status  = 0x%x\n", wIndex, temp);
 			break;
+		case USB_PORT_FEAT_REMOTE_WAKE_MASK:
+			xhci_set_remote_wake_mask(xhci, port_array,
+					wIndex, wake_mask);
+			temp = xhci_readl(xhci, port_array[wIndex]);
+			xhci_dbg(xhci, "set port remote wake mask, "
+					"actual port %d status  = 0x%x\n",
+					wIndex, temp);
+			break;
 		case USB_PORT_FEAT_BH_PORT_RESET:
 			temp |= PORT_WR;
 			xhci_writel(xhci, temp, port_array[wIndex]);
@@ -883,6 +920,10 @@
 			t2 |= PORT_LINK_STROBE | XDEV_U3;
 			set_bit(port_index, &bus_state->bus_suspended);
 		}
+		/* USB core sets remote wake mask for USB 3.0 hubs,
+		 * including the USB 3.0 roothub, but only if CONFIG_USB_SUSPEND
+		 * is enabled, so also enable remote wake here.
+		 */
 		if (hcd->self.root_hub->do_remote_wakeup) {
 			if (t1 & PORT_CONNECT) {
 				t2 |= PORT_WKOC_E | PORT_WKDISC_E;
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 383fc85..cae4c6f 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -34,10 +34,12 @@
  * Section 4.11.1.1:
  * "All components of all Command and Transfer TRBs shall be initialized to '0'"
  */
-static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, gfp_t flags)
+static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
+					unsigned int cycle_state, gfp_t flags)
 {
 	struct xhci_segment *seg;
 	dma_addr_t	dma;
+	int		i;
 
 	seg = kzalloc(sizeof *seg, flags);
 	if (!seg)
@@ -50,6 +52,11 @@
 	}
 
 	memset(seg->trbs, 0, SEGMENT_SIZE);
+	/* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */
+	if (cycle_state == 0) {
+		for (i = 0; i < TRBS_PER_SEGMENT; i++)
+			seg->trbs[i].link.control |= TRB_CYCLE;
+	}
 	seg->dma = dma;
 	seg->next = NULL;
 
@@ -65,6 +72,20 @@
 	kfree(seg);
 }
 
+static void xhci_free_segments_for_ring(struct xhci_hcd *xhci,
+				struct xhci_segment *first)
+{
+	struct xhci_segment *seg;
+
+	seg = first->next;
+	while (seg != first) {
+		struct xhci_segment *next = seg->next;
+		xhci_segment_free(xhci, seg);
+		seg = next;
+	}
+	xhci_segment_free(xhci, first);
+}
+
 /*
  * Make the prev segment point to the next segment.
  *
@@ -73,14 +94,14 @@
  * related flags, such as End TRB, Toggle Cycle, and no snoop.
  */
 static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
-		struct xhci_segment *next, bool link_trbs, bool isoc)
+		struct xhci_segment *next, enum xhci_ring_type type)
 {
 	u32 val;
 
 	if (!prev || !next)
 		return;
 	prev->next = next;
-	if (link_trbs) {
+	if (type != TYPE_EVENT) {
 		prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr =
 			cpu_to_le64(next->dma);
 
@@ -91,35 +112,55 @@
 		/* Always set the chain bit with 0.95 hardware */
 		/* Set chain bit for isoc rings on AMD 0.96 host */
 		if (xhci_link_trb_quirk(xhci) ||
-				(isoc && (xhci->quirks & XHCI_AMD_0x96_HOST)))
+				(type == TYPE_ISOC &&
+				 (xhci->quirks & XHCI_AMD_0x96_HOST)))
 			val |= TRB_CHAIN;
 		prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
 	}
 }
 
+/*
+ * Link the ring to the new segments.
+ * Set Toggle Cycle for the new ring if needed.
+ */
+static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring,
+		struct xhci_segment *first, struct xhci_segment *last,
+		unsigned int num_segs)
+{
+	struct xhci_segment *next;
+
+	if (!ring || !first || !last)
+		return;
+
+	next = ring->enq_seg->next;
+	xhci_link_segments(xhci, ring->enq_seg, first, ring->type);
+	xhci_link_segments(xhci, last, next, ring->type);
+	ring->num_segs += num_segs;
+	ring->num_trbs_free += (TRBS_PER_SEGMENT - 1) * num_segs;
+
+	if (ring->type != TYPE_EVENT && ring->enq_seg == ring->last_seg) {
+		ring->last_seg->trbs[TRBS_PER_SEGMENT-1].link.control
+			&= ~cpu_to_le32(LINK_TOGGLE);
+		last->trbs[TRBS_PER_SEGMENT-1].link.control
+			|= cpu_to_le32(LINK_TOGGLE);
+		ring->last_seg = last;
+	}
+}
+
 /* XXX: Do we need the hcd structure in all these functions? */
 void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
 {
-	struct xhci_segment *seg;
-	struct xhci_segment *first_seg;
-
 	if (!ring)
 		return;
-	if (ring->first_seg) {
-		first_seg = ring->first_seg;
-		seg = first_seg->next;
-		while (seg != first_seg) {
-			struct xhci_segment *next = seg->next;
-			xhci_segment_free(xhci, seg);
-			seg = next;
-		}
-		xhci_segment_free(xhci, first_seg);
-		ring->first_seg = NULL;
-	}
+
+	if (ring->first_seg)
+		xhci_free_segments_for_ring(xhci, ring->first_seg);
+
 	kfree(ring);
 }
 
-static void xhci_initialize_ring_info(struct xhci_ring *ring)
+static void xhci_initialize_ring_info(struct xhci_ring *ring,
+					unsigned int cycle_state)
 {
 	/* The ring is empty, so the enqueue pointer == dequeue pointer */
 	ring->enqueue = ring->first_seg->trbs;
@@ -129,11 +170,53 @@
 	/* The ring is initialized to 0. The producer must write 1 to the cycle
 	 * bit to handover ownership of the TRB, so PCS = 1.  The consumer must
 	 * compare CCS to the cycle bit to check ownership, so CCS = 1.
+	 *
+	 * New rings are initialized with cycle state equal to 1; if we are
+	 * handling ring expansion, set the cycle state equal to the old ring.
 	 */
-	ring->cycle_state = 1;
+	ring->cycle_state = cycle_state;
 	/* Not necessary for new rings, but needed for re-initialized rings */
 	ring->enq_updates = 0;
 	ring->deq_updates = 0;
+
+	/*
+	 * Each segment has a link TRB, and leave an extra TRB for SW
+	 * accounting purpose
+	 */
+	ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1;
+}
+
+/* Allocate segments and link them for a ring */
+static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
+		struct xhci_segment **first, struct xhci_segment **last,
+		unsigned int num_segs, unsigned int cycle_state,
+		enum xhci_ring_type type, gfp_t flags)
+{
+	struct xhci_segment *prev;
+
+	prev = xhci_segment_alloc(xhci, cycle_state, flags);
+	if (!prev)
+		return -ENOMEM;
+	num_segs--;
+
+	*first = prev;
+	while (num_segs > 0) {
+		struct xhci_segment	*next;
+
+		next = xhci_segment_alloc(xhci, cycle_state, flags);
+		if (!next) {
+			xhci_free_segments_for_ring(xhci, *first);
+			return -ENOMEM;
+		}
+		xhci_link_segments(xhci, prev, next, type);
+
+		prev = next;
+		num_segs--;
+	}
+	xhci_link_segments(xhci, prev, *first, type);
+	*last = prev;
+
+	return 0;
 }
 
 /**
@@ -144,44 +227,34 @@
  * See section 4.9.1 and figures 15 and 16.
  */
 static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
-		unsigned int num_segs, bool link_trbs, bool isoc, gfp_t flags)
+		unsigned int num_segs, unsigned int cycle_state,
+		enum xhci_ring_type type, gfp_t flags)
 {
 	struct xhci_ring	*ring;
-	struct xhci_segment	*prev;
+	int ret;
 
 	ring = kzalloc(sizeof *(ring), flags);
 	if (!ring)
 		return NULL;
 
+	ring->num_segs = num_segs;
 	INIT_LIST_HEAD(&ring->td_list);
+	ring->type = type;
 	if (num_segs == 0)
 		return ring;
 
-	ring->first_seg = xhci_segment_alloc(xhci, flags);
-	if (!ring->first_seg)
+	ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg,
+			&ring->last_seg, num_segs, cycle_state, type, flags);
+	if (ret)
 		goto fail;
-	num_segs--;
 
-	prev = ring->first_seg;
-	while (num_segs > 0) {
-		struct xhci_segment	*next;
-
-		next = xhci_segment_alloc(xhci, flags);
-		if (!next)
-			goto fail;
-		xhci_link_segments(xhci, prev, next, link_trbs, isoc);
-
-		prev = next;
-		num_segs--;
-	}
-	xhci_link_segments(xhci, prev, ring->first_seg, link_trbs, isoc);
-
-	if (link_trbs) {
+	/* Only event ring does not use link TRB */
+	if (type != TYPE_EVENT) {
 		/* See section 4.9.2.1 and 6.4.4.1 */
-		prev->trbs[TRBS_PER_SEGMENT-1].link.control |=
+		ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |=
 			cpu_to_le32(LINK_TOGGLE);
 	}
-	xhci_initialize_ring_info(ring);
+	xhci_initialize_ring_info(ring, cycle_state);
 	return ring;
 
 fail:
@@ -217,23 +290,64 @@
  * pointers to the beginning of the ring.
  */
 static void xhci_reinit_cached_ring(struct xhci_hcd *xhci,
-		struct xhci_ring *ring, bool isoc)
+			struct xhci_ring *ring, unsigned int cycle_state,
+			enum xhci_ring_type type)
 {
 	struct xhci_segment	*seg = ring->first_seg;
+	int i;
+
 	do {
 		memset(seg->trbs, 0,
 				sizeof(union xhci_trb)*TRBS_PER_SEGMENT);
+		if (cycle_state == 0) {
+			for (i = 0; i < TRBS_PER_SEGMENT; i++)
+				seg->trbs[i].link.control |= TRB_CYCLE;
+		}
 		/* All endpoint rings have link TRBs */
-		xhci_link_segments(xhci, seg, seg->next, 1, isoc);
+		xhci_link_segments(xhci, seg, seg->next, type);
 		seg = seg->next;
 	} while (seg != ring->first_seg);
-	xhci_initialize_ring_info(ring);
+	ring->type = type;
+	xhci_initialize_ring_info(ring, cycle_state);
 	/* td list should be empty since all URBs have been cancelled,
 	 * but just in case...
 	 */
 	INIT_LIST_HEAD(&ring->td_list);
 }
 
+/*
+ * Expand an existing ring.
+ * Look for a cached ring or allocate a new ring which has same segment numbers
+ * and link the two rings.
+ */
+int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
+				unsigned int num_trbs, gfp_t flags)
+{
+	struct xhci_segment	*first;
+	struct xhci_segment	*last;
+	unsigned int		num_segs;
+	unsigned int		num_segs_needed;
+	int			ret;
+
+	num_segs_needed = (num_trbs + (TRBS_PER_SEGMENT - 1) - 1) /
+				(TRBS_PER_SEGMENT - 1);
+
+	/* Allocate number of segments we needed, or double the ring size */
+	num_segs = ring->num_segs > num_segs_needed ?
+			ring->num_segs : num_segs_needed;
+
+	ret = xhci_alloc_segments_for_ring(xhci, &first, &last,
+			num_segs, ring->cycle_state, ring->type, flags);
+	if (ret)
+		return -ENOMEM;
+
+	xhci_link_rings(xhci, ring, first, last, num_segs);
+	xhci_dbg(xhci, "ring expansion succeed, now has %d segments\n",
+			ring->num_segs);
+
+	return 0;
+}
+
 #define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32)
 
 static struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
@@ -528,7 +642,7 @@
 	 */
 	for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
 		stream_info->stream_rings[cur_stream] =
-			xhci_ring_alloc(xhci, 1, true, false, mem_flags);
+			xhci_ring_alloc(xhci, 2, 1, TYPE_STREAM, mem_flags);
 		cur_ring = stream_info->stream_rings[cur_stream];
 		if (!cur_ring)
 			goto cleanup_rings;
@@ -862,7 +976,7 @@
 	}
 
 	/* Allocate endpoint 0 ring */
-	dev->eps[0].ring = xhci_ring_alloc(xhci, 1, true, false, flags);
+	dev->eps[0].ring = xhci_ring_alloc(xhci, 2, 1, TYPE_CTRL, flags);
 	if (!dev->eps[0].ring)
 		goto fail;
 
@@ -1300,24 +1414,16 @@
 	struct xhci_ring *ep_ring;
 	unsigned int max_packet;
 	unsigned int max_burst;
+	enum xhci_ring_type type;
 	u32 max_esit_payload;
 
 	ep_index = xhci_get_endpoint_index(&ep->desc);
 	ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
 
+	type = usb_endpoint_type(&ep->desc);
 	/* Set up the endpoint ring */
-	/*
-	 * Isochronous endpoint ring needs bigger size because one isoc URB
-	 * carries multiple packets and it will insert multiple tds to the
-	 * ring.
-	 * This should be replaced with dynamic ring resizing in the future.
-	 */
-	if (usb_endpoint_xfer_isoc(&ep->desc))
-		virt_dev->eps[ep_index].new_ring =
-			xhci_ring_alloc(xhci, 8, true, true, mem_flags);
-	else
-		virt_dev->eps[ep_index].new_ring =
-			xhci_ring_alloc(xhci, 1, true, false, mem_flags);
+	virt_dev->eps[ep_index].new_ring =
+		xhci_ring_alloc(xhci, 2, 1, type, mem_flags);
 	if (!virt_dev->eps[ep_index].new_ring) {
 		/* Attempt to use the ring cache */
 		if (virt_dev->num_rings_cached == 0)
@@ -1327,7 +1433,7 @@
 		virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
 		virt_dev->num_rings_cached--;
 		xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
-			usb_endpoint_xfer_isoc(&ep->desc) ? true : false);
+					1, type);
 	}
 	virt_dev->eps[ep_index].skip = false;
 	ep_ring = virt_dev->eps[ep_index].new_ring;
@@ -2157,7 +2263,7 @@
 	unsigned int	val, val2;
 	u64		val_64;
 	struct xhci_segment	*seg;
-	u32 page_size;
+	u32 page_size, temp;
 	int i;
 
 	page_size = xhci_readl(xhci, &xhci->op_regs->page_size);
@@ -2235,7 +2341,7 @@
 		goto fail;
 
 	/* Set up the command ring to have one segments for now. */
-	xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, false, flags);
+	xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags);
 	if (!xhci->cmd_ring)
 		goto fail;
 	xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
@@ -2266,7 +2372,7 @@
 	 * the event ring segment table (ERST).  Section 4.9.3.
 	 */
 	xhci_dbg(xhci, "// Allocating event ring\n");
-	xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, false,
+	xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
 						flags);
 	if (!xhci->event_ring)
 		goto fail;
@@ -2340,6 +2446,15 @@
 
 	INIT_LIST_HEAD(&xhci->lpm_failed_devs);
 
+	/* Enable USB 3.0 device notifications for function remote wake, which
+	 * is necessary for allowing USB 3.0 devices to do remote wakeup from
+	 * U3 (device suspend).
+	 */
+	temp = xhci_readl(xhci, &xhci->op_regs->dev_notification);
+	temp &= ~DEV_NOTE_MASK;
+	temp |= DEV_NOTE_FWAKE;
+	xhci_writel(xhci, temp, &xhci->op_regs->dev_notification);
+
 	return 0;
 
 fail:
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
new file mode 100644
index 0000000..689bc18
--- /dev/null
+++ b/drivers/usb/host/xhci-plat.c
@@ -0,0 +1,205 @@
+/*
+ * xhci-plat.c - xHCI host controller driver platform Bus Glue.
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * A lot of code borrowed from the Linux xHCI driver.
+ *
+ * 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.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "xhci.h"
+
+static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
+{
+	/*
+	 * As of now platform drivers don't provide MSI support so we ensure
+	 * here that the generic code does not try to make a pci_dev from our
+	 * dev struct in order to setup MSI
+	 */
+	xhci->quirks |= XHCI_BROKEN_MSI;
+}
+
+/* called during probe() after chip reset completes */
+static int xhci_plat_setup(struct usb_hcd *hcd)
+{
+	return xhci_gen_setup(hcd, xhci_plat_quirks);
+}
+
+static const struct hc_driver xhci_plat_xhci_driver = {
+	.description =		"xhci-hcd",
+	.product_desc =		"xHCI Host Controller",
+	.hcd_priv_size =	sizeof(struct xhci_hcd *),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			xhci_irq,
+	.flags =		HCD_MEMORY | HCD_USB3 | HCD_SHARED,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset =		xhci_plat_setup,
+	.start =		xhci_run,
+	.stop =			xhci_stop,
+	.shutdown =		xhci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		xhci_urb_enqueue,
+	.urb_dequeue =		xhci_urb_dequeue,
+	.alloc_dev =		xhci_alloc_dev,
+	.free_dev =		xhci_free_dev,
+	.alloc_streams =	xhci_alloc_streams,
+	.free_streams =		xhci_free_streams,
+	.add_endpoint =		xhci_add_endpoint,
+	.drop_endpoint =	xhci_drop_endpoint,
+	.endpoint_reset =	xhci_endpoint_reset,
+	.check_bandwidth =	xhci_check_bandwidth,
+	.reset_bandwidth =	xhci_reset_bandwidth,
+	.address_device =	xhci_address_device,
+	.update_hub_device =	xhci_update_hub_device,
+	.reset_device =		xhci_discover_or_reset_device,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	xhci_get_frame,
+
+	/* Root hub support */
+	.hub_control =		xhci_hub_control,
+	.hub_status_data =	xhci_hub_status_data,
+	.bus_suspend =		xhci_bus_suspend,
+	.bus_resume =		xhci_bus_resume,
+};
+
+static int xhci_plat_probe(struct platform_device *pdev)
+{
+	const struct hc_driver	*driver;
+	struct xhci_hcd		*xhci;
+	struct resource         *res;
+	struct usb_hcd		*hcd;
+	int			ret;
+	int			irq;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	driver = &xhci_plat_xhci_driver;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return -ENODEV;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
+	if (!hcd)
+		return -ENOMEM;
+
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = resource_size(res);
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+				driver->description)) {
+		dev_dbg(&pdev->dev, "controller already in use\n");
+		ret = -EBUSY;
+		goto put_hcd;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		dev_dbg(&pdev->dev, "error mapping memory\n");
+		ret = -EFAULT;
+		goto release_mem_region;
+	}
+
+	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+	if (ret)
+		goto unmap_registers;
+
+	/* USB 2.0 roothub is stored in the platform_device now. */
+	hcd = dev_get_drvdata(&pdev->dev);
+	xhci = hcd_to_xhci(hcd);
+	xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev,
+			dev_name(&pdev->dev), hcd);
+	if (!xhci->shared_hcd) {
+		ret = -ENOMEM;
+		goto dealloc_usb2_hcd;
+	}
+
+	/*
+	 * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset)
+	 * is called by usb_add_hcd().
+	 */
+	*((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci;
+
+	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+	if (ret)
+		goto put_usb3_hcd;
+
+	return 0;
+
+put_usb3_hcd:
+	usb_put_hcd(xhci->shared_hcd);
+
+dealloc_usb2_hcd:
+	usb_remove_hcd(hcd);
+
+unmap_registers:
+	iounmap(hcd->regs);
+
+release_mem_region:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+put_hcd:
+	usb_put_hcd(hcd);
+
+	return ret;
+}
+
+static int xhci_plat_remove(struct platform_device *dev)
+{
+	struct usb_hcd	*hcd = platform_get_drvdata(dev);
+	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
+
+	usb_remove_hcd(xhci->shared_hcd);
+	usb_put_hcd(xhci->shared_hcd);
+
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	usb_put_hcd(hcd);
+	kfree(xhci);
+
+	return 0;
+}
+
+static struct platform_driver usb_xhci_driver = {
+	.probe	= xhci_plat_probe,
+	.remove	= xhci_plat_remove,
+	.driver	= {
+		.name = "xhci-hcd",
+	},
+};
+MODULE_ALIAS("platform:xhci-hcd");
+
+int xhci_register_plat(void)
+{
+	return platform_driver_register(&usb_xhci_driver);
+}
+
+void xhci_unregister_plat(void)
+{
+	platform_driver_unregister(&usb_xhci_driver);
+}
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index b62037b..6bd9d53 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -143,17 +143,25 @@
  * See Cycle bit rules. SW is the consumer for the event ring only.
  * Don't make a ring full of link TRBs.  That would be dumb and this would loop.
  */
-static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer)
+static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
 {
-	union xhci_trb *next = ++(ring->dequeue);
+	union xhci_trb *next;
 	unsigned long long addr;
 
 	ring->deq_updates++;
+
+	/* If this is not event ring, there is one more usable TRB */
+	if (ring->type != TYPE_EVENT &&
+			!last_trb(xhci, ring, ring->deq_seg, ring->dequeue))
+		ring->num_trbs_free++;
+	next = ++(ring->dequeue);
+
 	/* Update the dequeue pointer further if that was a link TRB or we're at
 	 * the end of an event ring segment (which doesn't have link TRBS)
 	 */
 	while (last_trb(xhci, ring, ring->deq_seg, next)) {
-		if (consumer && last_trb_on_last_seg(xhci, ring, ring->deq_seg, next)) {
+		if (ring->type == TYPE_EVENT &&	last_trb_on_last_seg(xhci,
+				ring, ring->deq_seg, next)) {
 			ring->cycle_state = (ring->cycle_state ? 0 : 1);
 		}
 		ring->deq_seg = ring->deq_seg->next;
@@ -181,13 +189,17 @@
  *			prepare_transfer()?
  */
 static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
-		bool consumer, bool more_trbs_coming, bool isoc)
+			bool more_trbs_coming)
 {
 	u32 chain;
 	union xhci_trb *next;
 	unsigned long long addr;
 
 	chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN;
+	/* If this is not event ring, there is one less usable TRB */
+	if (ring->type != TYPE_EVENT &&
+			!last_trb(xhci, ring, ring->enq_seg, ring->enqueue))
+		ring->num_trbs_free--;
 	next = ++(ring->enqueue);
 
 	ring->enq_updates++;
@@ -195,35 +207,35 @@
 	 * the end of an event ring segment (which doesn't have link TRBS)
 	 */
 	while (last_trb(xhci, ring, ring->enq_seg, next)) {
-		if (!consumer) {
-			if (ring != xhci->event_ring) {
-				/*
-				 * If the caller doesn't plan on enqueueing more
-				 * TDs before ringing the doorbell, then we
-				 * don't want to give the link TRB to the
-				 * hardware just yet.  We'll give the link TRB
-				 * back in prepare_ring() just before we enqueue
-				 * the TD at the top of the ring.
-				 */
-				if (!chain && !more_trbs_coming)
-					break;
+		if (ring->type != TYPE_EVENT) {
+			/*
+			 * If the caller doesn't plan on enqueueing more
+			 * TDs before ringing the doorbell, then we
+			 * don't want to give the link TRB to the
+			 * hardware just yet.  We'll give the link TRB
+			 * back in prepare_ring() just before we enqueue
+			 * the TD at the top of the ring.
+			 */
+			if (!chain && !more_trbs_coming)
+				break;
 
-				/* If we're not dealing with 0.95 hardware or
-				 * isoc rings on AMD 0.96 host,
-				 * carry over the chain bit of the previous TRB
-				 * (which may mean the chain bit is cleared).
-				 */
-				if (!(isoc && (xhci->quirks & XHCI_AMD_0x96_HOST))
+			/* If we're not dealing with 0.95 hardware or
+			 * isoc rings on AMD 0.96 host,
+			 * carry over the chain bit of the previous TRB
+			 * (which may mean the chain bit is cleared).
+			 */
+			if (!(ring->type == TYPE_ISOC &&
+					(xhci->quirks & XHCI_AMD_0x96_HOST))
 						&& !xhci_link_trb_quirk(xhci)) {
-					next->link.control &=
-						cpu_to_le32(~TRB_CHAIN);
-					next->link.control |=
-						cpu_to_le32(chain);
-				}
-				/* Give this link TRB to the hardware */
-				wmb();
-				next->link.control ^= cpu_to_le32(TRB_CYCLE);
+				next->link.control &=
+					cpu_to_le32(~TRB_CHAIN);
+				next->link.control |=
+					cpu_to_le32(chain);
 			}
+			/* Give this link TRB to the hardware */
+			wmb();
+			next->link.control ^= cpu_to_le32(TRB_CYCLE);
+
 			/* Toggle the cycle bit after the last ring segment. */
 			if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
 				ring->cycle_state = (ring->cycle_state ? 0 : 1);
@@ -237,55 +249,23 @@
 }
 
 /*
- * Check to see if there's room to enqueue num_trbs on the ring.  See rules
- * above.
- * FIXME: this would be simpler and faster if we just kept track of the number
- * of free TRBs in a ring.
+ * Check to see if there's room to enqueue num_trbs on the ring and make sure
+ * enqueue pointer will not advance into dequeue segment. See rules above.
  */
-static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
+static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
 		unsigned int num_trbs)
 {
-	int i;
-	union xhci_trb *enq = ring->enqueue;
-	struct xhci_segment *enq_seg = ring->enq_seg;
-	struct xhci_segment *cur_seg;
-	unsigned int left_on_ring;
+	int num_trbs_in_deq_seg;
 
-	/* If we are currently pointing to a link TRB, advance the
-	 * enqueue pointer before checking for space */
-	while (last_trb(xhci, ring, enq_seg, enq)) {
-		enq_seg = enq_seg->next;
-		enq = enq_seg->trbs;
-	}
+	if (ring->num_trbs_free < num_trbs)
+		return 0;
 
-	/* Check if ring is empty */
-	if (enq == ring->dequeue) {
-		/* Can't use link trbs */
-		left_on_ring = TRBS_PER_SEGMENT - 1;
-		for (cur_seg = enq_seg->next; cur_seg != enq_seg;
-				cur_seg = cur_seg->next)
-			left_on_ring += TRBS_PER_SEGMENT - 1;
-
-		/* Always need one TRB free in the ring. */
-		left_on_ring -= 1;
-		if (num_trbs > left_on_ring) {
-			xhci_warn(xhci, "Not enough room on ring; "
-					"need %u TRBs, %u TRBs left\n",
-					num_trbs, left_on_ring);
+	if (ring->type != TYPE_COMMAND && ring->type != TYPE_EVENT) {
+		num_trbs_in_deq_seg = ring->dequeue - ring->deq_seg->trbs;
+		if (ring->num_trbs_free < num_trbs + num_trbs_in_deq_seg)
 			return 0;
-		}
-		return 1;
 	}
-	/* Make sure there's an extra empty TRB available */
-	for (i = 0; i <= num_trbs; ++i) {
-		if (enq == ring->dequeue)
-			return 0;
-		enq++;
-		while (last_trb(xhci, ring, enq_seg, enq)) {
-			enq_seg = enq_seg->next;
-			enq = enq_seg->trbs;
-		}
-	}
+
 	return 1;
 }
 
@@ -892,6 +872,43 @@
 	xhci_dbg(xhci, "xHCI host controller is dead.\n");
 }
 
+
+static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,
+		struct xhci_virt_device *dev,
+		struct xhci_ring *ep_ring,
+		unsigned int ep_index)
+{
+	union xhci_trb *dequeue_temp;
+	int num_trbs_free_temp;
+	bool revert = false;
+
+	num_trbs_free_temp = ep_ring->num_trbs_free;
+	dequeue_temp = ep_ring->dequeue;
+
+	while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) {
+		/* We have more usable TRBs */
+		ep_ring->num_trbs_free++;
+		ep_ring->dequeue++;
+		if (last_trb(xhci, ep_ring, ep_ring->deq_seg,
+				ep_ring->dequeue)) {
+			if (ep_ring->dequeue ==
+					dev->eps[ep_index].queued_deq_ptr)
+				break;
+			ep_ring->deq_seg = ep_ring->deq_seg->next;
+			ep_ring->dequeue = ep_ring->deq_seg->trbs;
+		}
+		if (ep_ring->dequeue == dequeue_temp) {
+			revert = true;
+			break;
+		}
+	}
+
+	if (revert) {
+		xhci_dbg(xhci, "Unable to find new dequeue pointer\n");
+		ep_ring->num_trbs_free = num_trbs_free_temp;
+	}
+}
+
 /*
  * When we get a completion for a Set Transfer Ring Dequeue Pointer command,
  * we need to clear the set deq pending flag in the endpoint ring state, so that
@@ -973,8 +990,8 @@
 			/* Update the ring's dequeue segment and dequeue pointer
 			 * to reflect the new position.
 			 */
-			ep_ring->deq_seg = dev->eps[ep_index].queued_deq_seg;
-			ep_ring->dequeue = dev->eps[ep_index].queued_deq_ptr;
+			update_ring_for_set_deq_completion(xhci, dev,
+				ep_ring, ep_index);
 		} else {
 			xhci_warn(xhci, "Mismatch between completed Set TR Deq "
 					"Ptr command & xHCI internal state.\n");
@@ -1185,7 +1202,7 @@
 		xhci->error_bitmask |= 1 << 6;
 		break;
 	}
-	inc_deq(xhci, xhci->cmd_ring, false);
+	inc_deq(xhci, xhci->cmd_ring);
 }
 
 static void handle_vendor_event(struct xhci_hcd *xhci,
@@ -1237,6 +1254,26 @@
 	return num_similar_speed_ports;
 }
 
+static void handle_device_notification(struct xhci_hcd *xhci,
+		union xhci_trb *event)
+{
+	u32 slot_id;
+	struct usb_device *udev;
+
+	slot_id = TRB_TO_SLOT_ID(event->generic.field[3]);
+	if (!xhci->devs[slot_id]) {
+		xhci_warn(xhci, "Device Notification event for "
+				"unused slot %u\n", slot_id);
+		return;
+	}
+
+	xhci_dbg(xhci, "Device Wake Notification event for slot ID %u\n",
+			slot_id);
+	udev = xhci->devs[slot_id]->udev;
+	if (udev && udev->parent)
+		usb_wakeup_notification(udev->parent, udev->portnum);
+}
+
 static void handle_port_status(struct xhci_hcd *xhci,
 		union xhci_trb *event)
 {
@@ -1321,20 +1358,21 @@
 		}
 
 		if (DEV_SUPERSPEED(temp)) {
-			xhci_dbg(xhci, "resume SS port %d\n", port_id);
+			xhci_dbg(xhci, "remote wake SS port %d\n", port_id);
+			/* Set a flag to say the port signaled remote wakeup,
+			 * so we can tell the difference between the end of
+			 * device and host initiated resume.
+			 */
+			bus_state->port_remote_wakeup |= 1 << faked_port_index;
+			xhci_test_and_clear_bit(xhci, port_array,
+					faked_port_index, PORT_PLC);
 			xhci_set_link_state(xhci, port_array, faked_port_index,
 						XDEV_U0);
-			slot_id = xhci_find_slot_id_by_port(hcd, xhci,
-					faked_port_index + 1);
-			if (!slot_id) {
-				xhci_dbg(xhci, "slot_id is zero\n");
-				goto cleanup;
-			}
-			xhci_ring_device(xhci, slot_id);
-			xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
-			/* Clear PORT_PLC */
-			xhci_test_and_clear_bit(xhci, port_array,
-						faked_port_index, PORT_PLC);
+			/* Need to wait until the next link state change
+			 * indicates the device is actually in U0.
+			 */
+			bogus_port_status = true;
+			goto cleanup;
 		} else {
 			xhci_dbg(xhci, "resume HS port %d\n", port_id);
 			bus_state->resume_done[faked_port_index] = jiffies +
@@ -1345,13 +1383,39 @@
 		}
 	}
 
+	if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_U0 &&
+			DEV_SUPERSPEED(temp)) {
+		xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
+		/* We've just brought the device into U0 through either the
+		 * Resume state after a device remote wakeup, or through the
+		 * U3Exit state after a host-initiated resume.  If it's a device
+		 * initiated remote wake, don't pass up the link state change,
+		 * so the roothub behavior is consistent with external
+		 * USB 3.0 hub behavior.
+		 */
+		slot_id = xhci_find_slot_id_by_port(hcd, xhci,
+				faked_port_index + 1);
+		if (slot_id && xhci->devs[slot_id])
+			xhci_ring_device(xhci, slot_id);
+		if (bus_state->port_remote_wakeup && (1 << faked_port_index)) {
+			bus_state->port_remote_wakeup &=
+				~(1 << faked_port_index);
+			xhci_test_and_clear_bit(xhci, port_array,
+					faked_port_index, PORT_PLC);
+			usb_wakeup_notification(hcd->self.root_hub,
+					faked_port_index + 1);
+			bogus_port_status = true;
+			goto cleanup;
+		}
+	}
+
 	if (hcd->speed != HCD_USB3)
 		xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
 					PORT_PLC);
 
 cleanup:
 	/* Update event ring dequeue pointer before dropping the lock */
-	inc_deq(xhci, xhci->event_ring, true);
+	inc_deq(xhci, xhci->event_ring);
 
 	/* Don't make the USB core poll the roothub if we got a bad port status
 	 * change event.  Besides, at that point we can't tell which roothub
@@ -1546,8 +1610,8 @@
 		} else {
 			/* Update ring dequeue pointer */
 			while (ep_ring->dequeue != td->last_trb)
-				inc_deq(xhci, ep_ring, false);
-			inc_deq(xhci, ep_ring, false);
+				inc_deq(xhci, ep_ring);
+			inc_deq(xhci, ep_ring);
 		}
 
 td_cleanup:
@@ -1795,8 +1859,8 @@
 
 	/* Update ring dequeue pointer */
 	while (ep_ring->dequeue != td->last_trb)
-		inc_deq(xhci, ep_ring, false);
-	inc_deq(xhci, ep_ring, false);
+		inc_deq(xhci, ep_ring);
+	inc_deq(xhci, ep_ring);
 
 	return finish_td(xhci, td, NULL, event, ep, status, true);
 }
@@ -2183,7 +2247,7 @@
 		 * Will roll back to continue process missed tds.
 		 */
 		if (trb_comp_code == COMP_MISSED_INT || !ep->skip) {
-			inc_deq(xhci, xhci->event_ring, true);
+			inc_deq(xhci, xhci->event_ring);
 		}
 
 		if (ret) {
@@ -2277,6 +2341,9 @@
 		else
 			update_ptrs = 0;
 		break;
+	case TRB_TYPE(TRB_DEV_NOTE):
+		handle_device_notification(xhci, event);
+		break;
 	default:
 		if ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) >=
 		    TRB_TYPE(48))
@@ -2295,7 +2362,7 @@
 
 	if (update_ptrs)
 		/* Update SW event ring dequeue pointer */
-		inc_deq(xhci, xhci->event_ring, true);
+		inc_deq(xhci, xhci->event_ring);
 
 	/* Are there more items on the event ring?  Caller will call us again to
 	 * check.
@@ -2346,7 +2413,7 @@
 	/* FIXME when MSI-X is supported and there are multiple vectors */
 	/* Clear the MSI-X event interrupt status */
 
-	if (hcd->irq != -1) {
+	if (hcd->irq) {
 		u32 irq_pending;
 		/* Acknowledge the PCI interrupt */
 		irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
@@ -2411,7 +2478,7 @@
  *			prepare_transfer()?
  */
 static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
-		bool consumer, bool more_trbs_coming, bool isoc,
+		bool more_trbs_coming,
 		u32 field1, u32 field2, u32 field3, u32 field4)
 {
 	struct xhci_generic_trb *trb;
@@ -2421,7 +2488,7 @@
 	trb->field[1] = cpu_to_le32(field2);
 	trb->field[2] = cpu_to_le32(field3);
 	trb->field[3] = cpu_to_le32(field4);
-	inc_enq(xhci, ring, consumer, more_trbs_coming, isoc);
+	inc_enq(xhci, ring, more_trbs_coming);
 }
 
 /*
@@ -2429,8 +2496,10 @@
  * FIXME allocate segments if the ring is full.
  */
 static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
-		u32 ep_state, unsigned int num_trbs, bool isoc, gfp_t mem_flags)
+		u32 ep_state, unsigned int num_trbs, gfp_t mem_flags)
 {
+	unsigned int num_trbs_needed;
+
 	/* Make sure the endpoint has been added to xHC schedule */
 	switch (ep_state) {
 	case EP_STATE_DISABLED:
@@ -2458,11 +2527,25 @@
 		 */
 		return -EINVAL;
 	}
-	if (!room_on_ring(xhci, ep_ring, num_trbs)) {
-		/* FIXME allocate more room */
-		xhci_err(xhci, "ERROR no room on ep ring\n");
-		return -ENOMEM;
-	}
+
+	while (1) {
+		if (room_on_ring(xhci, ep_ring, num_trbs))
+			break;
+
+		if (ep_ring == xhci->cmd_ring) {
+			xhci_err(xhci, "Do not support expand command ring\n");
+			return -ENOMEM;
+		}
+
+		xhci_dbg(xhci, "ERROR no room on ep ring, "
+					"try ring expansion\n");
+		num_trbs_needed = num_trbs - ep_ring->num_trbs_free;
+		if (xhci_ring_expansion(xhci, ep_ring, num_trbs_needed,
+					mem_flags)) {
+			xhci_err(xhci, "Ring expansion failed\n");
+			return -ENOMEM;
+		}
+	};
 
 	if (enqueue_is_link_trb(ep_ring)) {
 		struct xhci_ring *ring = ep_ring;
@@ -2474,8 +2557,9 @@
 			/* If we're not dealing with 0.95 hardware or isoc rings
 			 * on AMD 0.96 host, clear the chain bit.
 			 */
-			if (!xhci_link_trb_quirk(xhci) && !(isoc &&
-					(xhci->quirks & XHCI_AMD_0x96_HOST)))
+			if (!xhci_link_trb_quirk(xhci) &&
+					!(ring->type == TYPE_ISOC &&
+					 (xhci->quirks & XHCI_AMD_0x96_HOST)))
 				next->link.control &= cpu_to_le32(~TRB_CHAIN);
 			else
 				next->link.control |= cpu_to_le32(TRB_CHAIN);
@@ -2503,7 +2587,6 @@
 		unsigned int num_trbs,
 		struct urb *urb,
 		unsigned int td_index,
-		bool isoc,
 		gfp_t mem_flags)
 {
 	int ret;
@@ -2521,7 +2604,7 @@
 
 	ret = prepare_ring(xhci, ep_ring,
 			   le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
-			   num_trbs, isoc, mem_flags);
+			   num_trbs, mem_flags);
 	if (ret)
 		return ret;
 
@@ -2731,7 +2814,7 @@
 
 	trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id],
 			ep_index, urb->stream_id,
-			num_trbs, urb, 0, false, mem_flags);
+			num_trbs, urb, 0, mem_flags);
 	if (trb_buff_len < 0)
 		return trb_buff_len;
 
@@ -2819,7 +2902,7 @@
 			more_trbs_coming = true;
 		else
 			more_trbs_coming = false;
-		queue_trb(xhci, ep_ring, false, more_trbs_coming, false,
+		queue_trb(xhci, ep_ring, more_trbs_coming,
 				lower_32_bits(addr),
 				upper_32_bits(addr),
 				length_field,
@@ -2901,7 +2984,7 @@
 
 	ret = prepare_transfer(xhci, xhci->devs[slot_id],
 			ep_index, urb->stream_id,
-			num_trbs, urb, 0, false, mem_flags);
+			num_trbs, urb, 0, mem_flags);
 	if (ret < 0)
 		return ret;
 
@@ -2973,7 +3056,7 @@
 			more_trbs_coming = true;
 		else
 			more_trbs_coming = false;
-		queue_trb(xhci, ep_ring, false, more_trbs_coming, false,
+		queue_trb(xhci, ep_ring, more_trbs_coming,
 				lower_32_bits(addr),
 				upper_32_bits(addr),
 				length_field,
@@ -3030,7 +3113,7 @@
 		num_trbs++;
 	ret = prepare_transfer(xhci, xhci->devs[slot_id],
 			ep_index, urb->stream_id,
-			num_trbs, urb, 0, false, mem_flags);
+			num_trbs, urb, 0, mem_flags);
 	if (ret < 0)
 		return ret;
 
@@ -3063,7 +3146,7 @@
 		}
 	}
 
-	queue_trb(xhci, ep_ring, false, true, false,
+	queue_trb(xhci, ep_ring, true,
 		  setup->bRequestType | setup->bRequest << 8 | le16_to_cpu(setup->wValue) << 16,
 		  le16_to_cpu(setup->wIndex) | le16_to_cpu(setup->wLength) << 16,
 		  TRB_LEN(8) | TRB_INTR_TARGET(0),
@@ -3083,7 +3166,7 @@
 	if (urb->transfer_buffer_length > 0) {
 		if (setup->bRequestType & USB_DIR_IN)
 			field |= TRB_DIR_IN;
-		queue_trb(xhci, ep_ring, false, true, false,
+		queue_trb(xhci, ep_ring, true,
 				lower_32_bits(urb->transfer_dma),
 				upper_32_bits(urb->transfer_dma),
 				length_field,
@@ -3099,7 +3182,7 @@
 		field = 0;
 	else
 		field = TRB_DIR_IN;
-	queue_trb(xhci, ep_ring, false, false, false,
+	queue_trb(xhci, ep_ring, false,
 			0,
 			0,
 			TRB_INTR_TARGET(0),
@@ -3239,8 +3322,7 @@
 		trbs_per_td = count_isoc_trbs_needed(xhci, urb, i);
 
 		ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index,
-				urb->stream_id, trbs_per_td, urb, i, true,
-				mem_flags);
+				urb->stream_id, trbs_per_td, urb, i, mem_flags);
 		if (ret < 0) {
 			if (i == 0)
 				return ret;
@@ -3310,7 +3392,7 @@
 				remainder |
 				TRB_INTR_TARGET(0);
 
-			queue_trb(xhci, ep_ring, false, more_trbs_coming, true,
+			queue_trb(xhci, ep_ring, more_trbs_coming,
 				lower_32_bits(addr),
 				upper_32_bits(addr),
 				length_field,
@@ -3357,6 +3439,7 @@
 	ep_ring->enqueue = urb_priv->td[0]->first_trb;
 	ep_ring->enq_seg = urb_priv->td[0]->start_seg;
 	ep_ring->cycle_state = start_cycle;
+	ep_ring->num_trbs_free = ep_ring->num_trbs_free_temp;
 	usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
 	return ret;
 }
@@ -3393,7 +3476,7 @@
 	 * Do not insert any td of the urb to the ring if the check failed.
 	 */
 	ret = prepare_ring(xhci, ep_ring, le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
-			   num_trbs, true, mem_flags);
+			   num_trbs, mem_flags);
 	if (ret)
 		return ret;
 
@@ -3429,6 +3512,8 @@
 				urb->dev->speed == USB_SPEED_FULL)
 			urb->interval /= 8;
 	}
+	ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free;
+
 	return xhci_queue_isoc_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index);
 }
 
@@ -3452,7 +3537,7 @@
 		reserved_trbs++;
 
 	ret = prepare_ring(xhci, xhci->cmd_ring, EP_STATE_RUNNING,
-			reserved_trbs, false, GFP_ATOMIC);
+			reserved_trbs, GFP_ATOMIC);
 	if (ret < 0) {
 		xhci_err(xhci, "ERR: No room for command on command ring\n");
 		if (command_must_succeed)
@@ -3460,8 +3545,8 @@
 					"unfailable commands failed.\n");
 		return ret;
 	}
-	queue_trb(xhci, xhci->cmd_ring, false, false, false, field1, field2,
-			field3,	field4 | xhci->cmd_ring->cycle_state);
+	queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3,
+			field4 | xhci->cmd_ring->cycle_state);
 	return 0;
 }
 
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index c939f5f..e1963d4 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -224,13 +224,13 @@
 	int ret;
 
 	/* return if using legacy interrupt */
-	if (xhci_to_hcd(xhci)->irq >= 0)
+	if (xhci_to_hcd(xhci)->irq > 0)
 		return;
 
 	ret = xhci_free_msi(xhci);
 	if (!ret)
 		return;
-	if (pdev->irq >= 0)
+	if (pdev->irq > 0)
 		free_irq(pdev->irq, xhci_to_hcd(xhci));
 
 	return;
@@ -341,7 +341,7 @@
 	/* unregister the legacy interrupt */
 	if (hcd->irq)
 		free_irq(hcd->irq, hcd);
-	hcd->irq = -1;
+	hcd->irq = 0;
 
 	ret = xhci_setup_msix(xhci);
 	if (ret)
@@ -349,7 +349,7 @@
 		ret = xhci_setup_msi(xhci);
 
 	if (!ret)
-		/* hcd->irq is -1, we have MSI */
+		/* hcd->irq is 0, we have MSI */
 		return 0;
 
 	if (!pdev->irq) {
@@ -729,6 +729,7 @@
 	ring->enq_seg = ring->deq_seg;
 	ring->enqueue = ring->dequeue;
 
+	ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1;
 	/*
 	 * Ring is now zeroed, so the HW should look for change of ownership
 	 * when the cycle bit is set to 1.
@@ -3614,26 +3615,38 @@
 	3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000};
 
 /* Calculate HIRD/BESL for USB2 PORTPMSC*/
-static int xhci_calculate_hird_besl(int u2del, bool use_besl)
+static int xhci_calculate_hird_besl(struct xhci_hcd *xhci,
+					struct usb_device *udev)
 {
-	int hird;
+	int u2del, besl, besl_host;
+	int besl_device = 0;
+	u32 field;
 
-	if (use_besl) {
-		for (hird = 0; hird < 16; hird++) {
-			if (xhci_besl_encoding[hird] >= u2del)
+	u2del = HCS_U2_LATENCY(xhci->hcs_params3);
+	field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);
+
+	if (field & USB_BESL_SUPPORT) {
+		for (besl_host = 0; besl_host < 16; besl_host++) {
+			if (xhci_besl_encoding[besl_host] >= u2del)
 				break;
 		}
+		/* Use baseline BESL value as default */
+		if (field & USB_BESL_BASELINE_VALID)
+			besl_device = USB_GET_BESL_BASELINE(field);
+		else if (field & USB_BESL_DEEP_VALID)
+			besl_device = USB_GET_BESL_DEEP(field);
 	} else {
 		if (u2del <= 50)
-			hird = 0;
+			besl_host = 0;
 		else
-			hird = (u2del - 51) / 75 + 1;
-
-		if (hird > 15)
-			hird = 15;
+			besl_host = (u2del - 51) / 75 + 1;
 	}
 
-	return hird;
+	besl = besl_host + besl_device;
+	if (besl > 15)
+		besl = 15;
+
+	return besl;
 }
 
 static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
@@ -3646,7 +3659,7 @@
 	u32		temp, dev_id;
 	unsigned int	port_num;
 	unsigned long	flags;
-	int		u2del, hird;
+	int		hird;
 	int		ret;
 
 	if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support ||
@@ -3692,12 +3705,7 @@
 	 * HIRD or BESL shoule be used. See USB2.0 LPM errata.
 	 */
 	pm_addr = port_array[port_num] + 1;
-	u2del = HCS_U2_LATENCY(xhci->hcs_params3);
-	if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2))
-		hird = xhci_calculate_hird_besl(u2del, 1);
-	else
-		hird = xhci_calculate_hird_besl(u2del, 0);
-
+	hird = xhci_calculate_hird_besl(xhci, udev);
 	temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird);
 	xhci_writel(xhci, temp, pm_addr);
 
@@ -3776,7 +3784,7 @@
 	u32		temp;
 	unsigned int	port_num;
 	unsigned long	flags;
-	int		u2del, hird;
+	int		hird;
 
 	if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support ||
 			!udev->lpm_capable)
@@ -3799,11 +3807,7 @@
 	xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",
 			enable ? "enable" : "disable", port_num);
 
-	u2del = HCS_U2_LATENCY(xhci->hcs_params3);
-	if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2))
-		hird = xhci_calculate_hird_besl(u2del, 1);
-	else
-		hird = xhci_calculate_hird_besl(u2del, 0);
+	hird = xhci_calculate_hird_besl(xhci, udev);
 
 	if (enable) {
 		temp &= ~PORT_HIRD_MASK;
@@ -3964,7 +3968,8 @@
 	int			retval;
 	u32			temp;
 
-	hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2;
+	/* Accept arbitrarily long scatter-gather lists */
+	hcd->self.sg_tablesize = ~0;
 
 	if (usb_hcd_is_primary_hcd(hcd)) {
 		xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL);
@@ -4059,6 +4064,11 @@
 		printk(KERN_DEBUG "Problem registering PCI driver.");
 		return retval;
 	}
+	retval = xhci_register_plat();
+	if (retval < 0) {
+		printk(KERN_DEBUG "Problem registering platform driver.");
+		goto unreg_pci;
+	}
 	/*
 	 * Check the compiler generated sizes of structures that must be laid
 	 * out in specific ways for hardware access.
@@ -4078,11 +4088,15 @@
 	BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
 	BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8);
 	return 0;
+unreg_pci:
+	xhci_unregister_pci();
+	return retval;
 }
 module_init(xhci_hcd_init);
 
 static void __exit xhci_hcd_cleanup(void)
 {
 	xhci_unregister_pci();
+	xhci_unregister_plat();
 }
 module_exit(xhci_hcd_cleanup);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index fb99c83..91074fd 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1223,10 +1223,7 @@
 /* Allow two commands + a link TRB, along with any reserved command TRBs */
 #define MAX_RSVD_CMD_TRBS	(TRBS_PER_SEGMENT - 3)
 #define SEGMENT_SIZE		(TRBS_PER_SEGMENT*16)
-/* SEGMENT_SHIFT should be log2(SEGMENT_SIZE).
- * Change this if you change TRBS_PER_SEGMENT!
- */
-#define SEGMENT_SHIFT		10
+#define SEGMENT_SHIFT		(__ffs(SEGMENT_SIZE))
 /* TRB buffer pointers can't cross 64KB boundaries */
 #define TRB_MAX_BUFF_SHIFT		16
 #define TRB_MAX_BUFF_SIZE	(1 << TRB_MAX_BUFF_SHIFT)
@@ -1253,8 +1250,19 @@
 	int new_cycle_state;
 };
 
+enum xhci_ring_type {
+	TYPE_CTRL = 0,
+	TYPE_ISOC,
+	TYPE_BULK,
+	TYPE_INTR,
+	TYPE_STREAM,
+	TYPE_COMMAND,
+	TYPE_EVENT,
+};
+
 struct xhci_ring {
 	struct xhci_segment	*first_seg;
+	struct xhci_segment	*last_seg;
 	union  xhci_trb		*enqueue;
 	struct xhci_segment	*enq_seg;
 	unsigned int		enq_updates;
@@ -1269,6 +1277,10 @@
 	 */
 	u32			cycle_state;
 	unsigned int		stream_id;
+	unsigned int		num_segs;
+	unsigned int		num_trbs_free;
+	unsigned int		num_trbs_free_temp;
+	enum xhci_ring_type	type;
 	bool			last_td_was_short;
 };
 
@@ -1344,6 +1356,7 @@
 	/* ports suspend status arrays - max 31 ports for USB2, 15 for USB3 */
 	u32			port_c_suspend;
 	u32			suspended_ports;
+	u32			port_remote_wakeup;
 	unsigned long		resume_done[USB_MAXCHILDREN];
 };
 
@@ -1609,6 +1622,8 @@
 		struct usb_device *udev, struct usb_host_endpoint *ep,
 		gfp_t mem_flags);
 void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring);
+int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
+				unsigned int num_trbs, gfp_t flags);
 void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
 		struct xhci_virt_device *virt_dev,
 		unsigned int ep_index);
@@ -1648,6 +1663,17 @@
 static inline void xhci_unregister_pci(void) {}
 #endif
 
+#if defined(CONFIG_USB_XHCI_PLATFORM) \
+	|| defined(CONFIG_USB_XHCI_PLATFORM_MODULE)
+int xhci_register_plat(void);
+void xhci_unregister_plat(void);
+#else
+static inline int xhci_register_plat(void)
+{ return 0; }
+static inline void xhci_unregister_plat(void)
+{  }
+#endif
+
 /* xHCI host controller glue */
 typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
 void xhci_quiesce(struct xhci_hcd *xhci);
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c
index e233d2b..9f3eda9 100644
--- a/drivers/usb/musb/am35x.c
+++ b/drivers/usb/musb/am35x.c
@@ -226,6 +226,7 @@
 	struct device *dev = musb->controller;
 	struct musb_hdrc_platform_data *plat = dev->platform_data;
 	struct omap_musb_board_data *data = plat->board_data;
+	struct usb_otg *otg = musb->xceiv->otg;
 	unsigned long flags;
 	irqreturn_t ret = IRQ_NONE;
 	u32 epintr, usbintr;
@@ -289,14 +290,14 @@
 			WARNING("VBUS error workaround (delay coming)\n");
 		} else if (is_host_enabled(musb) && drvvbus) {
 			MUSB_HST_MODE(musb);
-			musb->xceiv->default_a = 1;
+			otg->default_a = 1;
 			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
 			portstate(musb->port1_status |= USB_PORT_STAT_POWER);
 			del_timer(&otg_workaround);
 		} else {
 			musb->is_active = 0;
 			MUSB_DEV_MODE(musb);
-			musb->xceiv->default_a = 0;
+			otg->default_a = 0;
 			musb->xceiv->state = OTG_STATE_B_IDLE;
 			portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
 		}
@@ -363,7 +364,7 @@
 		return -ENODEV;
 
 	usb_nop_xceiv_register();
-	musb->xceiv = otg_get_transceiver();
+	musb->xceiv = usb_get_transceiver();
 	if (!musb->xceiv)
 		return -ENODEV;
 
@@ -405,7 +406,7 @@
 	if (data->set_phy_power)
 		data->set_phy_power(0);
 
-	otg_put_transceiver(musb->xceiv);
+	usb_put_transceiver(musb->xceiv);
 	usb_nop_xceiv_unregister();
 
 	return 0;
@@ -456,7 +457,7 @@
 
 static u64 am35x_dmamask = DMA_BIT_MASK(32);
 
-static int __init am35x_probe(struct platform_device *pdev)
+static int __devinit am35x_probe(struct platform_device *pdev)
 {
 	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
 	struct platform_device		*musb;
@@ -561,7 +562,7 @@
 	return ret;
 }
 
-static int __exit am35x_remove(struct platform_device *pdev)
+static int __devexit am35x_remove(struct platform_device *pdev)
 {
 	struct am35x_glue	*glue = platform_get_drvdata(pdev);
 
@@ -630,7 +631,8 @@
 #endif
 
 static struct platform_driver am35x_driver = {
-	.remove		= __exit_p(am35x_remove),
+	.probe		= am35x_probe,
+	.remove		= __devexit_p(am35x_remove),
 	.driver		= {
 		.name	= "musb-am35x",
 		.pm	= DEV_PM_OPS,
@@ -643,9 +645,9 @@
 
 static int __init am35x_init(void)
 {
-	return platform_driver_probe(&am35x_driver, am35x_probe);
+	return platform_driver_register(&am35x_driver);
 }
-subsys_initcall(am35x_init);
+module_init(am35x_init);
 
 static void __exit am35x_exit(void)
 {
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index 5e7cfba..a087ed6 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -317,7 +317,7 @@
 		musb_readb(musb->mregs, MUSB_DEVCTL));
 }
 
-static int bfin_musb_set_power(struct otg_transceiver *x, unsigned mA)
+static int bfin_musb_set_power(struct usb_phy *x, unsigned mA)
 {
 	return 0;
 }
@@ -415,7 +415,7 @@
 	gpio_direction_output(musb->config->gpio_vrsel, 0);
 
 	usb_nop_xceiv_register();
-	musb->xceiv = otg_get_transceiver();
+	musb->xceiv = usb_get_transceiver();
 	if (!musb->xceiv) {
 		gpio_free(musb->config->gpio_vrsel);
 		return -ENODEV;
@@ -440,7 +440,7 @@
 {
 	gpio_free(musb->config->gpio_vrsel);
 
-	otg_put_transceiver(musb->xceiv);
+	usb_put_transceiver(musb->xceiv);
 	usb_nop_xceiv_unregister();
 	return 0;
 }
@@ -463,7 +463,7 @@
 
 static u64 bfin_dmamask = DMA_BIT_MASK(32);
 
-static int __init bfin_probe(struct platform_device *pdev)
+static int __devinit bfin_probe(struct platform_device *pdev)
 {
 	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
 	struct platform_device		*musb;
@@ -525,7 +525,7 @@
 	return ret;
 }
 
-static int __exit bfin_remove(struct platform_device *pdev)
+static int __devexit bfin_remove(struct platform_device *pdev)
 {
 	struct bfin_glue		*glue = platform_get_drvdata(pdev);
 
@@ -575,6 +575,7 @@
 #endif
 
 static struct platform_driver bfin_driver = {
+	.probe		= bfin_probe,
 	.remove		= __exit_p(bfin_remove),
 	.driver		= {
 		.name	= "musb-blackfin",
@@ -588,9 +589,9 @@
 
 static int __init bfin_init(void)
 {
-	return platform_driver_probe(&bfin_driver, bfin_probe);
+	return platform_driver_register(&bfin_driver);
 }
-subsys_initcall(bfin_init);
+module_init(bfin_init);
 
 static void __exit bfin_exit(void)
 {
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index 2613bfd..8bd9566 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -294,6 +294,7 @@
 {
 	struct musb		*musb = hci;
 	void __iomem		*reg_base = musb->ctrl_base;
+	struct usb_otg		*otg = musb->xceiv->otg;
 	unsigned long		flags;
 	irqreturn_t		ret = IRQ_NONE;
 	u32			status;
@@ -351,14 +352,14 @@
 			WARNING("VBUS error workaround (delay coming)\n");
 		} else if (is_host_enabled(musb) && drvvbus) {
 			MUSB_HST_MODE(musb);
-			musb->xceiv->default_a = 1;
+			otg->default_a = 1;
 			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
 			portstate(musb->port1_status |= USB_PORT_STAT_POWER);
 			del_timer(&otg_workaround);
 		} else {
 			musb->is_active = 0;
 			MUSB_DEV_MODE(musb);
-			musb->xceiv->default_a = 0;
+			otg->default_a = 0;
 			musb->xceiv->state = OTG_STATE_B_IDLE;
 			portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
 		}
@@ -424,7 +425,7 @@
 		goto fail;
 
 	usb_nop_xceiv_register();
-	musb->xceiv = otg_get_transceiver();
+	musb->xceiv = usb_get_transceiver();
 	if (!musb->xceiv)
 		goto fail;
 
@@ -457,7 +458,7 @@
 
 	phy_off();
 
-	otg_put_transceiver(musb->xceiv);
+	usb_put_transceiver(musb->xceiv);
 	usb_nop_xceiv_unregister();
 
 	return 0;
@@ -478,7 +479,7 @@
 
 static u64 da8xx_dmamask = DMA_BIT_MASK(32);
 
-static int __init da8xx_probe(struct platform_device *pdev)
+static int __devinit da8xx_probe(struct platform_device *pdev)
 {
 	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
 	struct platform_device		*musb;
@@ -562,7 +563,7 @@
 	return ret;
 }
 
-static int __exit da8xx_remove(struct platform_device *pdev)
+static int __devexit da8xx_remove(struct platform_device *pdev)
 {
 	struct da8xx_glue		*glue = platform_get_drvdata(pdev);
 
@@ -576,7 +577,8 @@
 }
 
 static struct platform_driver da8xx_driver = {
-	.remove		= __exit_p(da8xx_remove),
+	.probe		= da8xx_probe,
+	.remove		= __devexit_p(da8xx_remove),
 	.driver		= {
 		.name	= "musb-da8xx",
 	},
@@ -588,9 +590,9 @@
 
 static int __init da8xx_init(void)
 {
-	return platform_driver_probe(&da8xx_driver, da8xx_probe);
+	return platform_driver_register(&da8xx_driver);
 }
-subsys_initcall(da8xx_init);
+module_init(da8xx_init);
 
 static void __exit da8xx_exit(void)
 {
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index 7c569f5..97ab975 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -265,6 +265,7 @@
 	unsigned long	flags;
 	irqreturn_t	retval = IRQ_NONE;
 	struct musb	*musb = __hci;
+	struct usb_otg	*otg = musb->xceiv->otg;
 	void __iomem	*tibase = musb->ctrl_base;
 	struct cppi	*cppi;
 	u32		tmp;
@@ -331,14 +332,14 @@
 			WARNING("VBUS error workaround (delay coming)\n");
 		} else if (is_host_enabled(musb) && drvvbus) {
 			MUSB_HST_MODE(musb);
-			musb->xceiv->default_a = 1;
+			otg->default_a = 1;
 			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
 			portstate(musb->port1_status |= USB_PORT_STAT_POWER);
 			del_timer(&otg_workaround);
 		} else {
 			musb->is_active = 0;
 			MUSB_DEV_MODE(musb);
-			musb->xceiv->default_a = 0;
+			otg->default_a = 0;
 			musb->xceiv->state = OTG_STATE_B_IDLE;
 			portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
 		}
@@ -383,7 +384,7 @@
 	u32		revision;
 
 	usb_nop_xceiv_register();
-	musb->xceiv = otg_get_transceiver();
+	musb->xceiv = usb_get_transceiver();
 	if (!musb->xceiv)
 		return -ENODEV;
 
@@ -442,7 +443,7 @@
 	return 0;
 
 fail:
-	otg_put_transceiver(musb->xceiv);
+	usb_put_transceiver(musb->xceiv);
 	usb_nop_xceiv_unregister();
 	return -ENODEV;
 }
@@ -464,7 +465,7 @@
 	davinci_musb_source_power(musb, 0 /*off*/, 1);
 
 	/* delay, to avoid problems with module reload */
-	if (is_host_enabled(musb) && musb->xceiv->default_a) {
+	if (is_host_enabled(musb) && musb->xceiv->otg->default_a) {
 		int	maxdelay = 30;
 		u8	devctl, warn = 0;
 
@@ -491,7 +492,7 @@
 
 	phy_off();
 
-	otg_put_transceiver(musb->xceiv);
+	usb_put_transceiver(musb->xceiv);
 	usb_nop_xceiv_unregister();
 
 	return 0;
@@ -511,7 +512,7 @@
 
 static u64 davinci_dmamask = DMA_BIT_MASK(32);
 
-static int __init davinci_probe(struct platform_device *pdev)
+static int __devinit davinci_probe(struct platform_device *pdev)
 {
 	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
 	struct platform_device		*musb;
@@ -594,7 +595,7 @@
 	return ret;
 }
 
-static int __exit davinci_remove(struct platform_device *pdev)
+static int __devexit davinci_remove(struct platform_device *pdev)
 {
 	struct davinci_glue		*glue = platform_get_drvdata(pdev);
 
@@ -608,7 +609,8 @@
 }
 
 static struct platform_driver davinci_driver = {
-	.remove		= __exit_p(davinci_remove),
+	.probe		= davinci_probe,
+	.remove		= __devexit_p(davinci_remove),
 	.driver		= {
 		.name	= "musb-davinci",
 	},
@@ -620,9 +622,9 @@
 
 static int __init davinci_init(void)
 {
-	return platform_driver_probe(&davinci_driver, davinci_probe);
+	return platform_driver_register(&davinci_driver);
 }
-subsys_initcall(davinci_init);
+module_init(davinci_init);
 
 static void __exit davinci_exit(void)
 {
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 3d11cf64..0f8b829 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -131,9 +131,9 @@
 /*-------------------------------------------------------------------------*/
 
 #ifndef CONFIG_BLACKFIN
-static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset)
+static int musb_ulpi_read(struct usb_phy *phy, u32 offset)
 {
-	void __iomem *addr = otg->io_priv;
+	void __iomem *addr = phy->io_priv;
 	int	i = 0;
 	u8	r;
 	u8	power;
@@ -165,10 +165,9 @@
 	return musb_readb(addr, MUSB_ULPI_REG_DATA);
 }
 
-static int musb_ulpi_write(struct otg_transceiver *otg,
-		u32 offset, u32 data)
+static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data)
 {
-	void __iomem *addr = otg->io_priv;
+	void __iomem *addr = phy->io_priv;
 	int	i = 0;
 	u8	r = 0;
 	u8	power;
@@ -200,7 +199,7 @@
 #define musb_ulpi_write		NULL
 #endif
 
-static struct otg_io_access_ops musb_ulpi_access = {
+static struct usb_phy_io_ops musb_ulpi_access = {
 	.read = musb_ulpi_read,
 	.write = musb_ulpi_write,
 };
@@ -414,6 +413,7 @@
 static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
 				u8 devctl, u8 power)
 {
+	struct usb_otg *otg = musb->xceiv->otg;
 	irqreturn_t handled = IRQ_NONE;
 
 	dev_dbg(musb->controller, "<== Power=%02x, DevCtl=%02x, int_usb=0x%x\n", power, devctl,
@@ -626,7 +626,7 @@
 		case OTG_STATE_B_PERIPHERAL:
 			musb_g_suspend(musb);
 			musb->is_active = is_otg_enabled(musb)
-					&& musb->xceiv->gadget->b_hnp_enable;
+					&& otg->gadget->b_hnp_enable;
 			if (musb->is_active) {
 				musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
 				dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n");
@@ -643,7 +643,7 @@
 		case OTG_STATE_A_HOST:
 			musb->xceiv->state = OTG_STATE_A_SUSPEND;
 			musb->is_active = is_otg_enabled(musb)
-					&& musb->xceiv->host->b_hnp_enable;
+					&& otg->host->b_hnp_enable;
 			break;
 		case OTG_STATE_B_HOST:
 			/* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
@@ -1017,12 +1017,12 @@
 	|| defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE)	\
 	|| defined(CONFIG_USB_MUSB_AM35X)		\
 	|| defined(CONFIG_USB_MUSB_AM35X_MODULE)
-static ushort __initdata fifo_mode = 4;
+static ushort __devinitdata fifo_mode = 4;
 #elif defined(CONFIG_USB_MUSB_UX500)			\
 	|| defined(CONFIG_USB_MUSB_UX500_MODULE)
-static ushort __initdata fifo_mode = 5;
+static ushort __devinitdata fifo_mode = 5;
 #else
-static ushort __initdata fifo_mode = 2;
+static ushort __devinitdata fifo_mode = 2;
 #endif
 
 /* "modprobe ... fifo_mode=1" etc */
@@ -1035,7 +1035,7 @@
  */
 
 /* mode 0 - fits in 2KB */
-static struct musb_fifo_cfg __initdata mode_0_cfg[] = {
+static struct musb_fifo_cfg __devinitdata mode_0_cfg[] = {
 { .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, },
 { .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, },
 { .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, },
@@ -1044,7 +1044,7 @@
 };
 
 /* mode 1 - fits in 4KB */
-static struct musb_fifo_cfg __initdata mode_1_cfg[] = {
+static struct musb_fifo_cfg __devinitdata mode_1_cfg[] = {
 { .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
 { .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
 { .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, .mode = BUF_DOUBLE, },
@@ -1053,7 +1053,7 @@
 };
 
 /* mode 2 - fits in 4KB */
-static struct musb_fifo_cfg __initdata mode_2_cfg[] = {
+static struct musb_fifo_cfg __devinitdata mode_2_cfg[] = {
 { .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, },
 { .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, },
 { .hw_ep_num = 2, .style = FIFO_TX,   .maxpacket = 512, },
@@ -1063,7 +1063,7 @@
 };
 
 /* mode 3 - fits in 4KB */
-static struct musb_fifo_cfg __initdata mode_3_cfg[] = {
+static struct musb_fifo_cfg __devinitdata mode_3_cfg[] = {
 { .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
 { .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
 { .hw_ep_num = 2, .style = FIFO_TX,   .maxpacket = 512, },
@@ -1073,7 +1073,7 @@
 };
 
 /* mode 4 - fits in 16KB */
-static struct musb_fifo_cfg __initdata mode_4_cfg[] = {
+static struct musb_fifo_cfg __devinitdata mode_4_cfg[] = {
 { .hw_ep_num =  1, .style = FIFO_TX,   .maxpacket = 512, },
 { .hw_ep_num =  1, .style = FIFO_RX,   .maxpacket = 512, },
 { .hw_ep_num =  2, .style = FIFO_TX,   .maxpacket = 512, },
@@ -1104,7 +1104,7 @@
 };
 
 /* mode 5 - fits in 8KB */
-static struct musb_fifo_cfg __initdata mode_5_cfg[] = {
+static struct musb_fifo_cfg __devinitdata mode_5_cfg[] = {
 { .hw_ep_num =  1, .style = FIFO_TX,   .maxpacket = 512, },
 { .hw_ep_num =  1, .style = FIFO_RX,   .maxpacket = 512, },
 { .hw_ep_num =  2, .style = FIFO_TX,   .maxpacket = 512, },
@@ -1140,7 +1140,7 @@
  *
  * returns negative errno or offset for next fifo.
  */
-static int __init
+static int __devinit
 fifo_setup(struct musb *musb, struct musb_hw_ep  *hw_ep,
 		const struct musb_fifo_cfg *cfg, u16 offset)
 {
@@ -1211,11 +1211,11 @@
 	return offset + (maxpacket << ((c_size & MUSB_FIFOSZ_DPB) ? 1 : 0));
 }
 
-static struct musb_fifo_cfg __initdata ep0_cfg = {
+static struct musb_fifo_cfg __devinitdata ep0_cfg = {
 	.style = FIFO_RXTX, .maxpacket = 64,
 };
 
-static int __init ep_config_from_table(struct musb *musb)
+static int __devinit ep_config_from_table(struct musb *musb)
 {
 	const struct musb_fifo_cfg	*cfg;
 	unsigned		i, n;
@@ -1306,7 +1306,7 @@
  * ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false
  * @param musb the controller
  */
-static int __init ep_config_from_hw(struct musb *musb)
+static int __devinit ep_config_from_hw(struct musb *musb)
 {
 	u8 epnum = 0;
 	struct musb_hw_ep *hw_ep;
@@ -1353,7 +1353,7 @@
 /* Initialize MUSB (M)HDRC part of the USB hardware subsystem;
  * configure endpoints, or take their config from silicon
  */
-static int __init musb_core_init(u16 musb_type, struct musb *musb)
+static int __devinit musb_core_init(u16 musb_type, struct musb *musb)
 {
 	u8 reg;
 	char *type;
@@ -1589,7 +1589,7 @@
 EXPORT_SYMBOL_GPL(musb_interrupt);
 
 #ifndef CONFIG_MUSB_PIO_ONLY
-static bool __initdata use_dma = 1;
+static bool __devinitdata use_dma = 1;
 
 /* "modprobe ... use_dma=0" etc */
 module_param(use_dma, bool, 0);
@@ -1777,7 +1777,7 @@
  * Init support
  */
 
-static struct musb *__init
+static struct musb *__devinit
 allocate_instance(struct device *dev,
 		struct musb_hdrc_config *config, void __iomem *mbase)
 {
@@ -1853,7 +1853,7 @@
  * @mregs: virtual address of controller registers,
  *	not yet corrected for platform-specific offsets
  */
-static int __init
+static int __devinit
 musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
 {
 	int			status;
@@ -1961,11 +1961,11 @@
 	if (is_host_enabled(musb)) {
 		struct usb_hcd	*hcd = musb_to_hcd(musb);
 
-		otg_set_host(musb->xceiv, &hcd->self);
+		otg_set_host(musb->xceiv->otg, &hcd->self);
 
 		if (is_otg_enabled(musb))
 			hcd->self.otg_port = 1;
-		musb->xceiv->host = &hcd->self;
+		musb->xceiv->otg->host = &hcd->self;
 		hcd->power_budget = 2 * (plat->power ? : 250);
 
 		/* program PHY to use external vBus if required */
@@ -1984,10 +1984,10 @@
 		struct usb_hcd	*hcd = musb_to_hcd(musb);
 
 		MUSB_HST_MODE(musb);
-		musb->xceiv->default_a = 1;
+		musb->xceiv->otg->default_a = 1;
 		musb->xceiv->state = OTG_STATE_A_IDLE;
 
-		status = usb_add_hcd(musb_to_hcd(musb), -1, 0);
+		status = usb_add_hcd(musb_to_hcd(musb), 0, 0);
 
 		hcd->self.uses_pio_for_control = 1;
 		dev_dbg(musb->controller, "%s mode, status %d, devctl %02x %c\n",
@@ -1999,7 +1999,7 @@
 
 	} else /* peripheral is enabled */ {
 		MUSB_DEV_MODE(musb);
-		musb->xceiv->default_a = 0;
+		musb->xceiv->otg->default_a = 0;
 		musb->xceiv->state = OTG_STATE_B_IDLE;
 
 		status = musb_gadget_setup(musb);
@@ -2073,7 +2073,7 @@
 static u64	*orig_dma_mask;
 #endif
 
-static int __init musb_probe(struct platform_device *pdev)
+static int __devinit musb_probe(struct platform_device *pdev)
 {
 	struct device	*dev = &pdev->dev;
 	int		irq = platform_get_irq_byname(pdev, "mc");
@@ -2102,7 +2102,7 @@
 	return status;
 }
 
-static int __exit musb_remove(struct platform_device *pdev)
+static int __devexit musb_remove(struct platform_device *pdev)
 {
 	struct musb	*musb = dev_to_musb(&pdev->dev);
 	void __iomem	*ctrl_base = musb->ctrl_base;
@@ -2112,11 +2112,9 @@
 	 *  - Peripheral mode: peripheral is deactivated (or never-activated)
 	 *  - OTG mode: both roles are deactivated (or never-activated)
 	 */
-	pm_runtime_get_sync(musb->controller);
 	musb_exit_debugfs(musb);
 	musb_shutdown(pdev);
 
-	pm_runtime_put(musb->controller);
 	musb_free(musb);
 	iounmap(ctrl_base);
 	device_init_wakeup(&pdev->dev, 0);
@@ -2364,7 +2362,8 @@
 		.owner		= THIS_MODULE,
 		.pm		= MUSB_DEV_PM_OPS,
 	},
-	.remove		= __exit_p(musb_remove),
+	.probe		= musb_probe,
+	.remove		= __devexit_p(musb_remove),
 	.shutdown	= musb_shutdown,
 };
 
@@ -2380,13 +2379,9 @@
 		", "
 		"otg (peripheral+host)",
 		musb_driver_name);
-	return platform_driver_probe(&musb_driver, musb_probe);
+	return platform_driver_register(&musb_driver);
 }
-
-/* make us init after usbcore and i2c (transceivers, regulators, etc)
- * and before usb gadget and host-side drivers start to register
- */
-fs_initcall(musb_init);
+module_init(musb_init);
 
 static void __exit musb_cleanup(void)
 {
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 3d28fb8..93de517 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -372,7 +372,7 @@
 	u16			int_rx;
 	u16			int_tx;
 
-	struct otg_transceiver	*xceiv;
+	struct usb_phy		*xceiv;
 	u8			xceiv_event;
 
 	int nIrq;
diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c
index 13d9af9..40a37c9 100644
--- a/drivers/usb/musb/musb_debugfs.c
+++ b/drivers/usb/musb/musb_debugfs.c
@@ -235,29 +235,29 @@
 	.release		= single_release,
 };
 
-int __init musb_init_debugfs(struct musb *musb)
+int __devinit musb_init_debugfs(struct musb *musb)
 {
 	struct dentry		*root;
 	struct dentry		*file;
 	int			ret;
 
 	root = debugfs_create_dir("musb", NULL);
-	if (IS_ERR(root)) {
-		ret = PTR_ERR(root);
+	if (!root) {
+		ret = -ENOMEM;
 		goto err0;
 	}
 
 	file = debugfs_create_file("regdump", S_IRUGO, root, musb,
 			&musb_regdump_fops);
-	if (IS_ERR(file)) {
-		ret = PTR_ERR(file);
+	if (!file) {
+		ret = -ENOMEM;
 		goto err1;
 	}
 
 	file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR,
 			root, musb, &musb_test_mode_fops);
-	if (IS_ERR(file)) {
-		ret = PTR_ERR(file);
+	if (!file) {
+		ret = -ENOMEM;
 		goto err1;
 	}
 
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index ac3d2ee..f42c29b 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -574,6 +574,15 @@
 
 		if (request->actual == request->length) {
 			musb_g_giveback(musb_ep, request, 0);
+			/*
+			 * In the giveback function the MUSB lock is
+			 * released and acquired after sometime. During
+			 * this time period the INDEX register could get
+			 * changed by the gadget_queue function especially
+			 * on SMP systems. Reselect the INDEX to be sure
+			 * we are reading/modifying the right registers
+			 */
+			musb_ep_select(mbase, epnum);
 			req = musb_ep->desc ? next_request(musb_ep) : NULL;
 			if (!req) {
 				dev_dbg(musb->controller, "%s idle now\n",
@@ -983,6 +992,15 @@
 		}
 #endif
 		musb_g_giveback(musb_ep, request, 0);
+		/*
+		 * In the giveback function the MUSB lock is
+		 * released and acquired after sometime. During
+		 * this time period the INDEX register could get
+		 * changed by the gadget_queue function especially
+		 * on SMP systems. Reselect the INDEX to be sure
+		 * we are reading/modifying the right registers
+		 */
+		musb_ep_select(mbase, epnum);
 
 		req = next_request(musb_ep);
 		if (!req)
@@ -1624,7 +1642,7 @@
 		}
 
 		spin_unlock_irqrestore(&musb->lock, flags);
-		otg_start_srp(musb->xceiv);
+		otg_start_srp(musb->xceiv->otg);
 		spin_lock_irqsave(&musb->lock, flags);
 
 		/* Block idling for at least 1s */
@@ -1703,7 +1721,7 @@
 
 	if (!musb->xceiv->set_power)
 		return -EOPNOTSUPP;
-	return otg_set_power(musb->xceiv, mA);
+	return usb_phy_set_power(musb->xceiv, mA);
 }
 
 static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
@@ -1762,7 +1780,7 @@
 }
 
 
-static void __init
+static void __devinit
 init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)
 {
 	struct musb_hw_ep	*hw_ep = musb->endpoints + epnum;
@@ -1799,7 +1817,7 @@
  * Initialize the endpoints exposed to peripheral drivers, with backlinks
  * to the rest of the driver state.
  */
-static inline void __init musb_g_init_endpoints(struct musb *musb)
+static inline void __devinit musb_g_init_endpoints(struct musb *musb)
 {
 	u8			epnum;
 	struct musb_hw_ep	*hw_ep;
@@ -1832,7 +1850,7 @@
 /* called once during driver setup to initialize and link into
  * the driver model; memory is zeroed.
  */
-int __init musb_gadget_setup(struct musb *musb)
+int __devinit musb_gadget_setup(struct musb *musb)
 {
 	int status;
 
@@ -1898,6 +1916,7 @@
 		struct usb_gadget_driver *driver)
 {
 	struct musb		*musb = gadget_to_musb(g);
+	struct usb_otg		*otg = musb->xceiv->otg;
 	unsigned long		flags;
 	int			retval = -EINVAL;
 
@@ -1914,7 +1933,7 @@
 	spin_lock_irqsave(&musb->lock, flags);
 	musb->is_active = 1;
 
-	otg_set_peripheral(musb->xceiv, &musb->g);
+	otg_set_peripheral(otg, &musb->g);
 	musb->xceiv->state = OTG_STATE_B_IDLE;
 
 	/*
@@ -1938,15 +1957,15 @@
 		 * handles power budgeting ... this way also
 		 * ensures HdrcStart is indirectly called.
 		 */
-		retval = usb_add_hcd(musb_to_hcd(musb), -1, 0);
+		retval = usb_add_hcd(musb_to_hcd(musb), 0, 0);
 		if (retval < 0) {
 			dev_dbg(musb->controller, "add_hcd failed, %d\n", retval);
 			goto err2;
 		}
 
 		if ((musb->xceiv->last_event == USB_EVENT_ID)
-					&& musb->xceiv->set_vbus)
-			otg_set_vbus(musb->xceiv, 1);
+					&& otg->set_vbus)
+			otg_set_vbus(otg, 1);
 
 		hcd->self.uses_pio_for_control = 1;
 	}
@@ -2028,7 +2047,7 @@
 
 	musb->xceiv->state = OTG_STATE_UNDEFINED;
 	stop_activity(musb, driver);
-	otg_set_peripheral(musb->xceiv, NULL);
+	otg_set_peripheral(musb->xceiv->otg, NULL);
 
 	dev_dbg(musb->controller, "unregistering driver %s\n", driver->function);
 
diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
index e9f80ad..22ec3e3 100644
--- a/drivers/usb/musb/musb_virthub.c
+++ b/drivers/usb/musb/musb_virthub.c
@@ -47,6 +47,7 @@
 
 static void musb_port_suspend(struct musb *musb, bool do_suspend)
 {
+	struct usb_otg	*otg = musb->xceiv->otg;
 	u8		power;
 	void __iomem	*mbase = musb->mregs;
 
@@ -81,7 +82,7 @@
 		case OTG_STATE_A_HOST:
 			musb->xceiv->state = OTG_STATE_A_SUSPEND;
 			musb->is_active = is_otg_enabled(musb)
-					&& musb->xceiv->host->b_hnp_enable;
+					&& otg->host->b_hnp_enable;
 			if (musb->is_active)
 				mod_timer(&musb->otg_timer, jiffies
 					+ msecs_to_jiffies(
@@ -91,7 +92,7 @@
 		case OTG_STATE_B_HOST:
 			musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
 			musb->is_active = is_otg_enabled(musb)
-					&& musb->xceiv->host->b_hnp_enable;
+					&& otg->host->b_hnp_enable;
 			musb_platform_try_idle(musb, 0);
 			break;
 		default:
@@ -179,6 +180,8 @@
 
 void musb_root_disconnect(struct musb *musb)
 {
+	struct usb_otg	*otg = musb->xceiv->otg;
+
 	musb->port1_status = USB_PORT_STAT_POWER
 			| (USB_PORT_STAT_C_CONNECTION << 16);
 
@@ -188,7 +191,7 @@
 	switch (musb->xceiv->state) {
 	case OTG_STATE_A_SUSPEND:
 		if (is_otg_enabled(musb)
-				&& musb->xceiv->host->b_hnp_enable) {
+				&& otg->host->b_hnp_enable) {
 			musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
 			musb->g.is_a_peripheral = 1;
 			break;
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index df719ea..2ae0bb3 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -132,6 +132,7 @@
 
 static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
 {
+	struct usb_otg	*otg = musb->xceiv->otg;
 	u8		devctl;
 	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
 	int ret = 1;
@@ -163,11 +164,11 @@
 				}
 			}
 
-			if (ret && musb->xceiv->set_vbus)
-				otg_set_vbus(musb->xceiv, 1);
+			if (ret && otg->set_vbus)
+				otg_set_vbus(otg, 1);
 		} else {
 			musb->is_active = 1;
-			musb->xceiv->default_a = 1;
+			otg->default_a = 1;
 			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
 			devctl |= MUSB_DEVCTL_SESSION;
 			MUSB_HST_MODE(musb);
@@ -179,7 +180,7 @@
 		 * jumping right to B_IDLE...
 		 */
 
-		musb->xceiv->default_a = 0;
+		otg->default_a = 0;
 		musb->xceiv->state = OTG_STATE_B_IDLE;
 		devctl &= ~MUSB_DEVCTL_SESSION;
 
@@ -246,7 +247,7 @@
 
 		if (!is_otg_enabled(musb) || musb->gadget_driver) {
 			pm_runtime_get_sync(musb->controller);
-			otg_init(musb->xceiv);
+			usb_phy_init(musb->xceiv);
 			omap2430_musb_set_vbus(musb, 1);
 		}
 		break;
@@ -256,7 +257,7 @@
 
 		if (musb->gadget_driver)
 			pm_runtime_get_sync(musb->controller);
-		otg_init(musb->xceiv);
+		usb_phy_init(musb->xceiv);
 		break;
 
 	case USB_EVENT_NONE:
@@ -269,10 +270,10 @@
 			}
 
 		if (data->interface_type == MUSB_INTERFACE_UTMI) {
-			if (musb->xceiv->set_vbus)
-				otg_set_vbus(musb->xceiv, 0);
+			if (musb->xceiv->otg->set_vbus)
+				otg_set_vbus(musb->xceiv->otg, 0);
 		}
-		otg_shutdown(musb->xceiv);
+		usb_phy_shutdown(musb->xceiv);
 		break;
 	default:
 		dev_dbg(musb->controller, "ID float\n");
@@ -290,7 +291,7 @@
 	 * up through ULPI.  TWL4030-family PMICs include one,
 	 * which needs a driver, drivers aren't always needed.
 	 */
-	musb->xceiv = otg_get_transceiver();
+	musb->xceiv = usb_get_transceiver();
 	if (!musb->xceiv) {
 		pr_err("HS USB OTG: no transceiver configured\n");
 		return -ENODEV;
@@ -325,7 +326,7 @@
 			musb_readl(musb->mregs, OTG_SIMENABLE));
 
 	musb->nb.notifier_call = musb_otg_notifications;
-	status = otg_register_notifier(musb->xceiv, &musb->nb);
+	status = usb_register_notifier(musb->xceiv, &musb->nb);
 
 	if (status)
 		dev_dbg(musb->controller, "notification register failed\n");
@@ -349,7 +350,7 @@
 	switch (musb->xceiv->last_event) {
 
 	case USB_EVENT_ID:
-		otg_init(musb->xceiv);
+		usb_phy_init(musb->xceiv);
 		if (data->interface_type != MUSB_INTERFACE_UTMI)
 			break;
 		devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
@@ -368,7 +369,7 @@
 		break;
 
 	case USB_EVENT_VBUS:
-		otg_init(musb->xceiv);
+		usb_phy_init(musb->xceiv);
 		break;
 
 	default:
@@ -379,7 +380,7 @@
 static void omap2430_musb_disable(struct musb *musb)
 {
 	if (musb->xceiv->last_event)
-		otg_shutdown(musb->xceiv);
+		usb_phy_shutdown(musb->xceiv);
 }
 
 static int omap2430_musb_exit(struct musb *musb)
@@ -388,7 +389,7 @@
 	cancel_work_sync(&musb->otg_notifier_work);
 
 	omap2430_low_level_exit(musb);
-	otg_put_transceiver(musb->xceiv);
+	usb_put_transceiver(musb->xceiv);
 
 	return 0;
 }
@@ -408,7 +409,7 @@
 
 static u64 omap2430_dmamask = DMA_BIT_MASK(32);
 
-static int __init omap2430_probe(struct platform_device *pdev)
+static int __devinit omap2430_probe(struct platform_device *pdev)
 {
 	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
 	struct platform_device		*musb;
@@ -471,7 +472,7 @@
 	return ret;
 }
 
-static int __exit omap2430_remove(struct platform_device *pdev)
+static int __devexit omap2430_remove(struct platform_device *pdev)
 {
 	struct omap2430_glue		*glue = platform_get_drvdata(pdev);
 
@@ -494,7 +495,7 @@
 						OTG_INTERFSEL);
 
 	omap2430_low_level_exit(musb);
-	otg_set_suspend(musb->xceiv, 1);
+	usb_phy_set_suspend(musb->xceiv, 1);
 
 	return 0;
 }
@@ -508,7 +509,7 @@
 	musb_writel(musb->mregs, OTG_INTERFSEL,
 					musb->context.otg_interfsel);
 
-	otg_set_suspend(musb->xceiv, 0);
+	usb_phy_set_suspend(musb->xceiv, 0);
 
 	return 0;
 }
@@ -524,7 +525,8 @@
 #endif
 
 static struct platform_driver omap2430_driver = {
-	.remove		= __exit_p(omap2430_remove),
+	.probe		= omap2430_probe,
+	.remove		= __devexit_p(omap2430_remove),
 	.driver		= {
 		.name	= "musb-omap2430",
 		.pm	= DEV_PM_OPS,
@@ -537,9 +539,9 @@
 
 static int __init omap2430_init(void)
 {
-	return platform_driver_probe(&omap2430_driver, omap2430_probe);
+	return platform_driver_register(&omap2430_driver);
 }
-subsys_initcall(omap2430_init);
+module_init(omap2430_init);
 
 static void __exit omap2430_exit(void)
 {
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 1f40561..de13559 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -277,7 +277,7 @@
  * mode), or low power Default-B sessions, something else supplies power.
  * Caller must take care of locking.
  */
-static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)
+static int tusb_draw_power(struct usb_phy *x, unsigned mA)
 {
 	struct musb	*musb = the_musb;
 	void __iomem	*tbase = musb->ctrl_base;
@@ -293,7 +293,7 @@
 	 * The actual current usage would be very board-specific.  For now,
 	 * it's simpler to just use an aggregate (also board-specific).
 	 */
-	if (x->default_a || mA < (musb->min_power << 1))
+	if (x->otg->default_a || mA < (musb->min_power << 1))
 		mA = 0;
 
 	reg = musb_readl(tbase, TUSB_PRCM_MNGMT);
@@ -510,6 +510,7 @@
 	void __iomem	*tbase = musb->ctrl_base;
 	u32		conf, prcm, timer;
 	u8		devctl;
+	struct usb_otg	*otg = musb->xceiv->otg;
 
 	/* HDRC controls CPEN, but beware current surges during device
 	 * connect.  They can trigger transient overcurrent conditions
@@ -522,7 +523,7 @@
 
 	if (is_on) {
 		timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE);
-		musb->xceiv->default_a = 1;
+		otg->default_a = 1;
 		musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
 		devctl |= MUSB_DEVCTL_SESSION;
 
@@ -548,11 +549,11 @@
 				musb->xceiv->state = OTG_STATE_A_IDLE;
 			}
 			musb->is_active = 0;
-			musb->xceiv->default_a = 1;
+			otg->default_a = 1;
 			MUSB_HST_MODE(musb);
 		} else {
 			musb->is_active = 0;
-			musb->xceiv->default_a = 0;
+			otg->default_a = 0;
 			musb->xceiv->state = OTG_STATE_B_IDLE;
 			MUSB_DEV_MODE(musb);
 		}
@@ -644,6 +645,7 @@
 {
 	u32		otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
 	unsigned long	idle_timeout = 0;
+	struct usb_otg	*otg = musb->xceiv->otg;
 
 	/* ID pin */
 	if ((int_src & TUSB_INT_SRC_ID_STATUS_CHNG)) {
@@ -654,7 +656,7 @@
 		else
 			default_a = is_host_enabled(musb);
 		dev_dbg(musb->controller, "Default-%c\n", default_a ? 'A' : 'B');
-		musb->xceiv->default_a = default_a;
+		otg->default_a = default_a;
 		tusb_musb_set_vbus(musb, default_a);
 
 		/* Don't allow idling immediately */
@@ -666,7 +668,7 @@
 	if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) {
 
 		/* B-dev state machine:  no vbus ~= disconnect */
-		if ((is_otg_enabled(musb) && !musb->xceiv->default_a)
+		if ((is_otg_enabled(musb) && !otg->default_a)
 				|| !is_host_enabled(musb)) {
 			/* ? musb_root_disconnect(musb); */
 			musb->port1_status &=
@@ -1076,7 +1078,7 @@
 	int			ret;
 
 	usb_nop_xceiv_register();
-	musb->xceiv = otg_get_transceiver();
+	musb->xceiv = usb_get_transceiver();
 	if (!musb->xceiv)
 		return -ENODEV;
 
@@ -1128,7 +1130,7 @@
 		if (sync)
 			iounmap(sync);
 
-		otg_put_transceiver(musb->xceiv);
+		usb_put_transceiver(musb->xceiv);
 		usb_nop_xceiv_unregister();
 	}
 	return ret;
@@ -1144,7 +1146,7 @@
 
 	iounmap(musb->sync_va);
 
-	otg_put_transceiver(musb->xceiv);
+	usb_put_transceiver(musb->xceiv);
 	usb_nop_xceiv_unregister();
 	return 0;
 }
@@ -1165,7 +1167,7 @@
 
 static u64 tusb_dmamask = DMA_BIT_MASK(32);
 
-static int __init tusb_probe(struct platform_device *pdev)
+static int __devinit tusb_probe(struct platform_device *pdev)
 {
 	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
 	struct platform_device		*musb;
@@ -1227,7 +1229,7 @@
 	return ret;
 }
 
-static int __exit tusb_remove(struct platform_device *pdev)
+static int __devexit tusb_remove(struct platform_device *pdev)
 {
 	struct tusb6010_glue		*glue = platform_get_drvdata(pdev);
 
@@ -1239,7 +1241,8 @@
 }
 
 static struct platform_driver tusb_driver = {
-	.remove		= __exit_p(tusb_remove),
+	.probe		= tusb_probe,
+	.remove		= __devexit_p(tusb_remove),
 	.driver		= {
 		.name	= "musb-tusb",
 	},
@@ -1251,9 +1254,9 @@
 
 static int __init tusb_init(void)
 {
-	return platform_driver_probe(&tusb_driver, tusb_probe);
+	return platform_driver_register(&tusb_driver);
 }
-subsys_initcall(tusb_init);
+module_init(tusb_init);
 
 static void __exit tusb_exit(void)
 {
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
index f7e04bf..aa09dd4 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -37,7 +37,7 @@
 
 static int ux500_musb_init(struct musb *musb)
 {
-	musb->xceiv = otg_get_transceiver();
+	musb->xceiv = usb_get_transceiver();
 	if (!musb->xceiv) {
 		pr_err("HS USB OTG: no transceiver configured\n");
 		return -ENODEV;
@@ -48,7 +48,7 @@
 
 static int ux500_musb_exit(struct musb *musb)
 {
-	otg_put_transceiver(musb->xceiv);
+	usb_put_transceiver(musb->xceiv);
 
 	return 0;
 }
@@ -58,7 +58,7 @@
 	.exit		= ux500_musb_exit,
 };
 
-static int __init ux500_probe(struct platform_device *pdev)
+static int __devinit ux500_probe(struct platform_device *pdev)
 {
 	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
 	struct platform_device		*musb;
@@ -141,7 +141,7 @@
 	return ret;
 }
 
-static int __exit ux500_remove(struct platform_device *pdev)
+static int __devexit ux500_remove(struct platform_device *pdev)
 {
 	struct ux500_glue	*glue = platform_get_drvdata(pdev);
 
@@ -160,7 +160,7 @@
 	struct ux500_glue	*glue = dev_get_drvdata(dev);
 	struct musb		*musb = glue_to_musb(glue);
 
-	otg_set_suspend(musb->xceiv, 1);
+	usb_phy_set_suspend(musb->xceiv, 1);
 	clk_disable(glue->clk);
 
 	return 0;
@@ -178,7 +178,7 @@
 		return ret;
 	}
 
-	otg_set_suspend(musb->xceiv, 0);
+	usb_phy_set_suspend(musb->xceiv, 0);
 
 	return 0;
 }
@@ -194,7 +194,8 @@
 #endif
 
 static struct platform_driver ux500_driver = {
-	.remove		= __exit_p(ux500_remove),
+	.probe		= ux500_probe,
+	.remove		= __devexit_p(ux500_remove),
 	.driver		= {
 		.name	= "musb-ux500",
 		.pm	= DEV_PM_OPS,
@@ -207,9 +208,9 @@
 
 static int __init ux500_init(void)
 {
-	return platform_driver_probe(&ux500_driver, ux500_probe);
+	return platform_driver_register(&ux500_driver);
 }
-subsys_initcall(ux500_init);
+module_init(ux500_init);
 
 static void __exit ux500_exit(void)
 {
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
index 735ef4c..5c87db0 100644
--- a/drivers/usb/otg/Kconfig
+++ b/drivers/usb/otg/Kconfig
@@ -23,7 +23,7 @@
 	select USB_OTG_UTILS
 	help
 	  Provides simple GPIO VBUS sensing for controllers with an
-	  internal transceiver via the otg_transceiver interface, and
+	  internal transceiver via the usb_phy interface, and
 	  optionally control of a D+ pullup GPIO as well as a VBUS
 	  current limit regulator.
 
diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c
index 74fe6e6..a84af67 100644
--- a/drivers/usb/otg/ab8500-usb.c
+++ b/drivers/usb/otg/ab8500-usb.c
@@ -68,7 +68,7 @@
 };
 
 struct ab8500_usb {
-	struct otg_transceiver otg;
+	struct usb_phy phy;
 	struct device *dev;
 	int irq_num_id_rise;
 	int irq_num_id_fall;
@@ -82,9 +82,9 @@
 	int rev;
 };
 
-static inline struct ab8500_usb *xceiv_to_ab(struct otg_transceiver *x)
+static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x)
 {
-	return container_of(x, struct ab8500_usb, otg);
+	return container_of(x, struct ab8500_usb, phy);
 }
 
 static void ab8500_usb_wd_workaround(struct ab8500_usb *ab)
@@ -153,7 +153,7 @@
 	u8 reg;
 	enum ab8500_usb_link_status lsts;
 	void *v = NULL;
-	enum usb_xceiv_events event;
+	enum usb_phy_events event;
 
 	abx500_get_register_interruptible(ab->dev,
 			AB8500_USB,
@@ -169,8 +169,8 @@
 		/* TODO: Disable regulators. */
 		ab8500_usb_host_phy_dis(ab);
 		ab8500_usb_peri_phy_dis(ab);
-		ab->otg.state = OTG_STATE_B_IDLE;
-		ab->otg.default_a = false;
+		ab->phy.state = OTG_STATE_B_IDLE;
+		ab->phy.otg->default_a = false;
 		ab->vbus_draw = 0;
 		event = USB_EVENT_NONE;
 		break;
@@ -181,22 +181,22 @@
 	case USB_LINK_HOST_CHG_NM:
 	case USB_LINK_HOST_CHG_HS:
 	case USB_LINK_HOST_CHG_HS_CHIRP:
-		if (ab->otg.gadget) {
+		if (ab->phy.otg->gadget) {
 			/* TODO: Enable regulators. */
 			ab8500_usb_peri_phy_en(ab);
-			v = ab->otg.gadget;
+			v = ab->phy.otg->gadget;
 		}
 		event = USB_EVENT_VBUS;
 		break;
 
 	case USB_LINK_HM_IDGND:
-		if (ab->otg.host) {
+		if (ab->phy.otg->host) {
 			/* TODO: Enable regulators. */
 			ab8500_usb_host_phy_en(ab);
-			v = ab->otg.host;
+			v = ab->phy.otg->host;
 		}
-		ab->otg.state = OTG_STATE_A_IDLE;
-		ab->otg.default_a = true;
+		ab->phy.state = OTG_STATE_A_IDLE;
+		ab->phy.otg->default_a = true;
 		event = USB_EVENT_ID;
 		break;
 
@@ -212,7 +212,7 @@
 		break;
 	}
 
-	atomic_notifier_call_chain(&ab->otg.notifier, event, v);
+	atomic_notifier_call_chain(&ab->phy.notifier, event, v);
 
 	return 0;
 }
@@ -262,27 +262,27 @@
 	struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
 						phy_dis_work);
 
-	if (!ab->otg.host)
+	if (!ab->phy.otg->host)
 		ab8500_usb_host_phy_dis(ab);
 
-	if (!ab->otg.gadget)
+	if (!ab->phy.otg->gadget)
 		ab8500_usb_peri_phy_dis(ab);
 }
 
-static int ab8500_usb_set_power(struct otg_transceiver *otg, unsigned mA)
+static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA)
 {
 	struct ab8500_usb *ab;
 
-	if (!otg)
+	if (!phy)
 		return -ENODEV;
 
-	ab = xceiv_to_ab(otg);
+	ab = phy_to_ab(phy);
 
 	ab->vbus_draw = mA;
 
 	if (mA)
-		atomic_notifier_call_chain(&ab->otg.notifier,
-				USB_EVENT_ENUMERATED, ab->otg.gadget);
+		atomic_notifier_call_chain(&ab->phy.notifier,
+				USB_EVENT_ENUMERATED, ab->phy.otg->gadget);
 	return 0;
 }
 
@@ -290,21 +290,21 @@
  * ab->vbus_draw.
  */
 
-static int ab8500_usb_set_suspend(struct otg_transceiver *x, int suspend)
+static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend)
 {
 	/* TODO */
 	return 0;
 }
 
-static int ab8500_usb_set_peripheral(struct otg_transceiver *otg,
-		struct usb_gadget *gadget)
+static int ab8500_usb_set_peripheral(struct usb_otg *otg,
+					struct usb_gadget *gadget)
 {
 	struct ab8500_usb *ab;
 
 	if (!otg)
 		return -ENODEV;
 
-	ab = xceiv_to_ab(otg);
+	ab = phy_to_ab(otg->phy);
 
 	/* Some drivers call this function in atomic context.
 	 * Do not update ab8500 registers directly till this
@@ -313,11 +313,11 @@
 
 	if (!gadget) {
 		/* TODO: Disable regulators. */
-		ab->otg.gadget = NULL;
+		otg->gadget = NULL;
 		schedule_work(&ab->phy_dis_work);
 	} else {
-		ab->otg.gadget = gadget;
-		ab->otg.state = OTG_STATE_B_IDLE;
+		otg->gadget = gadget;
+		otg->phy->state = OTG_STATE_B_IDLE;
 
 		/* Phy will not be enabled if cable is already
 		 * plugged-in. Schedule to enable phy.
@@ -329,15 +329,14 @@
 	return 0;
 }
 
-static int ab8500_usb_set_host(struct otg_transceiver *otg,
-					struct usb_bus *host)
+static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
 {
 	struct ab8500_usb *ab;
 
 	if (!otg)
 		return -ENODEV;
 
-	ab = xceiv_to_ab(otg);
+	ab = phy_to_ab(otg->phy);
 
 	/* Some drivers call this function in atomic context.
 	 * Do not update ab8500 registers directly till this
@@ -346,10 +345,10 @@
 
 	if (!host) {
 		/* TODO: Disable regulators. */
-		ab->otg.host = NULL;
+		otg->host = NULL;
 		schedule_work(&ab->phy_dis_work);
 	} else {
-		ab->otg.host = host;
+		otg->host = host;
 		/* Phy will not be enabled if cable is already
 		 * plugged-in. Schedule to enable phy.
 		 * Use same delay to avoid any race condition.
@@ -472,6 +471,7 @@
 static int __devinit ab8500_usb_probe(struct platform_device *pdev)
 {
 	struct ab8500_usb	*ab;
+	struct usb_otg		*otg;
 	int err;
 	int rev;
 
@@ -488,19 +488,28 @@
 	if (!ab)
 		return -ENOMEM;
 
+	otg = kzalloc(sizeof *otg, GFP_KERNEL);
+	if (!otg) {
+		kfree(ab);
+		return -ENOMEM;
+	}
+
 	ab->dev			= &pdev->dev;
 	ab->rev			= rev;
-	ab->otg.dev		= ab->dev;
-	ab->otg.label		= "ab8500";
-	ab->otg.state		= OTG_STATE_UNDEFINED;
-	ab->otg.set_host	= ab8500_usb_set_host;
-	ab->otg.set_peripheral	= ab8500_usb_set_peripheral;
-	ab->otg.set_suspend	= ab8500_usb_set_suspend;
-	ab->otg.set_power	= ab8500_usb_set_power;
+	ab->phy.dev		= ab->dev;
+	ab->phy.otg		= otg;
+	ab->phy.label		= "ab8500";
+	ab->phy.set_suspend	= ab8500_usb_set_suspend;
+	ab->phy.set_power	= ab8500_usb_set_power;
+	ab->phy.state		= OTG_STATE_UNDEFINED;
+
+	otg->phy		= &ab->phy;
+	otg->set_host		= ab8500_usb_set_host;
+	otg->set_peripheral	= ab8500_usb_set_peripheral;
 
 	platform_set_drvdata(pdev, ab);
 
-	ATOMIC_INIT_NOTIFIER_HEAD(&ab->otg.notifier);
+	ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier);
 
 	/* v1: Wait for link status to become stable.
 	 * all: Updates form set_host and set_peripheral as they are atomic.
@@ -520,7 +529,7 @@
 	if (err < 0)
 		goto fail0;
 
-	err = otg_set_transceiver(&ab->otg);
+	err = usb_set_transceiver(&ab->phy);
 	if (err) {
 		dev_err(&pdev->dev, "Can't register transceiver\n");
 		goto fail1;
@@ -532,6 +541,7 @@
 fail1:
 	ab8500_usb_irq_free(ab);
 fail0:
+	kfree(otg);
 	kfree(ab);
 	return err;
 }
@@ -546,13 +556,14 @@
 
 	cancel_work_sync(&ab->phy_dis_work);
 
-	otg_set_transceiver(NULL);
+	usb_set_transceiver(NULL);
 
 	ab8500_usb_host_phy_dis(ab);
 	ab8500_usb_peri_phy_dis(ab);
 
 	platform_set_drvdata(pdev, NULL);
 
+	kfree(ab->phy.otg);
 	kfree(ab);
 
 	return 0;
diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c
index a190850..be4a63e 100644
--- a/drivers/usb/otg/fsl_otg.c
+++ b/drivers/usb/otg/fsl_otg.c
@@ -275,7 +275,7 @@
 	fsl_otg_dischrg_vbus(0);
 	srp_wait_done = 1;
 
-	if ((fsl_otg_dev->otg.state == OTG_STATE_B_SRP_INIT) &&
+	if ((fsl_otg_dev->phy.state == OTG_STATE_B_SRP_INIT) &&
 	    fsl_otg_dev->fsm.b_sess_vld)
 		fsl_otg_dev->fsm.b_srp_done = 1;
 }
@@ -288,7 +288,7 @@
 void a_wait_enum(unsigned long foo)
 {
 	VDBG("a_wait_enum timeout\n");
-	if (!fsl_otg_dev->otg.host->b_hnp_enable)
+	if (!fsl_otg_dev->phy.otg->host->b_hnp_enable)
 		fsl_otg_add_timer(a_wait_enum_tmr);
 	else
 		otg_statemachine(&fsl_otg_dev->fsm);
@@ -452,14 +452,14 @@
 /* Call suspend/resume routines in host driver */
 int fsl_otg_start_host(struct otg_fsm *fsm, int on)
 {
-	struct otg_transceiver *xceiv = fsm->transceiver;
+	struct usb_otg *otg = fsm->otg;
 	struct device *dev;
-	struct fsl_otg *otg_dev = container_of(xceiv, struct fsl_otg, otg);
+	struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
 	u32 retval = 0;
 
-	if (!xceiv->host)
+	if (!otg->host)
 		return -ENODEV;
-	dev = xceiv->host->controller;
+	dev = otg->host->controller;
 
 	/*
 	 * Update a_vbus_vld state as a_vbus_vld int is disabled
@@ -518,14 +518,14 @@
  */
 int fsl_otg_start_gadget(struct otg_fsm *fsm, int on)
 {
-	struct otg_transceiver *xceiv = fsm->transceiver;
+	struct usb_otg *otg = fsm->otg;
 	struct device *dev;
 
-	if (!xceiv->gadget || !xceiv->gadget->dev.parent)
+	if (!otg->gadget || !otg->gadget->dev.parent)
 		return -ENODEV;
 
 	VDBG("gadget %s\n", on ? "on" : "off");
-	dev = xceiv->gadget->dev.parent;
+	dev = otg->gadget->dev.parent;
 
 	if (on) {
 		if (dev->driver->resume)
@@ -542,14 +542,14 @@
  * Called by initialization code of host driver.  Register host controller
  * to the OTG.  Suspend host for OTG role detection.
  */
-static int fsl_otg_set_host(struct otg_transceiver *otg_p, struct usb_bus *host)
+static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
 {
-	struct fsl_otg *otg_dev = container_of(otg_p, struct fsl_otg, otg);
+	struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
 
-	if (!otg_p || otg_dev != fsl_otg_dev)
+	if (!otg || otg_dev != fsl_otg_dev)
 		return -ENODEV;
 
-	otg_p->host = host;
+	otg->host = host;
 
 	otg_dev->fsm.a_bus_drop = 0;
 	otg_dev->fsm.a_bus_req = 1;
@@ -557,8 +557,8 @@
 	if (host) {
 		VDBG("host off......\n");
 
-		otg_p->host->otg_port = fsl_otg_initdata.otg_port;
-		otg_p->host->is_b_host = otg_dev->fsm.id;
+		otg->host->otg_port = fsl_otg_initdata.otg_port;
+		otg->host->is_b_host = otg_dev->fsm.id;
 		/*
 		 * must leave time for khubd to finish its thing
 		 * before yanking the host driver out from under it,
@@ -574,7 +574,7 @@
 			/* Mini-A cable connected */
 			struct otg_fsm *fsm = &otg_dev->fsm;
 
-			otg_p->state = OTG_STATE_UNDEFINED;
+			otg->phy->state = OTG_STATE_UNDEFINED;
 			fsm->protocol = PROTO_UNDEF;
 		}
 	}
@@ -587,29 +587,29 @@
 }
 
 /* Called by initialization code of udc.  Register udc to OTG. */
-static int fsl_otg_set_peripheral(struct otg_transceiver *otg_p,
-				  struct usb_gadget *gadget)
+static int fsl_otg_set_peripheral(struct usb_otg *otg,
+					struct usb_gadget *gadget)
 {
-	struct fsl_otg *otg_dev = container_of(otg_p, struct fsl_otg, otg);
+	struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
 
 	VDBG("otg_dev 0x%x\n", (int)otg_dev);
 	VDBG("fsl_otg_dev 0x%x\n", (int)fsl_otg_dev);
 
-	if (!otg_p || otg_dev != fsl_otg_dev)
+	if (!otg || otg_dev != fsl_otg_dev)
 		return -ENODEV;
 
 	if (!gadget) {
-		if (!otg_dev->otg.default_a)
-			otg_p->gadget->ops->vbus_draw(otg_p->gadget, 0);
-		usb_gadget_vbus_disconnect(otg_dev->otg.gadget);
-		otg_dev->otg.gadget = 0;
+		if (!otg->default_a)
+			otg->gadget->ops->vbus_draw(otg->gadget, 0);
+		usb_gadget_vbus_disconnect(otg->gadget);
+		otg->gadget = 0;
 		otg_dev->fsm.b_bus_req = 0;
 		otg_statemachine(&otg_dev->fsm);
 		return 0;
 	}
 
-	otg_p->gadget = gadget;
-	otg_p->gadget->is_a_peripheral = !otg_dev->fsm.id;
+	otg->gadget = gadget;
+	otg->gadget->is_a_peripheral = !otg_dev->fsm.id;
 
 	otg_dev->fsm.b_bus_req = 1;
 
@@ -625,11 +625,11 @@
 }
 
 /* Set OTG port power, only for B-device */
-static int fsl_otg_set_power(struct otg_transceiver *otg_p, unsigned mA)
+static int fsl_otg_set_power(struct usb_phy *phy, unsigned mA)
 {
 	if (!fsl_otg_dev)
 		return -ENODEV;
-	if (otg_p->state == OTG_STATE_B_PERIPHERAL)
+	if (phy->state == OTG_STATE_B_PERIPHERAL)
 		pr_info("FSL OTG: Draw %d mA\n", mA);
 
 	return 0;
@@ -658,12 +658,12 @@
 }
 
 /* B-device start SRP */
-static int fsl_otg_start_srp(struct otg_transceiver *otg_p)
+static int fsl_otg_start_srp(struct usb_otg *otg)
 {
-	struct fsl_otg *otg_dev = container_of(otg_p, struct fsl_otg, otg);
+	struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
 
-	if (!otg_p || otg_dev != fsl_otg_dev
-	    || otg_p->state != OTG_STATE_B_IDLE)
+	if (!otg || otg_dev != fsl_otg_dev
+	    || otg->phy->state != OTG_STATE_B_IDLE)
 		return -ENODEV;
 
 	otg_dev->fsm.b_bus_req = 1;
@@ -673,11 +673,11 @@
 }
 
 /* A_host suspend will call this function to start hnp */
-static int fsl_otg_start_hnp(struct otg_transceiver *otg_p)
+static int fsl_otg_start_hnp(struct usb_otg *otg)
 {
-	struct fsl_otg *otg_dev = container_of(otg_p, struct fsl_otg, otg);
+	struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
 
-	if (!otg_p || otg_dev != fsl_otg_dev)
+	if (!otg || otg_dev != fsl_otg_dev)
 		return -ENODEV;
 
 	DBG("start_hnp...n");
@@ -698,7 +698,7 @@
 irqreturn_t fsl_otg_isr(int irq, void *dev_id)
 {
 	struct otg_fsm *fsm = &((struct fsl_otg *)dev_id)->fsm;
-	struct otg_transceiver *otg = &((struct fsl_otg *)dev_id)->otg;
+	struct usb_otg *otg = ((struct fsl_otg *)dev_id)->phy.otg;
 	u32 otg_int_src, otg_sc;
 
 	otg_sc = fsl_readl(&usb_dr_regs->otgsc);
@@ -774,6 +774,12 @@
 	if (!fsl_otg_tc)
 		return -ENOMEM;
 
+	fsl_otg_tc->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
+	if (!fsl_otg_tc->phy.otg) {
+		kfree(fsl_otg_tc);
+		return -ENOMEM;
+	}
+
 	INIT_DELAYED_WORK(&fsl_otg_tc->otg_event, fsl_otg_event);
 
 	INIT_LIST_HEAD(&active_timers);
@@ -788,17 +794,19 @@
 	fsl_otg_tc->fsm.ops = &fsl_otg_ops;
 
 	/* initialize the otg structure */
-	fsl_otg_tc->otg.label = DRIVER_DESC;
-	fsl_otg_tc->otg.set_host = fsl_otg_set_host;
-	fsl_otg_tc->otg.set_peripheral = fsl_otg_set_peripheral;
-	fsl_otg_tc->otg.set_power = fsl_otg_set_power;
-	fsl_otg_tc->otg.start_hnp = fsl_otg_start_hnp;
-	fsl_otg_tc->otg.start_srp = fsl_otg_start_srp;
+	fsl_otg_tc->phy.label = DRIVER_DESC;
+	fsl_otg_tc->phy.set_power = fsl_otg_set_power;
+
+	fsl_otg_tc->phy.otg->phy = &fsl_otg_tc->phy;
+	fsl_otg_tc->phy.otg->set_host = fsl_otg_set_host;
+	fsl_otg_tc->phy.otg->set_peripheral = fsl_otg_set_peripheral;
+	fsl_otg_tc->phy.otg->start_hnp = fsl_otg_start_hnp;
+	fsl_otg_tc->phy.otg->start_srp = fsl_otg_start_srp;
 
 	fsl_otg_dev = fsl_otg_tc;
 
 	/* Store the otg transceiver */
-	status = otg_set_transceiver(&fsl_otg_tc->otg);
+	status = usb_set_transceiver(&fsl_otg_tc->phy);
 	if (status) {
 		pr_warn(FSL_OTG_NAME ": unable to register OTG transceiver.\n");
 		goto err;
@@ -807,6 +815,7 @@
 	return 0;
 err:
 	fsl_otg_uninit_timers();
+	kfree(fsl_otg_tc->phy.otg);
 	kfree(fsl_otg_tc);
 	return status;
 }
@@ -815,19 +824,19 @@
 int usb_otg_start(struct platform_device *pdev)
 {
 	struct fsl_otg *p_otg;
-	struct otg_transceiver *otg_trans = otg_get_transceiver();
+	struct usb_phy *otg_trans = usb_get_transceiver();
 	struct otg_fsm *fsm;
 	int status;
 	struct resource *res;
 	u32 temp;
 	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
 
-	p_otg = container_of(otg_trans, struct fsl_otg, otg);
+	p_otg = container_of(otg_trans, struct fsl_otg, phy);
 	fsm = &p_otg->fsm;
 
 	/* Initialize the state machine structure with default values */
 	SET_OTG_STATE(otg_trans, OTG_STATE_UNDEFINED);
-	fsm->transceiver = &p_otg->otg;
+	fsm->otg = p_otg->phy.otg;
 
 	/* We don't require predefined MEM/IRQ resource index */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -857,9 +866,10 @@
 	status = request_irq(p_otg->irq, fsl_otg_isr,
 				IRQF_SHARED, driver_name, p_otg);
 	if (status) {
-		dev_dbg(p_otg->otg.dev, "can't get IRQ %d, error %d\n",
+		dev_dbg(p_otg->phy.dev, "can't get IRQ %d, error %d\n",
 			p_otg->irq, status);
 		iounmap(p_otg->dr_mem_map);
+		kfree(p_otg->phy.otg);
 		kfree(p_otg);
 		return status;
 	}
@@ -919,10 +929,10 @@
 	 * Also: record initial state of ID pin
 	 */
 	if (fsl_readl(&p_otg->dr_mem_map->otgsc) & OTGSC_STS_USB_ID) {
-		p_otg->otg.state = OTG_STATE_UNDEFINED;
+		p_otg->phy.state = OTG_STATE_UNDEFINED;
 		p_otg->fsm.id = 1;
 	} else {
-		p_otg->otg.state = OTG_STATE_A_IDLE;
+		p_otg->phy.state = OTG_STATE_A_IDLE;
 		p_otg->fsm.id = 0;
 	}
 
@@ -978,7 +988,7 @@
 	/* State */
 	t = scnprintf(next, size,
 		      "OTG state: %s\n\n",
-		      otg_state_string(fsl_otg_dev->otg.state));
+		      otg_state_string(fsl_otg_dev->phy.state));
 	size -= t;
 	next += t;
 
@@ -1124,12 +1134,13 @@
 {
 	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
 
-	otg_set_transceiver(NULL);
+	usb_set_transceiver(NULL);
 	free_irq(fsl_otg_dev->irq, fsl_otg_dev);
 
 	iounmap((void *)usb_dr_regs);
 
 	fsl_otg_uninit_timers();
+	kfree(fsl_otg_dev->phy.otg);
 	kfree(fsl_otg_dev);
 
 	device_remove_file(&pdev->dev, &dev_attr_fsl_usb2_otg_state);
diff --git a/drivers/usb/otg/fsl_otg.h b/drivers/usb/otg/fsl_otg.h
index 3f8ef73..ca26628 100644
--- a/drivers/usb/otg/fsl_otg.h
+++ b/drivers/usb/otg/fsl_otg.h
@@ -369,7 +369,7 @@
 }
 
 struct fsl_otg {
-	struct otg_transceiver otg;
+	struct usb_phy phy;
 	struct otg_fsm fsm;
 	struct usb_dr_mmap *dr_mem_map;
 	struct delayed_work otg_event;
diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c
index fb644c1..3ece43a 100644
--- a/drivers/usb/otg/gpio_vbus.c
+++ b/drivers/usb/otg/gpio_vbus.c
@@ -32,7 +32,7 @@
  * Needs to be loaded before the UDC driver that will use it.
  */
 struct gpio_vbus_data {
-	struct otg_transceiver otg;
+	struct usb_phy		phy;
 	struct device          *dev;
 	struct regulator       *vbus_draw;
 	int			vbus_draw_enabled;
@@ -98,7 +98,7 @@
 	struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
 	int gpio;
 
-	if (!gpio_vbus->otg.gadget)
+	if (!gpio_vbus->phy.otg->gadget)
 		return;
 
 	/* Peripheral controllers which manage the pullup themselves won't have
@@ -108,8 +108,8 @@
 	 */
 	gpio = pdata->gpio_pullup;
 	if (is_vbus_powered(pdata)) {
-		gpio_vbus->otg.state = OTG_STATE_B_PERIPHERAL;
-		usb_gadget_vbus_connect(gpio_vbus->otg.gadget);
+		gpio_vbus->phy.state = OTG_STATE_B_PERIPHERAL;
+		usb_gadget_vbus_connect(gpio_vbus->phy.otg->gadget);
 
 		/* drawing a "unit load" is *always* OK, except for OTG */
 		set_vbus_draw(gpio_vbus, 100);
@@ -124,8 +124,8 @@
 
 		set_vbus_draw(gpio_vbus, 0);
 
-		usb_gadget_vbus_disconnect(gpio_vbus->otg.gadget);
-		gpio_vbus->otg.state = OTG_STATE_B_IDLE;
+		usb_gadget_vbus_disconnect(gpio_vbus->phy.otg->gadget);
+		gpio_vbus->phy.state = OTG_STATE_B_IDLE;
 	}
 }
 
@@ -135,12 +135,13 @@
 	struct platform_device *pdev = data;
 	struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
 	struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
+	struct usb_otg *otg = gpio_vbus->phy.otg;
 
 	dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n",
 		is_vbus_powered(pdata) ? "supplied" : "inactive",
-		gpio_vbus->otg.gadget ? gpio_vbus->otg.gadget->name : "none");
+		otg->gadget ? otg->gadget->name : "none");
 
-	if (gpio_vbus->otg.gadget)
+	if (otg->gadget)
 		schedule_work(&gpio_vbus->work);
 
 	return IRQ_HANDLED;
@@ -149,15 +150,15 @@
 /* OTG transceiver interface */
 
 /* bind/unbind the peripheral controller */
-static int gpio_vbus_set_peripheral(struct otg_transceiver *otg,
-				struct usb_gadget *gadget)
+static int gpio_vbus_set_peripheral(struct usb_otg *otg,
+					struct usb_gadget *gadget)
 {
 	struct gpio_vbus_data *gpio_vbus;
 	struct gpio_vbus_mach_info *pdata;
 	struct platform_device *pdev;
 	int gpio, irq;
 
-	gpio_vbus = container_of(otg, struct gpio_vbus_data, otg);
+	gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy);
 	pdev = to_platform_device(gpio_vbus->dev);
 	pdata = gpio_vbus->dev->platform_data;
 	irq = gpio_to_irq(pdata->gpio_vbus);
@@ -174,7 +175,7 @@
 		set_vbus_draw(gpio_vbus, 0);
 
 		usb_gadget_vbus_disconnect(otg->gadget);
-		otg->state = OTG_STATE_UNDEFINED;
+		otg->phy->state = OTG_STATE_UNDEFINED;
 
 		otg->gadget = NULL;
 		return 0;
@@ -189,23 +190,23 @@
 }
 
 /* effective for B devices, ignored for A-peripheral */
-static int gpio_vbus_set_power(struct otg_transceiver *otg, unsigned mA)
+static int gpio_vbus_set_power(struct usb_phy *phy, unsigned mA)
 {
 	struct gpio_vbus_data *gpio_vbus;
 
-	gpio_vbus = container_of(otg, struct gpio_vbus_data, otg);
+	gpio_vbus = container_of(phy, struct gpio_vbus_data, phy);
 
-	if (otg->state == OTG_STATE_B_PERIPHERAL)
+	if (phy->state == OTG_STATE_B_PERIPHERAL)
 		set_vbus_draw(gpio_vbus, mA);
 	return 0;
 }
 
 /* for non-OTG B devices: set/clear transceiver suspend mode */
-static int gpio_vbus_set_suspend(struct otg_transceiver *otg, int suspend)
+static int gpio_vbus_set_suspend(struct usb_phy *phy, int suspend)
 {
 	struct gpio_vbus_data *gpio_vbus;
 
-	gpio_vbus = container_of(otg, struct gpio_vbus_data, otg);
+	gpio_vbus = container_of(phy, struct gpio_vbus_data, phy);
 
 	/* draw max 0 mA from vbus in suspend mode; or the previously
 	 * recorded amount of current if not suspended
@@ -213,7 +214,7 @@
 	 * NOTE: high powered configs (mA > 100) may draw up to 2.5 mA
 	 * if they're wake-enabled ... we don't handle that yet.
 	 */
-	return gpio_vbus_set_power(otg, suspend ? 0 : gpio_vbus->mA);
+	return gpio_vbus_set_power(phy, suspend ? 0 : gpio_vbus->mA);
 }
 
 /* platform driver interface */
@@ -233,13 +234,21 @@
 	if (!gpio_vbus)
 		return -ENOMEM;
 
+	gpio_vbus->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
+	if (!gpio_vbus->phy.otg) {
+		kfree(gpio_vbus);
+		return -ENOMEM;
+	}
+
 	platform_set_drvdata(pdev, gpio_vbus);
 	gpio_vbus->dev = &pdev->dev;
-	gpio_vbus->otg.label = "gpio-vbus";
-	gpio_vbus->otg.state = OTG_STATE_UNDEFINED;
-	gpio_vbus->otg.set_peripheral = gpio_vbus_set_peripheral;
-	gpio_vbus->otg.set_power = gpio_vbus_set_power;
-	gpio_vbus->otg.set_suspend = gpio_vbus_set_suspend;
+	gpio_vbus->phy.label = "gpio-vbus";
+	gpio_vbus->phy.set_power = gpio_vbus_set_power;
+	gpio_vbus->phy.set_suspend = gpio_vbus_set_suspend;
+	gpio_vbus->phy.state = OTG_STATE_UNDEFINED;
+
+	gpio_vbus->phy.otg->phy = &gpio_vbus->phy;
+	gpio_vbus->phy.otg->set_peripheral = gpio_vbus_set_peripheral;
 
 	err = gpio_request(gpio, "vbus_detect");
 	if (err) {
@@ -288,7 +297,7 @@
 	}
 
 	/* only active when a gadget is registered */
-	err = otg_set_transceiver(&gpio_vbus->otg);
+	err = usb_set_transceiver(&gpio_vbus->phy);
 	if (err) {
 		dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
 			err);
@@ -304,6 +313,7 @@
 	gpio_free(pdata->gpio_vbus);
 err_gpio:
 	platform_set_drvdata(pdev, NULL);
+	kfree(gpio_vbus->phy.otg);
 	kfree(gpio_vbus);
 	return err;
 }
@@ -316,13 +326,14 @@
 
 	regulator_put(gpio_vbus->vbus_draw);
 
-	otg_set_transceiver(NULL);
+	usb_set_transceiver(NULL);
 
 	free_irq(gpio_to_irq(gpio), &pdev->dev);
 	if (gpio_is_valid(pdata->gpio_pullup))
 		gpio_free(pdata->gpio_pullup);
 	gpio_free(gpio);
 	platform_set_drvdata(pdev, NULL);
+	kfree(gpio_vbus->phy.otg);
 	kfree(gpio_vbus);
 
 	return 0;
diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c
index 8c86787..70cf5d7 100644
--- a/drivers/usb/otg/isp1301_omap.c
+++ b/drivers/usb/otg/isp1301_omap.c
@@ -52,7 +52,7 @@
 MODULE_LICENSE("GPL");
 
 struct isp1301 {
-	struct otg_transceiver	otg;
+	struct usb_phy		phy;
 	struct i2c_client	*client;
 	void			(*i2c_release)(struct device *dev);
 
@@ -236,7 +236,7 @@
 
 static inline const char *state_name(struct isp1301 *isp)
 {
-	return otg_state_string(isp->otg.state);
+	return otg_state_string(isp->phy.state);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -251,7 +251,7 @@
 
 static void power_down(struct isp1301 *isp)
 {
-	isp->otg.state = OTG_STATE_UNDEFINED;
+	isp->phy.state = OTG_STATE_UNDEFINED;
 
 	// isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
 	isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND);
@@ -280,13 +280,13 @@
 #else
 	struct device	*dev;
 
-	if (!isp->otg.host)
+	if (!isp->phy.otg->host)
 		return -ENODEV;
 
 	/* Currently ASSUMES only the OTG port matters;
 	 * other ports could be active...
 	 */
-	dev = isp->otg.host->controller;
+	dev = isp->phy.otg->host->controller;
 	return dev->driver->suspend(dev, 3, 0);
 #endif
 }
@@ -298,20 +298,20 @@
 #else
 	struct device	*dev;
 
-	if (!isp->otg.host)
+	if (!isp->phy.otg->host)
 		return -ENODEV;
 
-	dev = isp->otg.host->controller;
+	dev = isp->phy.otg->host->controller;
 	return dev->driver->resume(dev, 0);
 #endif
 }
 
 static int gadget_suspend(struct isp1301 *isp)
 {
-	isp->otg.gadget->b_hnp_enable = 0;
-	isp->otg.gadget->a_hnp_support = 0;
-	isp->otg.gadget->a_alt_hnp_support = 0;
-	return usb_gadget_vbus_disconnect(isp->otg.gadget);
+	isp->phy.otg->gadget->b_hnp_enable = 0;
+	isp->phy.otg->gadget->a_hnp_support = 0;
+	isp->phy.otg->gadget->a_alt_hnp_support = 0;
+	return usb_gadget_vbus_disconnect(isp->phy.otg->gadget);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -341,19 +341,19 @@
 {
 	u32 l;
 
-	if (isp->otg.state == OTG_STATE_A_IDLE)
+	if (isp->phy.state == OTG_STATE_A_IDLE)
 		return;
 
-	isp->otg.default_a = 1;
-	if (isp->otg.host) {
-		isp->otg.host->is_b_host = 0;
+	isp->phy.otg->default_a = 1;
+	if (isp->phy.otg->host) {
+		isp->phy.otg->host->is_b_host = 0;
 		host_suspend(isp);
 	}
-	if (isp->otg.gadget) {
-		isp->otg.gadget->is_a_peripheral = 1;
+	if (isp->phy.otg->gadget) {
+		isp->phy.otg->gadget->is_a_peripheral = 1;
 		gadget_suspend(isp);
 	}
-	isp->otg.state = OTG_STATE_A_IDLE;
+	isp->phy.state = OTG_STATE_A_IDLE;
 	l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS;
 	omap_writel(l, OTG_CTRL);
 	isp->last_otg_ctrl = l;
@@ -365,19 +365,19 @@
 {
 	u32 l;
 
-	if (isp->otg.state == OTG_STATE_B_IDLE)
+	if (isp->phy.state == OTG_STATE_B_IDLE)
 		return;
 
-	isp->otg.default_a = 0;
-	if (isp->otg.host) {
-		isp->otg.host->is_b_host = 1;
+	isp->phy.otg->default_a = 0;
+	if (isp->phy.otg->host) {
+		isp->phy.otg->host->is_b_host = 1;
 		host_suspend(isp);
 	}
-	if (isp->otg.gadget) {
-		isp->otg.gadget->is_a_peripheral = 0;
+	if (isp->phy.otg->gadget) {
+		isp->phy.otg->gadget->is_a_peripheral = 0;
 		gadget_suspend(isp);
 	}
-	isp->otg.state = OTG_STATE_B_IDLE;
+	isp->phy.state = OTG_STATE_B_IDLE;
 	l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS;
 	omap_writel(l, OTG_CTRL);
 	isp->last_otg_ctrl = l;
@@ -478,7 +478,7 @@
 	default:
 		break;
 	}
-	if (isp->otg.state == state && !extra)
+	if (isp->phy.state == state && !extra)
 		return;
 	pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag,
 		otg_state_string(state), fsm, state_name(isp),
@@ -502,22 +502,23 @@
 
 	if (int_src & INTR_SESS_VLD)
 		otg_ctrl |= OTG_ASESSVLD;
-	else if (isp->otg.state == OTG_STATE_A_WAIT_VFALL) {
+	else if (isp->phy.state == OTG_STATE_A_WAIT_VFALL) {
 		a_idle(isp, "vfall");
 		otg_ctrl &= ~OTG_CTRL_BITS;
 	}
 	if (int_src & INTR_VBUS_VLD)
 		otg_ctrl |= OTG_VBUSVLD;
 	if (int_src & INTR_ID_GND) {		/* default-A */
-		if (isp->otg.state == OTG_STATE_B_IDLE
-				|| isp->otg.state == OTG_STATE_UNDEFINED) {
+		if (isp->phy.state == OTG_STATE_B_IDLE
+				|| isp->phy.state
+					== OTG_STATE_UNDEFINED) {
 			a_idle(isp, "init");
 			return;
 		}
 	} else {				/* default-B */
 		otg_ctrl |= OTG_ID;
-		if (isp->otg.state == OTG_STATE_A_IDLE
-				|| isp->otg.state == OTG_STATE_UNDEFINED) {
+		if (isp->phy.state == OTG_STATE_A_IDLE
+			|| isp->phy.state == OTG_STATE_UNDEFINED) {
 			b_idle(isp, "init");
 			return;
 		}
@@ -551,14 +552,14 @@
 	isp->last_otg_ctrl = otg_ctrl;
 	otg_ctrl = otg_ctrl & OTG_XCEIV_INPUTS;
 
-	switch (isp->otg.state) {
+	switch (isp->phy.state) {
 	case OTG_STATE_B_IDLE:
 	case OTG_STATE_B_PERIPHERAL:
 	case OTG_STATE_B_SRP_INIT:
 		if (!(otg_ctrl & OTG_PULLUP)) {
 			// if (otg_ctrl & OTG_B_HNPEN) {
-			if (isp->otg.gadget->b_hnp_enable) {
-				isp->otg.state = OTG_STATE_B_WAIT_ACON;
+			if (isp->phy.otg->gadget->b_hnp_enable) {
+				isp->phy.state = OTG_STATE_B_WAIT_ACON;
 				pr_debug("  --> b_wait_acon\n");
 			}
 			goto pulldown;
@@ -585,10 +586,10 @@
 		else clr |= ISP; \
 		} while (0)
 
-	if (!(isp->otg.host))
+	if (!(isp->phy.otg->host))
 		otg_ctrl &= ~OTG_DRV_VBUS;
 
-	switch (isp->otg.state) {
+	switch (isp->phy.state) {
 	case OTG_STATE_A_SUSPEND:
 		if (otg_ctrl & OTG_DRV_VBUS) {
 			set |= OTG1_VBUS_DRV;
@@ -599,7 +600,7 @@
 
 		/* FALLTHROUGH */
 	case OTG_STATE_A_VBUS_ERR:
-		isp->otg.state = OTG_STATE_A_WAIT_VFALL;
+		isp->phy.state = OTG_STATE_A_WAIT_VFALL;
 		pr_debug("  --> a_wait_vfall\n");
 		/* FALLTHROUGH */
 	case OTG_STATE_A_WAIT_VFALL:
@@ -608,7 +609,7 @@
 		break;
 	case OTG_STATE_A_IDLE:
 		if (otg_ctrl & OTG_DRV_VBUS) {
-			isp->otg.state = OTG_STATE_A_WAIT_VRISE;
+			isp->phy.state = OTG_STATE_A_WAIT_VRISE;
 			pr_debug("  --> a_wait_vrise\n");
 		}
 		/* FALLTHROUGH */
@@ -628,17 +629,17 @@
 	if (otg_change & OTG_PULLUP) {
 		u32 l;
 
-		switch (isp->otg.state) {
+		switch (isp->phy.state) {
 		case OTG_STATE_B_IDLE:
 			if (clr & OTG1_DP_PULLUP)
 				break;
-			isp->otg.state = OTG_STATE_B_PERIPHERAL;
+			isp->phy.state = OTG_STATE_B_PERIPHERAL;
 			pr_debug("  --> b_peripheral\n");
 			break;
 		case OTG_STATE_A_SUSPEND:
 			if (clr & OTG1_DP_PULLUP)
 				break;
-			isp->otg.state = OTG_STATE_A_PERIPHERAL;
+			isp->phy.state = OTG_STATE_A_PERIPHERAL;
 			pr_debug("  --> a_peripheral\n");
 			break;
 		default:
@@ -659,6 +660,7 @@
 	u32		otg_ctrl;
 	int		ret = IRQ_NONE;
 	struct isp1301	*isp = _isp;
+	struct usb_otg	*otg = isp->phy.otg;
 
 	/* update ISP1301 transceiver from OTG controller */
 	if (otg_irq & OPRT_CHG) {
@@ -675,7 +677,7 @@
 		 * remote wakeup (SRP, normal) using their own timer
 		 * to give "check cable and A-device" messages.
 		 */
-		if (isp->otg.state == OTG_STATE_B_SRP_INIT)
+		if (isp->phy.state == OTG_STATE_B_SRP_INIT)
 			b_idle(isp, "srp_timeout");
 
 		omap_writew(B_SRP_TMROUT, OTG_IRQ_SRC);
@@ -693,7 +695,7 @@
 		omap_writel(otg_ctrl, OTG_CTRL);
 
 		/* subset of b_peripheral()... */
-		isp->otg.state = OTG_STATE_B_PERIPHERAL;
+		isp->phy.state = OTG_STATE_B_PERIPHERAL;
 		pr_debug("  --> b_peripheral\n");
 
 		omap_writew(B_HNP_FAIL, OTG_IRQ_SRC);
@@ -705,9 +707,9 @@
 				state_name(isp), omap_readl(OTG_CTRL));
 
 		isp1301_defer_work(isp, WORK_UPDATE_OTG);
-		switch (isp->otg.state) {
+		switch (isp->phy.state) {
 		case OTG_STATE_A_IDLE:
-			if (!isp->otg.host)
+			if (!otg->host)
 				break;
 			isp1301_defer_work(isp, WORK_HOST_RESUME);
 			otg_ctrl = omap_readl(OTG_CTRL);
@@ -736,7 +738,7 @@
 		otg_ctrl |= OTG_BUSDROP;
 		otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
 		omap_writel(otg_ctrl, OTG_CTRL);
-		isp->otg.state = OTG_STATE_A_WAIT_VFALL;
+		isp->phy.state = OTG_STATE_A_WAIT_VFALL;
 
 		omap_writew(A_REQ_TMROUT, OTG_IRQ_SRC);
 		ret = IRQ_HANDLED;
@@ -750,7 +752,7 @@
 		otg_ctrl |= OTG_BUSDROP;
 		otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
 		omap_writel(otg_ctrl, OTG_CTRL);
-		isp->otg.state = OTG_STATE_A_VBUS_ERR;
+		isp->phy.state = OTG_STATE_A_VBUS_ERR;
 
 		omap_writew(A_VBUS_ERR, OTG_IRQ_SRC);
 		ret = IRQ_HANDLED;
@@ -771,7 +773,7 @@
 
 		/* role is peripheral */
 		if (otg_ctrl & OTG_DRIVER_SEL) {
-			switch (isp->otg.state) {
+			switch (isp->phy.state) {
 			case OTG_STATE_A_IDLE:
 				b_idle(isp, __func__);
 				break;
@@ -787,19 +789,19 @@
 				omap_writel(otg_ctrl | OTG_A_BUSREQ, OTG_CTRL);
 			}
 
-			if (isp->otg.host) {
-				switch (isp->otg.state) {
+			if (otg->host) {
+				switch (isp->phy.state) {
 				case OTG_STATE_B_WAIT_ACON:
-					isp->otg.state = OTG_STATE_B_HOST;
+					isp->phy.state = OTG_STATE_B_HOST;
 					pr_debug("  --> b_host\n");
 					kick = 1;
 					break;
 				case OTG_STATE_A_WAIT_BCON:
-					isp->otg.state = OTG_STATE_A_HOST;
+					isp->phy.state = OTG_STATE_A_HOST;
 					pr_debug("  --> a_host\n");
 					break;
 				case OTG_STATE_A_PERIPHERAL:
-					isp->otg.state = OTG_STATE_A_WAIT_BCON;
+					isp->phy.state = OTG_STATE_A_WAIT_BCON;
 					pr_debug("  --> a_wait_bcon\n");
 					break;
 				default:
@@ -813,8 +815,7 @@
 		ret = IRQ_HANDLED;
 
 		if (kick)
-			usb_bus_start_enum(isp->otg.host,
-						isp->otg.host->otg_port);
+			usb_bus_start_enum(otg->host, otg->host->otg_port);
 	}
 
 	check_state(isp, __func__);
@@ -930,7 +931,7 @@
 	l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS;
 	omap_writel(l, OTG_CTRL);
 
-	usb_gadget_vbus_connect(isp->otg.gadget);
+	usb_gadget_vbus_connect(isp->phy.otg->gadget);
 
 #ifdef	CONFIG_USB_OTG
 	enable_vbus_draw(isp, 8);
@@ -940,7 +941,7 @@
 	/* UDC driver just set OTG_BSESSVLD */
 	isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLUP);
 	isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLDOWN);
-	isp->otg.state = OTG_STATE_B_PERIPHERAL;
+	isp->phy.state = OTG_STATE_B_PERIPHERAL;
 	pr_debug("  --> b_peripheral\n");
 	dump_regs(isp, "2periph");
 #endif
@@ -948,8 +949,9 @@
 
 static void isp_update_otg(struct isp1301 *isp, u8 stat)
 {
+	struct usb_otg		*otg = isp->phy.otg;
 	u8			isp_stat, isp_bstat;
-	enum usb_otg_state	state = isp->otg.state;
+	enum usb_otg_state	state = isp->phy.state;
 
 	if (stat & INTR_BDIS_ACON)
 		pr_debug("OTG:  BDIS_ACON, %s\n", state_name(isp));
@@ -957,7 +959,7 @@
 	/* start certain state transitions right away */
 	isp_stat = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE);
 	if (isp_stat & INTR_ID_GND) {
-		if (isp->otg.default_a) {
+		if (otg->default_a) {
 			switch (state) {
 			case OTG_STATE_B_IDLE:
 				a_idle(isp, "idle");
@@ -972,7 +974,7 @@
 				 * when HNP is used.
 				 */
 				if (isp_stat & INTR_VBUS_VLD)
-					isp->otg.state = OTG_STATE_A_HOST;
+					isp->phy.state = OTG_STATE_A_HOST;
 				break;
 			case OTG_STATE_A_WAIT_VFALL:
 				if (!(isp_stat & INTR_SESS_VLD))
@@ -980,7 +982,7 @@
 				break;
 			default:
 				if (!(isp_stat & INTR_VBUS_VLD))
-					isp->otg.state = OTG_STATE_A_VBUS_ERR;
+					isp->phy.state = OTG_STATE_A_VBUS_ERR;
 				break;
 			}
 			isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
@@ -989,14 +991,14 @@
 			case OTG_STATE_B_PERIPHERAL:
 			case OTG_STATE_B_HOST:
 			case OTG_STATE_B_WAIT_ACON:
-				usb_gadget_vbus_disconnect(isp->otg.gadget);
+				usb_gadget_vbus_disconnect(otg->gadget);
 				break;
 			default:
 				break;
 			}
 			if (state != OTG_STATE_A_IDLE)
 				a_idle(isp, "id");
-			if (isp->otg.host && state == OTG_STATE_A_IDLE)
+			if (otg->host && state == OTG_STATE_A_IDLE)
 				isp1301_defer_work(isp, WORK_HOST_RESUME);
 			isp_bstat = 0;
 		}
@@ -1006,10 +1008,10 @@
 		/* if user unplugged mini-A end of cable,
 		 * don't bypass A_WAIT_VFALL.
 		 */
-		if (isp->otg.default_a) {
+		if (otg->default_a) {
 			switch (state) {
 			default:
-				isp->otg.state = OTG_STATE_A_WAIT_VFALL;
+				isp->phy.state = OTG_STATE_A_WAIT_VFALL;
 				break;
 			case OTG_STATE_A_WAIT_VFALL:
 				state = OTG_STATE_A_IDLE;
@@ -1022,7 +1024,7 @@
 				host_suspend(isp);
 				isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1,
 						MC1_BDIS_ACON_EN);
-				isp->otg.state = OTG_STATE_B_IDLE;
+				isp->phy.state = OTG_STATE_B_IDLE;
 				l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
 				l &= ~OTG_CTRL_BITS;
 				omap_writel(l, OTG_CTRL);
@@ -1033,7 +1035,7 @@
 		}
 		isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
 
-		switch (isp->otg.state) {
+		switch (isp->phy.state) {
 		case OTG_STATE_B_PERIPHERAL:
 		case OTG_STATE_B_WAIT_ACON:
 		case OTG_STATE_B_HOST:
@@ -1055,7 +1057,7 @@
 			omap_writel(l, OTG_CTRL);
 			/* FALLTHROUGH */
 		case OTG_STATE_B_IDLE:
-			if (isp->otg.gadget && (isp_bstat & OTG_B_SESS_VLD)) {
+			if (otg->gadget && (isp_bstat & OTG_B_SESS_VLD)) {
 #ifdef	CONFIG_USB_OTG
 				update_otg1(isp, isp_stat);
 				update_otg2(isp, isp_bstat);
@@ -1073,7 +1075,7 @@
 		}
 	}
 
-	if (state != isp->otg.state)
+	if (state != isp->phy.state)
 		pr_debug("  isp, %s -> %s\n",
 				otg_state_string(state), state_name(isp));
 
@@ -1131,10 +1133,10 @@
 			 * skip A_WAIT_VRISE; hc transitions invisibly
 			 * skip A_WAIT_BCON; same.
 			 */
-			switch (isp->otg.state) {
+			switch (isp->phy.state) {
 			case OTG_STATE_A_WAIT_BCON:
 			case OTG_STATE_A_WAIT_VRISE:
-				isp->otg.state = OTG_STATE_A_HOST;
+				isp->phy.state = OTG_STATE_A_HOST;
 				pr_debug("  --> a_host\n");
 				otg_ctrl = omap_readl(OTG_CTRL);
 				otg_ctrl |= OTG_A_BUSREQ;
@@ -1143,7 +1145,7 @@
 				omap_writel(otg_ctrl, OTG_CTRL);
 				break;
 			case OTG_STATE_B_WAIT_ACON:
-				isp->otg.state = OTG_STATE_B_HOST;
+				isp->phy.state = OTG_STATE_B_HOST;
 				pr_debug("  --> b_host (acon)\n");
 				break;
 			case OTG_STATE_B_HOST:
@@ -1204,6 +1206,7 @@
 	/* ugly -- i2c hijacks our memory hook to wait_for_completion() */
 	if (isp->i2c_release)
 		isp->i2c_release(dev);
+	kfree(isp->phy.otg);
 	kfree (isp);
 }
 
@@ -1274,9 +1277,9 @@
 
 /* add or disable the host device+driver */
 static int
-isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
+isp1301_set_host(struct usb_otg *otg, struct usb_bus *host)
 {
-	struct isp1301	*isp = container_of(otg, struct isp1301, otg);
+	struct isp1301	*isp = container_of(otg->phy, struct isp1301, phy);
 
 	if (!otg || isp != the_transceiver)
 		return -ENODEV;
@@ -1284,21 +1287,21 @@
 	if (!host) {
 		omap_writew(0, OTG_IRQ_EN);
 		power_down(isp);
-		isp->otg.host = NULL;
+		otg->host = NULL;
 		return 0;
 	}
 
 #ifdef	CONFIG_USB_OTG
-	isp->otg.host = host;
+	otg->host = host;
 	dev_dbg(&isp->client->dev, "registered host\n");
 	host_suspend(isp);
-	if (isp->otg.gadget)
+	if (otg->gadget)
 		return isp1301_otg_enable(isp);
 	return 0;
 
 #elif	!defined(CONFIG_USB_GADGET_OMAP)
 	// FIXME update its refcount
-	isp->otg.host = host;
+	otg->host = host;
 
 	power_up(isp);
 
@@ -1330,9 +1333,9 @@
 }
 
 static int
-isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
+isp1301_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
 {
-	struct isp1301	*isp = container_of(otg, struct isp1301, otg);
+	struct isp1301	*isp = container_of(otg->phy, struct isp1301, phy);
 #ifndef	CONFIG_USB_OTG
 	u32 l;
 #endif
@@ -1342,24 +1345,24 @@
 
 	if (!gadget) {
 		omap_writew(0, OTG_IRQ_EN);
-		if (!isp->otg.default_a)
+		if (!otg->default_a)
 			enable_vbus_draw(isp, 0);
-		usb_gadget_vbus_disconnect(isp->otg.gadget);
-		isp->otg.gadget = NULL;
+		usb_gadget_vbus_disconnect(otg->gadget);
+		otg->gadget = NULL;
 		power_down(isp);
 		return 0;
 	}
 
 #ifdef	CONFIG_USB_OTG
-	isp->otg.gadget = gadget;
+	otg->gadget = gadget;
 	dev_dbg(&isp->client->dev, "registered gadget\n");
 	/* gadget driver may be suspended until vbus_connect () */
-	if (isp->otg.host)
+	if (otg->host)
 		return isp1301_otg_enable(isp);
 	return 0;
 
 #elif	!defined(CONFIG_USB_OHCI_HCD) && !defined(CONFIG_USB_OHCI_HCD_MODULE)
-	isp->otg.gadget = gadget;
+	otg->gadget = gadget;
 	// FIXME update its refcount
 
 	l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
@@ -1368,7 +1371,7 @@
 	omap_writel(l, OTG_CTRL);
 
 	power_up(isp);
-	isp->otg.state = OTG_STATE_B_IDLE;
+	isp->phy.state = OTG_STATE_B_IDLE;
 
 	if (machine_is_omap_h2() || machine_is_omap_h3())
 		isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
@@ -1399,7 +1402,7 @@
 /*-------------------------------------------------------------------------*/
 
 static int
-isp1301_set_power(struct otg_transceiver *dev, unsigned mA)
+isp1301_set_power(struct usb_phy *dev, unsigned mA)
 {
 	if (!the_transceiver)
 		return -ENODEV;
@@ -1409,13 +1412,13 @@
 }
 
 static int
-isp1301_start_srp(struct otg_transceiver *dev)
+isp1301_start_srp(struct usb_otg *otg)
 {
-	struct isp1301	*isp = container_of(dev, struct isp1301, otg);
+	struct isp1301	*isp = container_of(otg->phy, struct isp1301, phy);
 	u32		otg_ctrl;
 
-	if (!dev || isp != the_transceiver
-			|| isp->otg.state != OTG_STATE_B_IDLE)
+	if (!otg || isp != the_transceiver
+			|| isp->phy.state != OTG_STATE_B_IDLE)
 		return -ENODEV;
 
 	otg_ctrl = omap_readl(OTG_CTRL);
@@ -1425,7 +1428,7 @@
 	otg_ctrl |= OTG_B_BUSREQ;
 	otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK;
 	omap_writel(otg_ctrl, OTG_CTRL);
-	isp->otg.state = OTG_STATE_B_SRP_INIT;
+	isp->phy.state = OTG_STATE_B_SRP_INIT;
 
 	pr_debug("otg: SRP, %s ... %06x\n", state_name(isp),
 			omap_readl(OTG_CTRL));
@@ -1436,27 +1439,26 @@
 }
 
 static int
-isp1301_start_hnp(struct otg_transceiver *dev)
+isp1301_start_hnp(struct usb_otg *otg)
 {
 #ifdef	CONFIG_USB_OTG
-	struct isp1301	*isp = container_of(dev, struct isp1301, otg);
+	struct isp1301	*isp = container_of(otg->phy, struct isp1301, phy);
 	u32 l;
 
-	if (!dev || isp != the_transceiver)
+	if (!otg || isp != the_transceiver)
 		return -ENODEV;
-	if (isp->otg.default_a && (isp->otg.host == NULL
-			|| !isp->otg.host->b_hnp_enable))
+	if (otg->default_a && (otg->host == NULL || !otg->host->b_hnp_enable))
 		return -ENOTCONN;
-	if (!isp->otg.default_a && (isp->otg.gadget == NULL
-			|| !isp->otg.gadget->b_hnp_enable))
+	if (!otg->default_a && (otg->gadget == NULL
+			|| !otg->gadget->b_hnp_enable))
 		return -ENOTCONN;
 
 	/* We want hardware to manage most HNP protocol timings.
 	 * So do this part as early as possible...
 	 */
-	switch (isp->otg.state) {
+	switch (isp->phy.state) {
 	case OTG_STATE_B_HOST:
-		isp->otg.state = OTG_STATE_B_PERIPHERAL;
+		isp->phy.state = OTG_STATE_B_PERIPHERAL;
 		/* caller will suspend next */
 		break;
 	case OTG_STATE_A_HOST:
@@ -1466,7 +1468,7 @@
 				MC1_BDIS_ACON_EN);
 #endif
 		/* caller must suspend then clear A_BUSREQ */
-		usb_gadget_vbus_connect(isp->otg.gadget);
+		usb_gadget_vbus_connect(otg->gadget);
 		l = omap_readl(OTG_CTRL);
 		l |= OTG_A_SETB_HNPEN;
 		omap_writel(l, OTG_CTRL);
@@ -1503,6 +1505,12 @@
 	if (!isp)
 		return 0;
 
+	isp->phy.otg = kzalloc(sizeof *isp->phy.otg, GFP_KERNEL);
+	if (!isp->phy.otg) {
+		kfree(isp);
+		return 0;
+	}
+
 	INIT_WORK(&isp->work, isp1301_work);
 	init_timer(&isp->timer);
 	isp->timer.function = isp1301_timer;
@@ -1576,14 +1584,15 @@
 		goto fail;
 	}
 
-	isp->otg.dev = &i2c->dev;
-	isp->otg.label = DRIVER_NAME;
+	isp->phy.dev = &i2c->dev;
+	isp->phy.label = DRIVER_NAME;
+	isp->phy.set_power = isp1301_set_power,
 
-	isp->otg.set_host = isp1301_set_host,
-	isp->otg.set_peripheral = isp1301_set_peripheral,
-	isp->otg.set_power = isp1301_set_power,
-	isp->otg.start_srp = isp1301_start_srp,
-	isp->otg.start_hnp = isp1301_start_hnp,
+	isp->phy.otg->phy = &isp->phy;
+	isp->phy.otg->set_host = isp1301_set_host,
+	isp->phy.otg->set_peripheral = isp1301_set_peripheral,
+	isp->phy.otg->start_srp = isp1301_start_srp,
+	isp->phy.otg->start_hnp = isp1301_start_hnp,
 
 	enable_vbus_draw(isp, 0);
 	power_down(isp);
@@ -1601,7 +1610,7 @@
 	dev_dbg(&i2c->dev, "scheduled timer, %d min\n", TIMER_MINUTES);
 #endif
 
-	status = otg_set_transceiver(&isp->otg);
+	status = usb_set_transceiver(&isp->phy);
 	if (status < 0)
 		dev_err(&i2c->dev, "can't register transceiver, %d\n",
 			status);
@@ -1609,6 +1618,7 @@
 	return 0;
 
 fail:
+	kfree(isp->phy.otg);
 	kfree(isp);
 	return -ENODEV;
 }
@@ -1639,7 +1649,7 @@
 static void __exit isp_exit(void)
 {
 	if (the_transceiver)
-		otg_set_transceiver(NULL);
+		usb_set_transceiver(NULL);
 	i2c_del_driver(&isp1301_driver);
 }
 module_exit(isp_exit);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index b276f8f..1d0347c 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -69,9 +69,9 @@
 	int ret = 0;
 
 	if (init) {
-		hsusb_vddcx = regulator_get(motg->otg.dev, "HSUSB_VDDCX");
+		hsusb_vddcx = regulator_get(motg->phy.dev, "HSUSB_VDDCX");
 		if (IS_ERR(hsusb_vddcx)) {
-			dev_err(motg->otg.dev, "unable to get hsusb vddcx\n");
+			dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
 			return PTR_ERR(hsusb_vddcx);
 		}
 
@@ -79,7 +79,7 @@
 				USB_PHY_VDD_DIG_VOL_MIN,
 				USB_PHY_VDD_DIG_VOL_MAX);
 		if (ret) {
-			dev_err(motg->otg.dev, "unable to set the voltage "
+			dev_err(motg->phy.dev, "unable to set the voltage "
 					"for hsusb vddcx\n");
 			regulator_put(hsusb_vddcx);
 			return ret;
@@ -87,18 +87,18 @@
 
 		ret = regulator_enable(hsusb_vddcx);
 		if (ret) {
-			dev_err(motg->otg.dev, "unable to enable hsusb vddcx\n");
+			dev_err(motg->phy.dev, "unable to enable hsusb vddcx\n");
 			regulator_put(hsusb_vddcx);
 		}
 	} else {
 		ret = regulator_set_voltage(hsusb_vddcx, 0,
 			USB_PHY_VDD_DIG_VOL_MAX);
 		if (ret)
-			dev_err(motg->otg.dev, "unable to set the voltage "
+			dev_err(motg->phy.dev, "unable to set the voltage "
 					"for hsusb vddcx\n");
 		ret = regulator_disable(hsusb_vddcx);
 		if (ret)
-			dev_err(motg->otg.dev, "unable to disable hsusb vddcx\n");
+			dev_err(motg->phy.dev, "unable to disable hsusb vddcx\n");
 
 		regulator_put(hsusb_vddcx);
 	}
@@ -111,40 +111,40 @@
 	int rc = 0;
 
 	if (init) {
-		hsusb_3p3 = regulator_get(motg->otg.dev, "HSUSB_3p3");
+		hsusb_3p3 = regulator_get(motg->phy.dev, "HSUSB_3p3");
 		if (IS_ERR(hsusb_3p3)) {
-			dev_err(motg->otg.dev, "unable to get hsusb 3p3\n");
+			dev_err(motg->phy.dev, "unable to get hsusb 3p3\n");
 			return PTR_ERR(hsusb_3p3);
 		}
 
 		rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN,
 				USB_PHY_3P3_VOL_MAX);
 		if (rc) {
-			dev_err(motg->otg.dev, "unable to set voltage level "
+			dev_err(motg->phy.dev, "unable to set voltage level "
 					"for hsusb 3p3\n");
 			goto put_3p3;
 		}
 		rc = regulator_enable(hsusb_3p3);
 		if (rc) {
-			dev_err(motg->otg.dev, "unable to enable the hsusb 3p3\n");
+			dev_err(motg->phy.dev, "unable to enable the hsusb 3p3\n");
 			goto put_3p3;
 		}
-		hsusb_1p8 = regulator_get(motg->otg.dev, "HSUSB_1p8");
+		hsusb_1p8 = regulator_get(motg->phy.dev, "HSUSB_1p8");
 		if (IS_ERR(hsusb_1p8)) {
-			dev_err(motg->otg.dev, "unable to get hsusb 1p8\n");
+			dev_err(motg->phy.dev, "unable to get hsusb 1p8\n");
 			rc = PTR_ERR(hsusb_1p8);
 			goto disable_3p3;
 		}
 		rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
 				USB_PHY_1P8_VOL_MAX);
 		if (rc) {
-			dev_err(motg->otg.dev, "unable to set voltage level "
+			dev_err(motg->phy.dev, "unable to set voltage level "
 					"for hsusb 1p8\n");
 			goto put_1p8;
 		}
 		rc = regulator_enable(hsusb_1p8);
 		if (rc) {
-			dev_err(motg->otg.dev, "unable to enable the hsusb 1p8\n");
+			dev_err(motg->phy.dev, "unable to enable the hsusb 1p8\n");
 			goto put_1p8;
 		}
 
@@ -235,9 +235,9 @@
 	return ret < 0 ? ret : 0;
 }
 
-static int ulpi_read(struct otg_transceiver *otg, u32 reg)
+static int ulpi_read(struct usb_phy *phy, u32 reg)
 {
-	struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
 	int cnt = 0;
 
 	/* initiate read operation */
@@ -253,16 +253,16 @@
 	}
 
 	if (cnt >= ULPI_IO_TIMEOUT_USEC) {
-		dev_err(otg->dev, "ulpi_read: timeout %08x\n",
+		dev_err(phy->dev, "ulpi_read: timeout %08x\n",
 			readl(USB_ULPI_VIEWPORT));
 		return -ETIMEDOUT;
 	}
 	return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
 }
 
-static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
+static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
 {
-	struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
 	int cnt = 0;
 
 	/* initiate write operation */
@@ -279,13 +279,13 @@
 	}
 
 	if (cnt >= ULPI_IO_TIMEOUT_USEC) {
-		dev_err(otg->dev, "ulpi_write: timeout\n");
+		dev_err(phy->dev, "ulpi_write: timeout\n");
 		return -ETIMEDOUT;
 	}
 	return 0;
 }
 
-static struct otg_io_access_ops msm_otg_io_ops = {
+static struct usb_phy_io_ops msm_otg_io_ops = {
 	.read = ulpi_read,
 	.write = ulpi_write,
 };
@@ -299,9 +299,9 @@
 		return;
 
 	while (seq[0] >= 0) {
-		dev_vdbg(motg->otg.dev, "ulpi: write 0x%02x to 0x%02x\n",
+		dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
 				seq[0], seq[1]);
-		ulpi_write(&motg->otg, seq[0], seq[1]);
+		ulpi_write(&motg->phy, seq[0], seq[1]);
 		seq += 2;
 	}
 }
@@ -313,11 +313,11 @@
 	if (assert) {
 		ret = clk_reset(motg->clk, CLK_RESET_ASSERT);
 		if (ret)
-			dev_err(motg->otg.dev, "usb hs_clk assert failed\n");
+			dev_err(motg->phy.dev, "usb hs_clk assert failed\n");
 	} else {
 		ret = clk_reset(motg->clk, CLK_RESET_DEASSERT);
 		if (ret)
-			dev_err(motg->otg.dev, "usb hs_clk deassert failed\n");
+			dev_err(motg->phy.dev, "usb hs_clk deassert failed\n");
 	}
 	return ret;
 }
@@ -328,13 +328,13 @@
 
 	ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT);
 	if (ret) {
-		dev_err(motg->otg.dev, "usb phy clk assert failed\n");
+		dev_err(motg->phy.dev, "usb phy clk assert failed\n");
 		return ret;
 	}
 	usleep_range(10000, 12000);
 	ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT);
 	if (ret)
-		dev_err(motg->otg.dev, "usb phy clk deassert failed\n");
+		dev_err(motg->phy.dev, "usb phy clk deassert failed\n");
 	return ret;
 }
 
@@ -358,7 +358,7 @@
 	writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
 
 	for (retries = 3; retries > 0; retries--) {
-		ret = ulpi_write(&motg->otg, ULPI_FUNC_CTRL_SUSPENDM,
+		ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM,
 				ULPI_CLR(ULPI_FUNC_CTRL));
 		if (!ret)
 			break;
@@ -375,7 +375,7 @@
 		return ret;
 
 	for (retries = 3; retries > 0; retries--) {
-		ret = ulpi_read(&motg->otg, ULPI_DEBUG);
+		ret = ulpi_read(&motg->phy, ULPI_DEBUG);
 		if (ret != -ETIMEDOUT)
 			break;
 		ret = msm_otg_phy_clk_reset(motg);
@@ -385,14 +385,14 @@
 	if (!retries)
 		return -ETIMEDOUT;
 
-	dev_info(motg->otg.dev, "phy_reset: success\n");
+	dev_info(motg->phy.dev, "phy_reset: success\n");
 	return 0;
 }
 
 #define LINK_RESET_TIMEOUT_USEC		(250 * 1000)
-static int msm_otg_reset(struct otg_transceiver *otg)
+static int msm_otg_reset(struct usb_phy *phy)
 {
-	struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
 	struct msm_otg_platform_data *pdata = motg->pdata;
 	int cnt = 0;
 	int ret;
@@ -401,7 +401,7 @@
 
 	ret = msm_otg_phy_reset(motg);
 	if (ret) {
-		dev_err(otg->dev, "phy_reset failed\n");
+		dev_err(phy->dev, "phy_reset failed\n");
 		return ret;
 	}
 
@@ -435,8 +435,8 @@
 			val |= OTGSC_BSVIE;
 		}
 		writel(val, USB_OTGSC);
-		ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_RISE);
-		ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_FALL);
+		ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
+		ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
 	}
 
 	return 0;
@@ -448,8 +448,8 @@
 #ifdef CONFIG_PM_SLEEP
 static int msm_otg_suspend(struct msm_otg *motg)
 {
-	struct otg_transceiver *otg = &motg->otg;
-	struct usb_bus *bus = otg->host;
+	struct usb_phy *phy = &motg->phy;
+	struct usb_bus *bus = phy->otg->host;
 	struct msm_otg_platform_data *pdata = motg->pdata;
 	int cnt = 0;
 
@@ -475,10 +475,10 @@
 	 */
 
 	if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
-		ulpi_read(otg, 0x14);
+		ulpi_read(phy, 0x14);
 		if (pdata->otg_control == OTG_PHY_CONTROL)
-			ulpi_write(otg, 0x01, 0x30);
-		ulpi_write(otg, 0x08, 0x09);
+			ulpi_write(phy, 0x01, 0x30);
+		ulpi_write(phy, 0x08, 0x09);
 	}
 
 	/*
@@ -495,8 +495,8 @@
 	}
 
 	if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
-		dev_err(otg->dev, "Unable to suspend PHY\n");
-		msm_otg_reset(otg);
+		dev_err(phy->dev, "Unable to suspend PHY\n");
+		msm_otg_reset(phy);
 		enable_irq(motg->irq);
 		return -ETIMEDOUT;
 	}
@@ -528,7 +528,7 @@
 		msm_hsusb_config_vddcx(0);
 	}
 
-	if (device_may_wakeup(otg->dev))
+	if (device_may_wakeup(phy->dev))
 		enable_irq_wake(motg->irq);
 	if (bus)
 		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
@@ -536,15 +536,15 @@
 	atomic_set(&motg->in_lpm, 1);
 	enable_irq(motg->irq);
 
-	dev_info(otg->dev, "USB in low power mode\n");
+	dev_info(phy->dev, "USB in low power mode\n");
 
 	return 0;
 }
 
 static int msm_otg_resume(struct msm_otg *motg)
 {
-	struct otg_transceiver *otg = &motg->otg;
-	struct usb_bus *bus = otg->host;
+	struct usb_phy *phy = &motg->phy;
+	struct usb_bus *bus = phy->otg->host;
 	int cnt = 0;
 	unsigned temp;
 
@@ -592,13 +592,13 @@
 		 * PHY. USB state can not be restored. Re-insertion
 		 * of USB cable is the only way to get USB working.
 		 */
-		dev_err(otg->dev, "Unable to resume USB."
+		dev_err(phy->dev, "Unable to resume USB."
 				"Re-plugin the cable\n");
-		msm_otg_reset(otg);
+		msm_otg_reset(phy);
 	}
 
 skip_phy_resume:
-	if (device_may_wakeup(otg->dev))
+	if (device_may_wakeup(phy->dev))
 		disable_irq_wake(motg->irq);
 	if (bus)
 		set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
@@ -607,11 +607,11 @@
 
 	if (motg->async_int) {
 		motg->async_int = 0;
-		pm_runtime_put(otg->dev);
+		pm_runtime_put(phy->dev);
 		enable_irq(motg->irq);
 	}
 
-	dev_info(otg->dev, "USB exited from low power mode\n");
+	dev_info(phy->dev, "USB exited from low power mode\n");
 
 	return 0;
 }
@@ -623,13 +623,13 @@
 		return;
 
 	/* TODO: Notify PMIC about available current */
-	dev_info(motg->otg.dev, "Avail curr from USB = %u\n", mA);
+	dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
 	motg->cur_power = mA;
 }
 
-static int msm_otg_set_power(struct otg_transceiver *otg, unsigned mA)
+static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
 {
-	struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
 
 	/*
 	 * Gadget driver uses set_power method to notify about the
@@ -644,19 +644,19 @@
 	return 0;
 }
 
-static void msm_otg_start_host(struct otg_transceiver *otg, int on)
+static void msm_otg_start_host(struct usb_phy *phy, int on)
 {
-	struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
 	struct msm_otg_platform_data *pdata = motg->pdata;
 	struct usb_hcd *hcd;
 
-	if (!otg->host)
+	if (!phy->otg->host)
 		return;
 
-	hcd = bus_to_hcd(otg->host);
+	hcd = bus_to_hcd(phy->otg->host);
 
 	if (on) {
-		dev_dbg(otg->dev, "host on\n");
+		dev_dbg(phy->dev, "host on\n");
 
 		if (pdata->vbus_power)
 			pdata->vbus_power(1);
@@ -671,7 +671,7 @@
 		usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
 #endif
 	} else {
-		dev_dbg(otg->dev, "host off\n");
+		dev_dbg(phy->dev, "host off\n");
 
 #ifdef CONFIG_USB
 		usb_remove_hcd(hcd);
@@ -683,9 +683,9 @@
 	}
 }
 
-static int msm_otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
+static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
 {
-	struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+	struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
 	struct usb_hcd *hcd;
 
 	/*
@@ -693,16 +693,16 @@
 	 * only peripheral configuration.
 	 */
 	if (motg->pdata->mode == USB_PERIPHERAL) {
-		dev_info(otg->dev, "Host mode is not supported\n");
+		dev_info(otg->phy->dev, "Host mode is not supported\n");
 		return -ENODEV;
 	}
 
 	if (!host) {
-		if (otg->state == OTG_STATE_A_HOST) {
-			pm_runtime_get_sync(otg->dev);
-			msm_otg_start_host(otg, 0);
+		if (otg->phy->state == OTG_STATE_A_HOST) {
+			pm_runtime_get_sync(otg->phy->dev);
+			msm_otg_start_host(otg->phy, 0);
 			otg->host = NULL;
-			otg->state = OTG_STATE_UNDEFINED;
+			otg->phy->state = OTG_STATE_UNDEFINED;
 			schedule_work(&motg->sm_work);
 		} else {
 			otg->host = NULL;
@@ -715,30 +715,30 @@
 	hcd->power_budget = motg->pdata->power_budget;
 
 	otg->host = host;
-	dev_dbg(otg->dev, "host driver registered w/ tranceiver\n");
+	dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n");
 
 	/*
 	 * Kick the state machine work, if peripheral is not supported
 	 * or peripheral is already registered with us.
 	 */
 	if (motg->pdata->mode == USB_HOST || otg->gadget) {
-		pm_runtime_get_sync(otg->dev);
+		pm_runtime_get_sync(otg->phy->dev);
 		schedule_work(&motg->sm_work);
 	}
 
 	return 0;
 }
 
-static void msm_otg_start_peripheral(struct otg_transceiver *otg, int on)
+static void msm_otg_start_peripheral(struct usb_phy *phy, int on)
 {
-	struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
 	struct msm_otg_platform_data *pdata = motg->pdata;
 
-	if (!otg->gadget)
+	if (!phy->otg->gadget)
 		return;
 
 	if (on) {
-		dev_dbg(otg->dev, "gadget on\n");
+		dev_dbg(phy->dev, "gadget on\n");
 		/*
 		 * Some boards have a switch cotrolled by gpio
 		 * to enable/disable internal HUB. Disable internal
@@ -746,36 +746,36 @@
 		 */
 		if (pdata->setup_gpio)
 			pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
-		usb_gadget_vbus_connect(otg->gadget);
+		usb_gadget_vbus_connect(phy->otg->gadget);
 	} else {
-		dev_dbg(otg->dev, "gadget off\n");
-		usb_gadget_vbus_disconnect(otg->gadget);
+		dev_dbg(phy->dev, "gadget off\n");
+		usb_gadget_vbus_disconnect(phy->otg->gadget);
 		if (pdata->setup_gpio)
 			pdata->setup_gpio(OTG_STATE_UNDEFINED);
 	}
 
 }
 
-static int msm_otg_set_peripheral(struct otg_transceiver *otg,
-			struct usb_gadget *gadget)
+static int msm_otg_set_peripheral(struct usb_otg *otg,
+					struct usb_gadget *gadget)
 {
-	struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+	struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
 
 	/*
 	 * Fail peripheral registration if this board can support
 	 * only host configuration.
 	 */
 	if (motg->pdata->mode == USB_HOST) {
-		dev_info(otg->dev, "Peripheral mode is not supported\n");
+		dev_info(otg->phy->dev, "Peripheral mode is not supported\n");
 		return -ENODEV;
 	}
 
 	if (!gadget) {
-		if (otg->state == OTG_STATE_B_PERIPHERAL) {
-			pm_runtime_get_sync(otg->dev);
-			msm_otg_start_peripheral(otg, 0);
+		if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
+			pm_runtime_get_sync(otg->phy->dev);
+			msm_otg_start_peripheral(otg->phy, 0);
 			otg->gadget = NULL;
-			otg->state = OTG_STATE_UNDEFINED;
+			otg->phy->state = OTG_STATE_UNDEFINED;
 			schedule_work(&motg->sm_work);
 		} else {
 			otg->gadget = NULL;
@@ -784,14 +784,14 @@
 		return 0;
 	}
 	otg->gadget = gadget;
-	dev_dbg(otg->dev, "peripheral driver registered w/ tranceiver\n");
+	dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n");
 
 	/*
 	 * Kick the state machine work, if host is not supported
 	 * or host is already registered with us.
 	 */
 	if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
-		pm_runtime_get_sync(otg->dev);
+		pm_runtime_get_sync(otg->phy->dev);
 		schedule_work(&motg->sm_work);
 	}
 
@@ -800,17 +800,17 @@
 
 static bool msm_chg_check_secondary_det(struct msm_otg *motg)
 {
-	struct otg_transceiver *otg = &motg->otg;
+	struct usb_phy *phy = &motg->phy;
 	u32 chg_det;
 	bool ret = false;
 
 	switch (motg->pdata->phy_type) {
 	case CI_45NM_INTEGRATED_PHY:
-		chg_det = ulpi_read(otg, 0x34);
+		chg_det = ulpi_read(phy, 0x34);
 		ret = chg_det & (1 << 4);
 		break;
 	case SNPS_28NM_INTEGRATED_PHY:
-		chg_det = ulpi_read(otg, 0x87);
+		chg_det = ulpi_read(phy, 0x87);
 		ret = chg_det & 1;
 		break;
 	default:
@@ -821,38 +821,38 @@
 
 static void msm_chg_enable_secondary_det(struct msm_otg *motg)
 {
-	struct otg_transceiver *otg = &motg->otg;
+	struct usb_phy *phy = &motg->phy;
 	u32 chg_det;
 
 	switch (motg->pdata->phy_type) {
 	case CI_45NM_INTEGRATED_PHY:
-		chg_det = ulpi_read(otg, 0x34);
+		chg_det = ulpi_read(phy, 0x34);
 		/* Turn off charger block */
 		chg_det |= ~(1 << 1);
-		ulpi_write(otg, chg_det, 0x34);
+		ulpi_write(phy, chg_det, 0x34);
 		udelay(20);
 		/* control chg block via ULPI */
 		chg_det &= ~(1 << 3);
-		ulpi_write(otg, chg_det, 0x34);
+		ulpi_write(phy, chg_det, 0x34);
 		/* put it in host mode for enabling D- source */
 		chg_det &= ~(1 << 2);
-		ulpi_write(otg, chg_det, 0x34);
+		ulpi_write(phy, chg_det, 0x34);
 		/* Turn on chg detect block */
 		chg_det &= ~(1 << 1);
-		ulpi_write(otg, chg_det, 0x34);
+		ulpi_write(phy, chg_det, 0x34);
 		udelay(20);
 		/* enable chg detection */
 		chg_det &= ~(1 << 0);
-		ulpi_write(otg, chg_det, 0x34);
+		ulpi_write(phy, chg_det, 0x34);
 		break;
 	case SNPS_28NM_INTEGRATED_PHY:
 		/*
 		 * Configure DM as current source, DP as current sink
 		 * and enable battery charging comparators.
 		 */
-		ulpi_write(otg, 0x8, 0x85);
-		ulpi_write(otg, 0x2, 0x85);
-		ulpi_write(otg, 0x1, 0x85);
+		ulpi_write(phy, 0x8, 0x85);
+		ulpi_write(phy, 0x2, 0x85);
+		ulpi_write(phy, 0x1, 0x85);
 		break;
 	default:
 		break;
@@ -861,17 +861,17 @@
 
 static bool msm_chg_check_primary_det(struct msm_otg *motg)
 {
-	struct otg_transceiver *otg = &motg->otg;
+	struct usb_phy *phy = &motg->phy;
 	u32 chg_det;
 	bool ret = false;
 
 	switch (motg->pdata->phy_type) {
 	case CI_45NM_INTEGRATED_PHY:
-		chg_det = ulpi_read(otg, 0x34);
+		chg_det = ulpi_read(phy, 0x34);
 		ret = chg_det & (1 << 4);
 		break;
 	case SNPS_28NM_INTEGRATED_PHY:
-		chg_det = ulpi_read(otg, 0x87);
+		chg_det = ulpi_read(phy, 0x87);
 		ret = chg_det & 1;
 		break;
 	default:
@@ -882,23 +882,23 @@
 
 static void msm_chg_enable_primary_det(struct msm_otg *motg)
 {
-	struct otg_transceiver *otg = &motg->otg;
+	struct usb_phy *phy = &motg->phy;
 	u32 chg_det;
 
 	switch (motg->pdata->phy_type) {
 	case CI_45NM_INTEGRATED_PHY:
-		chg_det = ulpi_read(otg, 0x34);
+		chg_det = ulpi_read(phy, 0x34);
 		/* enable chg detection */
 		chg_det &= ~(1 << 0);
-		ulpi_write(otg, chg_det, 0x34);
+		ulpi_write(phy, chg_det, 0x34);
 		break;
 	case SNPS_28NM_INTEGRATED_PHY:
 		/*
 		 * Configure DP as current source, DM as current sink
 		 * and enable battery charging comparators.
 		 */
-		ulpi_write(otg, 0x2, 0x85);
-		ulpi_write(otg, 0x1, 0x85);
+		ulpi_write(phy, 0x2, 0x85);
+		ulpi_write(phy, 0x1, 0x85);
 		break;
 	default:
 		break;
@@ -907,17 +907,17 @@
 
 static bool msm_chg_check_dcd(struct msm_otg *motg)
 {
-	struct otg_transceiver *otg = &motg->otg;
+	struct usb_phy *phy = &motg->phy;
 	u32 line_state;
 	bool ret = false;
 
 	switch (motg->pdata->phy_type) {
 	case CI_45NM_INTEGRATED_PHY:
-		line_state = ulpi_read(otg, 0x15);
+		line_state = ulpi_read(phy, 0x15);
 		ret = !(line_state & 1);
 		break;
 	case SNPS_28NM_INTEGRATED_PHY:
-		line_state = ulpi_read(otg, 0x87);
+		line_state = ulpi_read(phy, 0x87);
 		ret = line_state & 2;
 		break;
 	default:
@@ -928,17 +928,17 @@
 
 static void msm_chg_disable_dcd(struct msm_otg *motg)
 {
-	struct otg_transceiver *otg = &motg->otg;
+	struct usb_phy *phy = &motg->phy;
 	u32 chg_det;
 
 	switch (motg->pdata->phy_type) {
 	case CI_45NM_INTEGRATED_PHY:
-		chg_det = ulpi_read(otg, 0x34);
+		chg_det = ulpi_read(phy, 0x34);
 		chg_det &= ~(1 << 5);
-		ulpi_write(otg, chg_det, 0x34);
+		ulpi_write(phy, chg_det, 0x34);
 		break;
 	case SNPS_28NM_INTEGRATED_PHY:
-		ulpi_write(otg, 0x10, 0x86);
+		ulpi_write(phy, 0x10, 0x86);
 		break;
 	default:
 		break;
@@ -947,19 +947,19 @@
 
 static void msm_chg_enable_dcd(struct msm_otg *motg)
 {
-	struct otg_transceiver *otg = &motg->otg;
+	struct usb_phy *phy = &motg->phy;
 	u32 chg_det;
 
 	switch (motg->pdata->phy_type) {
 	case CI_45NM_INTEGRATED_PHY:
-		chg_det = ulpi_read(otg, 0x34);
+		chg_det = ulpi_read(phy, 0x34);
 		/* Turn on D+ current source */
 		chg_det |= (1 << 5);
-		ulpi_write(otg, chg_det, 0x34);
+		ulpi_write(phy, chg_det, 0x34);
 		break;
 	case SNPS_28NM_INTEGRATED_PHY:
 		/* Data contact detection enable */
-		ulpi_write(otg, 0x10, 0x85);
+		ulpi_write(phy, 0x10, 0x85);
 		break;
 	default:
 		break;
@@ -968,32 +968,32 @@
 
 static void msm_chg_block_on(struct msm_otg *motg)
 {
-	struct otg_transceiver *otg = &motg->otg;
+	struct usb_phy *phy = &motg->phy;
 	u32 func_ctrl, chg_det;
 
 	/* put the controller in non-driving mode */
-	func_ctrl = ulpi_read(otg, ULPI_FUNC_CTRL);
+	func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
 	func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
 	func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
-	ulpi_write(otg, func_ctrl, ULPI_FUNC_CTRL);
+	ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
 
 	switch (motg->pdata->phy_type) {
 	case CI_45NM_INTEGRATED_PHY:
-		chg_det = ulpi_read(otg, 0x34);
+		chg_det = ulpi_read(phy, 0x34);
 		/* control chg block via ULPI */
 		chg_det &= ~(1 << 3);
-		ulpi_write(otg, chg_det, 0x34);
+		ulpi_write(phy, chg_det, 0x34);
 		/* Turn on chg detect block */
 		chg_det &= ~(1 << 1);
-		ulpi_write(otg, chg_det, 0x34);
+		ulpi_write(phy, chg_det, 0x34);
 		udelay(20);
 		break;
 	case SNPS_28NM_INTEGRATED_PHY:
 		/* Clear charger detecting control bits */
-		ulpi_write(otg, 0x3F, 0x86);
+		ulpi_write(phy, 0x3F, 0x86);
 		/* Clear alt interrupt latch and enable bits */
-		ulpi_write(otg, 0x1F, 0x92);
-		ulpi_write(otg, 0x1F, 0x95);
+		ulpi_write(phy, 0x1F, 0x92);
+		ulpi_write(phy, 0x1F, 0x95);
 		udelay(100);
 		break;
 	default:
@@ -1003,32 +1003,32 @@
 
 static void msm_chg_block_off(struct msm_otg *motg)
 {
-	struct otg_transceiver *otg = &motg->otg;
+	struct usb_phy *phy = &motg->phy;
 	u32 func_ctrl, chg_det;
 
 	switch (motg->pdata->phy_type) {
 	case CI_45NM_INTEGRATED_PHY:
-		chg_det = ulpi_read(otg, 0x34);
+		chg_det = ulpi_read(phy, 0x34);
 		/* Turn off charger block */
 		chg_det |= ~(1 << 1);
-		ulpi_write(otg, chg_det, 0x34);
+		ulpi_write(phy, chg_det, 0x34);
 		break;
 	case SNPS_28NM_INTEGRATED_PHY:
 		/* Clear charger detecting control bits */
-		ulpi_write(otg, 0x3F, 0x86);
+		ulpi_write(phy, 0x3F, 0x86);
 		/* Clear alt interrupt latch and enable bits */
-		ulpi_write(otg, 0x1F, 0x92);
-		ulpi_write(otg, 0x1F, 0x95);
+		ulpi_write(phy, 0x1F, 0x92);
+		ulpi_write(phy, 0x1F, 0x95);
 		break;
 	default:
 		break;
 	}
 
 	/* put the controller in normal mode */
-	func_ctrl = ulpi_read(otg, ULPI_FUNC_CTRL);
+	func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
 	func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
 	func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
-	ulpi_write(otg, func_ctrl, ULPI_FUNC_CTRL);
+	ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
 }
 
 #define MSM_CHG_DCD_POLL_TIME		(100 * HZ/1000) /* 100 msec */
@@ -1038,14 +1038,14 @@
 static void msm_chg_detect_work(struct work_struct *w)
 {
 	struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
-	struct otg_transceiver *otg = &motg->otg;
+	struct usb_phy *phy = &motg->phy;
 	bool is_dcd, tmout, vout;
 	unsigned long delay;
 
-	dev_dbg(otg->dev, "chg detection work\n");
+	dev_dbg(phy->dev, "chg detection work\n");
 	switch (motg->chg_state) {
 	case USB_CHG_STATE_UNDEFINED:
-		pm_runtime_get_sync(otg->dev);
+		pm_runtime_get_sync(phy->dev);
 		msm_chg_block_on(motg);
 		msm_chg_enable_dcd(motg);
 		motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
@@ -1088,7 +1088,7 @@
 		motg->chg_state = USB_CHG_STATE_DETECTED;
 	case USB_CHG_STATE_DETECTED:
 		msm_chg_block_off(motg);
-		dev_dbg(otg->dev, "charger = %d\n", motg->chg_type);
+		dev_dbg(phy->dev, "charger = %d\n", motg->chg_type);
 		schedule_work(&motg->sm_work);
 		return;
 	default:
@@ -1152,22 +1152,22 @@
 static void msm_otg_sm_work(struct work_struct *w)
 {
 	struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
-	struct otg_transceiver *otg = &motg->otg;
+	struct usb_otg *otg = motg->phy.otg;
 
-	switch (otg->state) {
+	switch (otg->phy->state) {
 	case OTG_STATE_UNDEFINED:
-		dev_dbg(otg->dev, "OTG_STATE_UNDEFINED state\n");
-		msm_otg_reset(otg);
+		dev_dbg(otg->phy->dev, "OTG_STATE_UNDEFINED state\n");
+		msm_otg_reset(otg->phy);
 		msm_otg_init_sm(motg);
-		otg->state = OTG_STATE_B_IDLE;
+		otg->phy->state = OTG_STATE_B_IDLE;
 		/* FALL THROUGH */
 	case OTG_STATE_B_IDLE:
-		dev_dbg(otg->dev, "OTG_STATE_B_IDLE state\n");
+		dev_dbg(otg->phy->dev, "OTG_STATE_B_IDLE state\n");
 		if (!test_bit(ID, &motg->inputs) && otg->host) {
 			/* disable BSV bit */
 			writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC);
-			msm_otg_start_host(otg, 1);
-			otg->state = OTG_STATE_A_HOST;
+			msm_otg_start_host(otg->phy, 1);
+			otg->phy->state = OTG_STATE_A_HOST;
 		} else if (test_bit(B_SESS_VLD, &motg->inputs)) {
 			switch (motg->chg_state) {
 			case USB_CHG_STATE_UNDEFINED:
@@ -1182,13 +1182,15 @@
 				case USB_CDP_CHARGER:
 					msm_otg_notify_charger(motg,
 							IDEV_CHG_MAX);
-					msm_otg_start_peripheral(otg, 1);
-					otg->state = OTG_STATE_B_PERIPHERAL;
+					msm_otg_start_peripheral(otg->phy, 1);
+					otg->phy->state
+						= OTG_STATE_B_PERIPHERAL;
 					break;
 				case USB_SDP_CHARGER:
 					msm_otg_notify_charger(motg, IUNIT);
-					msm_otg_start_peripheral(otg, 1);
-					otg->state = OTG_STATE_B_PERIPHERAL;
+					msm_otg_start_peripheral(otg->phy, 1);
+					otg->phy->state
+						= OTG_STATE_B_PERIPHERAL;
 					break;
 				default:
 					break;
@@ -1204,34 +1206,34 @@
 			 * is incremented in charger detection work.
 			 */
 			if (cancel_delayed_work_sync(&motg->chg_work)) {
-				pm_runtime_put_sync(otg->dev);
-				msm_otg_reset(otg);
+				pm_runtime_put_sync(otg->phy->dev);
+				msm_otg_reset(otg->phy);
 			}
 			msm_otg_notify_charger(motg, 0);
 			motg->chg_state = USB_CHG_STATE_UNDEFINED;
 			motg->chg_type = USB_INVALID_CHARGER;
 		}
-		pm_runtime_put_sync(otg->dev);
+		pm_runtime_put_sync(otg->phy->dev);
 		break;
 	case OTG_STATE_B_PERIPHERAL:
-		dev_dbg(otg->dev, "OTG_STATE_B_PERIPHERAL state\n");
+		dev_dbg(otg->phy->dev, "OTG_STATE_B_PERIPHERAL state\n");
 		if (!test_bit(B_SESS_VLD, &motg->inputs) ||
 				!test_bit(ID, &motg->inputs)) {
 			msm_otg_notify_charger(motg, 0);
-			msm_otg_start_peripheral(otg, 0);
+			msm_otg_start_peripheral(otg->phy, 0);
 			motg->chg_state = USB_CHG_STATE_UNDEFINED;
 			motg->chg_type = USB_INVALID_CHARGER;
-			otg->state = OTG_STATE_B_IDLE;
-			msm_otg_reset(otg);
+			otg->phy->state = OTG_STATE_B_IDLE;
+			msm_otg_reset(otg->phy);
 			schedule_work(w);
 		}
 		break;
 	case OTG_STATE_A_HOST:
-		dev_dbg(otg->dev, "OTG_STATE_A_HOST state\n");
+		dev_dbg(otg->phy->dev, "OTG_STATE_A_HOST state\n");
 		if (test_bit(ID, &motg->inputs)) {
-			msm_otg_start_host(otg, 0);
-			otg->state = OTG_STATE_B_IDLE;
-			msm_otg_reset(otg);
+			msm_otg_start_host(otg->phy, 0);
+			otg->phy->state = OTG_STATE_B_IDLE;
+			msm_otg_reset(otg->phy);
 			schedule_work(w);
 		}
 		break;
@@ -1243,13 +1245,13 @@
 static irqreturn_t msm_otg_irq(int irq, void *data)
 {
 	struct msm_otg *motg = data;
-	struct otg_transceiver *otg = &motg->otg;
+	struct usb_phy *phy = &motg->phy;
 	u32 otgsc = 0;
 
 	if (atomic_read(&motg->in_lpm)) {
 		disable_irq_nosync(irq);
 		motg->async_int = 1;
-		pm_runtime_get(otg->dev);
+		pm_runtime_get(phy->dev);
 		return IRQ_HANDLED;
 	}
 
@@ -1262,15 +1264,15 @@
 			set_bit(ID, &motg->inputs);
 		else
 			clear_bit(ID, &motg->inputs);
-		dev_dbg(otg->dev, "ID set/clear\n");
-		pm_runtime_get_noresume(otg->dev);
+		dev_dbg(phy->dev, "ID set/clear\n");
+		pm_runtime_get_noresume(phy->dev);
 	} else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) {
 		if (otgsc & OTGSC_BSV)
 			set_bit(B_SESS_VLD, &motg->inputs);
 		else
 			clear_bit(B_SESS_VLD, &motg->inputs);
-		dev_dbg(otg->dev, "BSV set/clear\n");
-		pm_runtime_get_noresume(otg->dev);
+		dev_dbg(phy->dev, "BSV set/clear\n");
+		pm_runtime_get_noresume(phy->dev);
 	}
 
 	writel(otgsc, USB_OTGSC);
@@ -1281,9 +1283,9 @@
 static int msm_otg_mode_show(struct seq_file *s, void *unused)
 {
 	struct msm_otg *motg = s->private;
-	struct otg_transceiver *otg = &motg->otg;
+	struct usb_otg *otg = motg->phy.otg;
 
-	switch (otg->state) {
+	switch (otg->phy->state) {
 	case OTG_STATE_A_HOST:
 		seq_printf(s, "host\n");
 		break;
@@ -1309,7 +1311,7 @@
 	struct seq_file *s = file->private_data;
 	struct msm_otg *motg = s->private;
 	char buf[16];
-	struct otg_transceiver *otg = &motg->otg;
+	struct usb_otg *otg = motg->phy.otg;
 	int status = count;
 	enum usb_mode_type req_mode;
 
@@ -1333,7 +1335,7 @@
 
 	switch (req_mode) {
 	case USB_NONE:
-		switch (otg->state) {
+		switch (otg->phy->state) {
 		case OTG_STATE_A_HOST:
 		case OTG_STATE_B_PERIPHERAL:
 			set_bit(ID, &motg->inputs);
@@ -1344,7 +1346,7 @@
 		}
 		break;
 	case USB_PERIPHERAL:
-		switch (otg->state) {
+		switch (otg->phy->state) {
 		case OTG_STATE_B_IDLE:
 		case OTG_STATE_A_HOST:
 			set_bit(ID, &motg->inputs);
@@ -1355,7 +1357,7 @@
 		}
 		break;
 	case USB_HOST:
-		switch (otg->state) {
+		switch (otg->phy->state) {
 		case OTG_STATE_B_IDLE:
 		case OTG_STATE_B_PERIPHERAL:
 			clear_bit(ID, &motg->inputs);
@@ -1368,7 +1370,7 @@
 		goto out;
 	}
 
-	pm_runtime_get_sync(otg->dev);
+	pm_runtime_get_sync(otg->phy->dev);
 	schedule_work(&motg->sm_work);
 out:
 	return status;
@@ -1414,7 +1416,7 @@
 	int ret = 0;
 	struct resource *res;
 	struct msm_otg *motg;
-	struct otg_transceiver *otg;
+	struct usb_phy *phy;
 
 	dev_info(&pdev->dev, "msm_otg probe\n");
 	if (!pdev->dev.platform_data) {
@@ -1428,9 +1430,15 @@
 		return -ENOMEM;
 	}
 
+	motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
+	if (!motg->phy.otg) {
+		dev_err(&pdev->dev, "unable to allocate msm_otg\n");
+		return -ENOMEM;
+	}
+
 	motg->pdata = pdev->dev.platform_data;
-	otg = &motg->otg;
-	otg->dev = &pdev->dev;
+	phy = &motg->phy;
+	phy->dev = &pdev->dev;
 
 	motg->phy_reset_clk = clk_get(&pdev->dev, "usb_phy_clk");
 	if (IS_ERR(motg->phy_reset_clk)) {
@@ -1538,16 +1546,18 @@
 		goto disable_clks;
 	}
 
-	otg->init = msm_otg_reset;
-	otg->set_host = msm_otg_set_host;
-	otg->set_peripheral = msm_otg_set_peripheral;
-	otg->set_power = msm_otg_set_power;
+	phy->init = msm_otg_reset;
+	phy->set_power = msm_otg_set_power;
 
-	otg->io_ops = &msm_otg_io_ops;
+	phy->io_ops = &msm_otg_io_ops;
 
-	ret = otg_set_transceiver(&motg->otg);
+	phy->otg->phy = &motg->phy;
+	phy->otg->set_host = msm_otg_set_host;
+	phy->otg->set_peripheral = msm_otg_set_peripheral;
+
+	ret = usb_set_transceiver(&motg->phy);
 	if (ret) {
-		dev_err(&pdev->dev, "otg_set_transceiver failed\n");
+		dev_err(&pdev->dev, "usb_set_transceiver failed\n");
 		goto free_irq;
 	}
 
@@ -1591,6 +1601,7 @@
 put_phy_reset_clk:
 	clk_put(motg->phy_reset_clk);
 free_motg:
+	kfree(motg->phy.otg);
 	kfree(motg);
 	return ret;
 }
@@ -1598,10 +1609,10 @@
 static int __devexit msm_otg_remove(struct platform_device *pdev)
 {
 	struct msm_otg *motg = platform_get_drvdata(pdev);
-	struct otg_transceiver *otg = &motg->otg;
+	struct usb_phy *phy = &motg->phy;
 	int cnt = 0;
 
-	if (otg->host || otg->gadget)
+	if (phy->otg->host || phy->otg->gadget)
 		return -EBUSY;
 
 	msm_otg_debugfs_cleanup();
@@ -1613,14 +1624,14 @@
 	device_init_wakeup(&pdev->dev, 0);
 	pm_runtime_disable(&pdev->dev);
 
-	otg_set_transceiver(NULL);
+	usb_set_transceiver(NULL);
 	free_irq(motg->irq, motg);
 
 	/*
 	 * Put PHY in low power mode.
 	 */
-	ulpi_read(otg, 0x14);
-	ulpi_write(otg, 0x08, 0x09);
+	ulpi_read(phy, 0x14);
+	ulpi_write(phy, 0x08, 0x09);
 
 	writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
 	while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
@@ -1630,7 +1641,7 @@
 		cnt++;
 	}
 	if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
-		dev_err(otg->dev, "Unable to suspend PHY\n");
+		dev_err(phy->dev, "Unable to suspend PHY\n");
 
 	clk_disable(motg->pclk);
 	clk_disable(motg->clk);
@@ -1651,6 +1662,7 @@
 	if (motg->core_clk)
 		clk_put(motg->core_clk);
 
+	kfree(motg->phy.otg);
 	kfree(motg);
 
 	return 0;
@@ -1660,7 +1672,7 @@
 static int msm_otg_runtime_idle(struct device *dev)
 {
 	struct msm_otg *motg = dev_get_drvdata(dev);
-	struct otg_transceiver *otg = &motg->otg;
+	struct usb_otg *otg = motg->phy.otg;
 
 	dev_dbg(dev, "OTG runtime idle\n");
 
@@ -1670,7 +1682,7 @@
 	 * This 1 sec delay also prevents entering into LPM immediately
 	 * after asynchronous interrupt.
 	 */
-	if (otg->state != OTG_STATE_UNDEFINED)
+	if (otg->phy->state != OTG_STATE_UNDEFINED)
 		pm_schedule_suspend(dev, 1000);
 
 	return -EAGAIN;
diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c
index b5fbe14..6cc6c3f 100644
--- a/drivers/usb/otg/mv_otg.c
+++ b/drivers/usb/otg/mv_otg.c
@@ -55,16 +55,16 @@
 	"a_vbus_err"
 };
 
-static int mv_otg_set_vbus(struct otg_transceiver *otg, bool on)
+static int mv_otg_set_vbus(struct usb_otg *otg, bool on)
 {
-	struct mv_otg *mvotg = container_of(otg, struct mv_otg, otg);
+	struct mv_otg *mvotg = container_of(otg->phy, struct mv_otg, phy);
 	if (mvotg->pdata->set_vbus == NULL)
 		return -ENODEV;
 
 	return mvotg->pdata->set_vbus(on);
 }
 
-static int mv_otg_set_host(struct otg_transceiver *otg,
+static int mv_otg_set_host(struct usb_otg *otg,
 			   struct usb_bus *host)
 {
 	otg->host = host;
@@ -72,7 +72,7 @@
 	return 0;
 }
 
-static int mv_otg_set_peripheral(struct otg_transceiver *otg,
+static int mv_otg_set_peripheral(struct usb_otg *otg,
 				 struct usb_gadget *gadget)
 {
 	otg->gadget = gadget;
@@ -203,7 +203,7 @@
 static void mv_otg_start_host(struct mv_otg *mvotg, int on)
 {
 #ifdef CONFIG_USB
-	struct otg_transceiver *otg = &mvotg->otg;
+	struct usb_otg *otg = mvotg->phy.otg;
 	struct usb_hcd *hcd;
 
 	if (!otg->host)
@@ -222,12 +222,12 @@
 
 static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on)
 {
-	struct otg_transceiver *otg = &mvotg->otg;
+	struct usb_otg *otg = mvotg->phy.otg;
 
 	if (!otg->gadget)
 		return;
 
-	dev_info(otg->dev, "gadget %s\n", on ? "on" : "off");
+	dev_info(mvotg->phy.dev, "gadget %s\n", on ? "on" : "off");
 
 	if (on)
 		usb_gadget_vbus_connect(otg->gadget);
@@ -343,69 +343,69 @@
 static void mv_otg_update_state(struct mv_otg *mvotg)
 {
 	struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl;
-	struct otg_transceiver *otg = &mvotg->otg;
-	int old_state = otg->state;
+	struct usb_phy *phy = &mvotg->phy;
+	int old_state = phy->state;
 
 	switch (old_state) {
 	case OTG_STATE_UNDEFINED:
-		otg->state = OTG_STATE_B_IDLE;
+		phy->state = OTG_STATE_B_IDLE;
 		/* FALL THROUGH */
 	case OTG_STATE_B_IDLE:
 		if (otg_ctrl->id == 0)
-			otg->state = OTG_STATE_A_IDLE;
+			phy->state = OTG_STATE_A_IDLE;
 		else if (otg_ctrl->b_sess_vld)
-			otg->state = OTG_STATE_B_PERIPHERAL;
+			phy->state = OTG_STATE_B_PERIPHERAL;
 		break;
 	case OTG_STATE_B_PERIPHERAL:
 		if (!otg_ctrl->b_sess_vld || otg_ctrl->id == 0)
-			otg->state = OTG_STATE_B_IDLE;
+			phy->state = OTG_STATE_B_IDLE;
 		break;
 	case OTG_STATE_A_IDLE:
 		if (otg_ctrl->id)
-			otg->state = OTG_STATE_B_IDLE;
+			phy->state = OTG_STATE_B_IDLE;
 		else if (!(otg_ctrl->a_bus_drop) &&
 			 (otg_ctrl->a_bus_req || otg_ctrl->a_srp_det))
-			otg->state = OTG_STATE_A_WAIT_VRISE;
+			phy->state = OTG_STATE_A_WAIT_VRISE;
 		break;
 	case OTG_STATE_A_WAIT_VRISE:
 		if (otg_ctrl->a_vbus_vld)
-			otg->state = OTG_STATE_A_WAIT_BCON;
+			phy->state = OTG_STATE_A_WAIT_BCON;
 		break;
 	case OTG_STATE_A_WAIT_BCON:
 		if (otg_ctrl->id || otg_ctrl->a_bus_drop
 		    || otg_ctrl->a_wait_bcon_timeout) {
 			mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
 			mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
-			otg->state = OTG_STATE_A_WAIT_VFALL;
+			phy->state = OTG_STATE_A_WAIT_VFALL;
 			otg_ctrl->a_bus_req = 0;
 		} else if (!otg_ctrl->a_vbus_vld) {
 			mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
 			mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
-			otg->state = OTG_STATE_A_VBUS_ERR;
+			phy->state = OTG_STATE_A_VBUS_ERR;
 		} else if (otg_ctrl->b_conn) {
 			mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
 			mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
-			otg->state = OTG_STATE_A_HOST;
+			phy->state = OTG_STATE_A_HOST;
 		}
 		break;
 	case OTG_STATE_A_HOST:
 		if (otg_ctrl->id || !otg_ctrl->b_conn
 		    || otg_ctrl->a_bus_drop)
-			otg->state = OTG_STATE_A_WAIT_BCON;
+			phy->state = OTG_STATE_A_WAIT_BCON;
 		else if (!otg_ctrl->a_vbus_vld)
-			otg->state = OTG_STATE_A_VBUS_ERR;
+			phy->state = OTG_STATE_A_VBUS_ERR;
 		break;
 	case OTG_STATE_A_WAIT_VFALL:
 		if (otg_ctrl->id
 		    || (!otg_ctrl->b_conn && otg_ctrl->a_sess_vld)
 		    || otg_ctrl->a_bus_req)
-			otg->state = OTG_STATE_A_IDLE;
+			phy->state = OTG_STATE_A_IDLE;
 		break;
 	case OTG_STATE_A_VBUS_ERR:
 		if (otg_ctrl->id || otg_ctrl->a_clr_err
 		    || otg_ctrl->a_bus_drop) {
 			otg_ctrl->a_clr_err = 0;
-			otg->state = OTG_STATE_A_WAIT_VFALL;
+			phy->state = OTG_STATE_A_WAIT_VFALL;
 		}
 		break;
 	default:
@@ -416,15 +416,17 @@
 static void mv_otg_work(struct work_struct *work)
 {
 	struct mv_otg *mvotg;
-	struct otg_transceiver *otg;
+	struct usb_phy *phy;
+	struct usb_otg *otg;
 	int old_state;
 
 	mvotg = container_of((struct delayed_work *)work, struct mv_otg, work);
 
 run:
 	/* work queue is single thread, or we need spin_lock to protect */
-	otg = &mvotg->otg;
-	old_state = otg->state;
+	phy = &mvotg->phy;
+	otg = phy->otg;
+	old_state = phy->state;
 
 	if (!mvotg->active)
 		return;
@@ -432,14 +434,14 @@
 	mv_otg_update_inputs(mvotg);
 	mv_otg_update_state(mvotg);
 
-	if (old_state != otg->state) {
+	if (old_state != phy->state) {
 		dev_info(&mvotg->pdev->dev, "change from state %s to %s\n",
 			 state_string[old_state],
-			 state_string[otg->state]);
+			 state_string[phy->state]);
 
-		switch (otg->state) {
+		switch (phy->state) {
 		case OTG_STATE_B_IDLE:
-			mvotg->otg.default_a = 0;
+			otg->default_a = 0;
 			if (old_state == OTG_STATE_B_PERIPHERAL)
 				mv_otg_start_periphrals(mvotg, 0);
 			mv_otg_reset(mvotg);
@@ -450,14 +452,14 @@
 			mv_otg_start_periphrals(mvotg, 1);
 			break;
 		case OTG_STATE_A_IDLE:
-			mvotg->otg.default_a = 1;
+			otg->default_a = 1;
 			mv_otg_enable(mvotg);
 			if (old_state == OTG_STATE_A_WAIT_VFALL)
 				mv_otg_start_host(mvotg, 0);
 			mv_otg_reset(mvotg);
 			break;
 		case OTG_STATE_A_WAIT_VRISE:
-			mv_otg_set_vbus(&mvotg->otg, 1);
+			mv_otg_set_vbus(otg, 1);
 			break;
 		case OTG_STATE_A_WAIT_BCON:
 			if (old_state != OTG_STATE_A_HOST)
@@ -479,7 +481,7 @@
 			 * here. In fact, it need host driver to notify us.
 			 */
 			mvotg->otg_ctrl.b_conn = 0;
-			mv_otg_set_vbus(&mvotg->otg, 0);
+			mv_otg_set_vbus(otg, 0);
 			break;
 		case OTG_STATE_A_VBUS_ERR:
 			break;
@@ -548,8 +550,8 @@
 		return -1;
 
 	/* We will use this interface to change to A device */
-	if (mvotg->otg.state != OTG_STATE_B_IDLE
-	    && mvotg->otg.state != OTG_STATE_A_IDLE)
+	if (mvotg->phy.state != OTG_STATE_B_IDLE
+	    && mvotg->phy.state != OTG_STATE_A_IDLE)
 		return -1;
 
 	/* The clock may disabled and we need to set irq for ID detected */
@@ -579,7 +581,7 @@
 	      const char *buf, size_t count)
 {
 	struct mv_otg *mvotg = dev_get_drvdata(dev);
-	if (!mvotg->otg.default_a)
+	if (!mvotg->phy.otg->default_a)
 		return -1;
 
 	if (count > 2)
@@ -615,7 +617,7 @@
 	       const char *buf, size_t count)
 {
 	struct mv_otg *mvotg = dev_get_drvdata(dev);
-	if (!mvotg->otg.default_a)
+	if (!mvotg->phy.otg->default_a)
 		return -1;
 
 	if (count > 2)
@@ -688,9 +690,10 @@
 	for (clk_i = 0; clk_i <= mvotg->clknum; clk_i++)
 		clk_put(mvotg->clk[clk_i]);
 
-	otg_set_transceiver(NULL);
+	usb_set_transceiver(NULL);
 	platform_set_drvdata(pdev, NULL);
 
+	kfree(mvotg->phy.otg);
 	kfree(mvotg);
 
 	return 0;
@@ -700,6 +703,7 @@
 {
 	struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
 	struct mv_otg *mvotg;
+	struct usb_otg *otg;
 	struct resource *r;
 	int retval = 0, clk_i, i;
 	size_t size;
@@ -716,6 +720,12 @@
 		return -ENOMEM;
 	}
 
+	otg = kzalloc(sizeof *otg, GFP_KERNEL);
+	if (!otg) {
+		kfree(mvotg);
+		return -ENOMEM;
+	}
+
 	platform_set_drvdata(pdev, mvotg);
 
 	mvotg->pdev = pdev;
@@ -741,12 +751,15 @@
 
 	/* OTG common part */
 	mvotg->pdev = pdev;
-	mvotg->otg.dev = &pdev->dev;
-	mvotg->otg.label = driver_name;
-	mvotg->otg.set_host = mv_otg_set_host;
-	mvotg->otg.set_peripheral = mv_otg_set_peripheral;
-	mvotg->otg.set_vbus = mv_otg_set_vbus;
-	mvotg->otg.state = OTG_STATE_UNDEFINED;
+	mvotg->phy.dev = &pdev->dev;
+	mvotg->phy.otg = otg;
+	mvotg->phy.label = driver_name;
+	mvotg->phy.state = OTG_STATE_UNDEFINED;
+
+	otg->phy = &mvotg->phy;
+	otg->set_host = mv_otg_set_host;
+	otg->set_peripheral = mv_otg_set_peripheral;
+	otg->set_vbus = mv_otg_set_vbus;
 
 	for (i = 0; i < OTG_TIMER_NUM; i++)
 		init_timer(&mvotg->otg_ctrl.timer[i]);
@@ -840,7 +853,7 @@
 		goto err_disable_clk;
 	}
 
-	retval = otg_set_transceiver(&mvotg->otg);
+	retval = usb_set_transceiver(&mvotg->phy);
 	if (retval < 0) {
 		dev_err(&pdev->dev, "can't register transceiver, %d\n",
 			retval);
@@ -867,7 +880,7 @@
 	return 0;
 
 err_set_transceiver:
-	otg_set_transceiver(NULL);
+	usb_set_transceiver(NULL);
 err_free_irq:
 	free_irq(mvotg->irq, mvotg);
 err_disable_clk:
@@ -888,6 +901,7 @@
 		clk_put(mvotg->clk[clk_i]);
 
 	platform_set_drvdata(pdev, NULL);
+	kfree(otg);
 	kfree(mvotg);
 
 	return retval;
@@ -898,10 +912,10 @@
 {
 	struct mv_otg *mvotg = platform_get_drvdata(pdev);
 
-	if (mvotg->otg.state != OTG_STATE_B_IDLE) {
+	if (mvotg->phy.state != OTG_STATE_B_IDLE) {
 		dev_info(&pdev->dev,
 			 "OTG state is not B_IDLE, it is %d!\n",
-			 mvotg->otg.state);
+			 mvotg->phy.state);
 		return -EAGAIN;
 	}
 
diff --git a/drivers/usb/otg/mv_otg.h b/drivers/usb/otg/mv_otg.h
index be6ca14..8a9e351 100644
--- a/drivers/usb/otg/mv_otg.h
+++ b/drivers/usb/otg/mv_otg.h
@@ -136,7 +136,7 @@
 };
 
 struct mv_otg {
-	struct otg_transceiver otg;
+	struct usb_phy phy;
 	struct mv_otg_ctrl otg_ctrl;
 
 	/* base address */
diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c
index c1e3600..58b26df 100644
--- a/drivers/usb/otg/nop-usb-xceiv.c
+++ b/drivers/usb/otg/nop-usb-xceiv.c
@@ -33,7 +33,7 @@
 #include <linux/slab.h>
 
 struct nop_usb_xceiv {
-	struct otg_transceiver	otg;
+	struct usb_phy		phy;
 	struct device		*dev;
 };
 
@@ -58,51 +58,37 @@
 }
 EXPORT_SYMBOL(usb_nop_xceiv_unregister);
 
-static inline struct nop_usb_xceiv *xceiv_to_nop(struct otg_transceiver *x)
-{
-	return container_of(x, struct nop_usb_xceiv, otg);
-}
-
-static int nop_set_suspend(struct otg_transceiver *x, int suspend)
+static int nop_set_suspend(struct usb_phy *x, int suspend)
 {
 	return 0;
 }
 
-static int nop_set_peripheral(struct otg_transceiver *x,
-		struct usb_gadget *gadget)
+static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
 {
-	struct nop_usb_xceiv *nop;
-
-	if (!x)
+	if (!otg)
 		return -ENODEV;
 
-	nop = xceiv_to_nop(x);
-
 	if (!gadget) {
-		nop->otg.gadget = NULL;
+		otg->gadget = NULL;
 		return -ENODEV;
 	}
 
-	nop->otg.gadget = gadget;
-	nop->otg.state = OTG_STATE_B_IDLE;
+	otg->gadget = gadget;
+	otg->phy->state = OTG_STATE_B_IDLE;
 	return 0;
 }
 
-static int nop_set_host(struct otg_transceiver *x, struct usb_bus *host)
+static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
 {
-	struct nop_usb_xceiv *nop;
-
-	if (!x)
+	if (!otg)
 		return -ENODEV;
 
-	nop = xceiv_to_nop(x);
-
 	if (!host) {
-		nop->otg.host = NULL;
+		otg->host = NULL;
 		return -ENODEV;
 	}
 
-	nop->otg.host = host;
+	otg->host = host;
 	return 0;
 }
 
@@ -115,15 +101,23 @@
 	if (!nop)
 		return -ENOMEM;
 
-	nop->dev		= &pdev->dev;
-	nop->otg.dev		= nop->dev;
-	nop->otg.label		= "nop-xceiv";
-	nop->otg.state		= OTG_STATE_UNDEFINED;
-	nop->otg.set_host	= nop_set_host;
-	nop->otg.set_peripheral	= nop_set_peripheral;
-	nop->otg.set_suspend	= nop_set_suspend;
+	nop->phy.otg = kzalloc(sizeof *nop->phy.otg, GFP_KERNEL);
+	if (!nop->phy.otg) {
+		kfree(nop);
+		return -ENOMEM;
+	}
 
-	err = otg_set_transceiver(&nop->otg);
+	nop->dev		= &pdev->dev;
+	nop->phy.dev		= nop->dev;
+	nop->phy.label		= "nop-xceiv";
+	nop->phy.set_suspend	= nop_set_suspend;
+	nop->phy.state		= OTG_STATE_UNDEFINED;
+
+	nop->phy.otg->phy		= &nop->phy;
+	nop->phy.otg->set_host		= nop_set_host;
+	nop->phy.otg->set_peripheral	= nop_set_peripheral;
+
+	err = usb_set_transceiver(&nop->phy);
 	if (err) {
 		dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
 			err);
@@ -132,10 +126,11 @@
 
 	platform_set_drvdata(pdev, nop);
 
-	ATOMIC_INIT_NOTIFIER_HEAD(&nop->otg.notifier);
+	ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
 
 	return 0;
 exit:
+	kfree(nop->phy.otg);
 	kfree(nop);
 	return err;
 }
@@ -144,9 +139,10 @@
 {
 	struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
 
-	otg_set_transceiver(NULL);
+	usb_set_transceiver(NULL);
 
 	platform_set_drvdata(pdev, NULL);
+	kfree(nop->phy.otg);
 	kfree(nop);
 
 	return 0;
diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c
index 307c27b..801e597 100644
--- a/drivers/usb/otg/otg.c
+++ b/drivers/usb/otg/otg.c
@@ -15,56 +15,56 @@
 
 #include <linux/usb/otg.h>
 
-static struct otg_transceiver *xceiv;
+static struct usb_phy *phy;
 
 /**
- * otg_get_transceiver - find the (single) OTG transceiver
+ * usb_get_transceiver - find the (single) USB transceiver
  *
  * Returns the transceiver driver, after getting a refcount to it; or
  * null if there is no such transceiver.  The caller is responsible for
- * calling otg_put_transceiver() to release that count.
+ * calling usb_put_transceiver() to release that count.
  *
  * For use by USB host and peripheral drivers.
  */
-struct otg_transceiver *otg_get_transceiver(void)
+struct usb_phy *usb_get_transceiver(void)
 {
-	if (xceiv)
-		get_device(xceiv->dev);
-	return xceiv;
+	if (phy)
+		get_device(phy->dev);
+	return phy;
 }
-EXPORT_SYMBOL(otg_get_transceiver);
+EXPORT_SYMBOL(usb_get_transceiver);
 
 /**
- * otg_put_transceiver - release the (single) OTG transceiver
- * @x: the transceiver returned by otg_get_transceiver()
+ * usb_put_transceiver - release the (single) USB transceiver
+ * @x: the transceiver returned by usb_get_transceiver()
  *
- * Releases a refcount the caller received from otg_get_transceiver().
+ * Releases a refcount the caller received from usb_get_transceiver().
  *
  * For use by USB host and peripheral drivers.
  */
-void otg_put_transceiver(struct otg_transceiver *x)
+void usb_put_transceiver(struct usb_phy *x)
 {
 	if (x)
 		put_device(x->dev);
 }
-EXPORT_SYMBOL(otg_put_transceiver);
+EXPORT_SYMBOL(usb_put_transceiver);
 
 /**
- * otg_set_transceiver - declare the (single) OTG transceiver
- * @x: the USB OTG transceiver to be used; or NULL
+ * usb_set_transceiver - declare the (single) USB transceiver
+ * @x: the USB transceiver to be used; or NULL
  *
  * This call is exclusively for use by transceiver drivers, which
  * coordinate the activities of drivers for host and peripheral
  * controllers, and in some cases for VBUS current regulation.
  */
-int otg_set_transceiver(struct otg_transceiver *x)
+int usb_set_transceiver(struct usb_phy *x)
 {
-	if (xceiv && x)
+	if (phy && x)
 		return -EBUSY;
-	xceiv = x;
+	phy = x;
 	return 0;
 }
-EXPORT_SYMBOL(otg_set_transceiver);
+EXPORT_SYMBOL(usb_set_transceiver);
 
 const char *otg_state_string(enum usb_otg_state state)
 {
diff --git a/drivers/usb/otg/otg_fsm.c b/drivers/usb/otg/otg_fsm.c
index 0911738..ade131a 100644
--- a/drivers/usb/otg/otg_fsm.c
+++ b/drivers/usb/otg/otg_fsm.c
@@ -117,10 +117,10 @@
 int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 {
 	state_changed = 1;
-	if (fsm->transceiver->state == new_state)
+	if (fsm->otg->phy->state == new_state)
 		return 0;
 	VDBG("Set state: %s\n", otg_state_string(new_state));
-	otg_leave_state(fsm, fsm->transceiver->state);
+	otg_leave_state(fsm, fsm->otg->phy->state);
 	switch (new_state) {
 	case OTG_STATE_B_IDLE:
 		otg_drv_vbus(fsm, 0);
@@ -155,8 +155,8 @@
 		otg_loc_conn(fsm, 0);
 		otg_loc_sof(fsm, 1);
 		otg_set_protocol(fsm, PROTO_HOST);
-		usb_bus_start_enum(fsm->transceiver->host,
-				fsm->transceiver->host->otg_port);
+		usb_bus_start_enum(fsm->otg->host,
+				fsm->otg->host->otg_port);
 		break;
 	case OTG_STATE_A_IDLE:
 		otg_drv_vbus(fsm, 0);
@@ -221,7 +221,7 @@
 		break;
 	}
 
-	fsm->transceiver->state = new_state;
+	fsm->otg->phy->state = new_state;
 	return 0;
 }
 
@@ -233,7 +233,7 @@
 
 	spin_lock_irqsave(&fsm->lock, flags);
 
-	state = fsm->transceiver->state;
+	state = fsm->otg->phy->state;
 	state_changed = 0;
 	/* State machine state change judgement */
 
@@ -248,7 +248,7 @@
 	case OTG_STATE_B_IDLE:
 		if (!fsm->id)
 			otg_set_state(fsm, OTG_STATE_A_IDLE);
-		else if (fsm->b_sess_vld && fsm->transceiver->gadget)
+		else if (fsm->b_sess_vld && fsm->otg->gadget)
 			otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
 		else if (fsm->b_bus_req && fsm->b_sess_end && fsm->b_se0_srp)
 			otg_set_state(fsm, OTG_STATE_B_SRP_INIT);
@@ -260,7 +260,7 @@
 	case OTG_STATE_B_PERIPHERAL:
 		if (!fsm->id || !fsm->b_sess_vld)
 			otg_set_state(fsm, OTG_STATE_B_IDLE);
-		else if (fsm->b_bus_req && fsm->transceiver->
+		else if (fsm->b_bus_req && fsm->otg->
 				gadget->b_hnp_enable && fsm->a_bus_suspend)
 			otg_set_state(fsm, OTG_STATE_B_WAIT_ACON);
 		break;
@@ -302,7 +302,7 @@
 		break;
 	case OTG_STATE_A_HOST:
 		if ((!fsm->a_bus_req || fsm->a_suspend_req) &&
-				fsm->transceiver->host->b_hnp_enable)
+				fsm->otg->host->b_hnp_enable)
 			otg_set_state(fsm, OTG_STATE_A_SUSPEND);
 		else if (fsm->id || !fsm->b_conn || fsm->a_bus_drop)
 			otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
@@ -310,9 +310,9 @@
 			otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
 		break;
 	case OTG_STATE_A_SUSPEND:
-		if (!fsm->b_conn && fsm->transceiver->host->b_hnp_enable)
+		if (!fsm->b_conn && fsm->otg->host->b_hnp_enable)
 			otg_set_state(fsm, OTG_STATE_A_PERIPHERAL);
-		else if (!fsm->b_conn && !fsm->transceiver->host->b_hnp_enable)
+		else if (!fsm->b_conn && !fsm->otg->host->b_hnp_enable)
 			otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
 		else if (fsm->a_bus_req || fsm->b_bus_resume)
 			otg_set_state(fsm, OTG_STATE_A_HOST);
diff --git a/drivers/usb/otg/otg_fsm.h b/drivers/usb/otg/otg_fsm.h
index 0cecf1d..c30a2e1 100644
--- a/drivers/usb/otg/otg_fsm.h
+++ b/drivers/usb/otg/otg_fsm.h
@@ -82,7 +82,7 @@
 	int loc_sof;
 
 	struct otg_fsm_ops *ops;
-	struct otg_transceiver *transceiver;
+	struct usb_otg *otg;
 
 	/* Current usb protocol used: 0:undefine; 1:host; 2:client */
 	int protocol;
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
index 14f66c3..c4a86da 100644
--- a/drivers/usb/otg/twl4030-usb.c
+++ b/drivers/usb/otg/twl4030-usb.c
@@ -144,7 +144,7 @@
 #define GPIO_USB_4PIN_ULPI_2430C	(3 << 0)
 
 struct twl4030_usb {
-	struct otg_transceiver	otg;
+	struct usb_phy		phy;
 	struct device		*dev;
 
 	/* TWL4030 internal USB regulator supplies */
@@ -166,7 +166,7 @@
 };
 
 /* internal define on top of container_of */
-#define xceiv_to_twl(x)		container_of((x), struct twl4030_usb, otg)
+#define phy_to_twl(x)		container_of((x), struct twl4030_usb, phy)
 
 /*-------------------------------------------------------------------------*/
 
@@ -246,10 +246,11 @@
 
 /*-------------------------------------------------------------------------*/
 
-static enum usb_xceiv_events twl4030_usb_linkstat(struct twl4030_usb *twl)
+static enum usb_phy_events twl4030_usb_linkstat(struct twl4030_usb *twl)
 {
 	int	status;
 	int	linkstat = USB_EVENT_NONE;
+	struct usb_otg *otg = twl->phy.otg;
 
 	twl->vbus_supplied = false;
 
@@ -281,7 +282,7 @@
 	dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n",
 			status, status, linkstat);
 
-	twl->otg.last_event = linkstat;
+	twl->phy.last_event = linkstat;
 
 	/* REVISIT this assumes host and peripheral controllers
 	 * are registered, and that both are active...
@@ -290,11 +291,11 @@
 	spin_lock_irq(&twl->lock);
 	twl->linkstat = linkstat;
 	if (linkstat == USB_EVENT_ID) {
-		twl->otg.default_a = true;
-		twl->otg.state = OTG_STATE_A_IDLE;
+		otg->default_a = true;
+		twl->phy.state = OTG_STATE_A_IDLE;
 	} else {
-		twl->otg.default_a = false;
-		twl->otg.state = OTG_STATE_B_IDLE;
+		otg->default_a = false;
+		twl->phy.state = OTG_STATE_B_IDLE;
 	}
 	spin_unlock_irq(&twl->lock);
 
@@ -520,8 +521,8 @@
 		else
 			twl4030_phy_resume(twl);
 
-		atomic_notifier_call_chain(&twl->otg.notifier, status,
-				twl->otg.gadget);
+		atomic_notifier_call_chain(&twl->phy.notifier, status,
+				twl->phy.otg->gadget);
 	}
 	sysfs_notify(&twl->dev->kobj, NULL, "vbus");
 
@@ -542,15 +543,15 @@
 			twl->asleep = 0;
 		}
 
-		atomic_notifier_call_chain(&twl->otg.notifier, status,
-				twl->otg.gadget);
+		atomic_notifier_call_chain(&twl->phy.notifier, status,
+				twl->phy.otg->gadget);
 	}
 	sysfs_notify(&twl->dev->kobj, NULL, "vbus");
 }
 
-static int twl4030_set_suspend(struct otg_transceiver *x, int suspend)
+static int twl4030_set_suspend(struct usb_phy *x, int suspend)
 {
-	struct twl4030_usb *twl = xceiv_to_twl(x);
+	struct twl4030_usb *twl = phy_to_twl(x);
 
 	if (suspend)
 		twl4030_phy_suspend(twl, 1);
@@ -560,33 +561,27 @@
 	return 0;
 }
 
-static int twl4030_set_peripheral(struct otg_transceiver *x,
-		struct usb_gadget *gadget)
+static int twl4030_set_peripheral(struct usb_otg *otg,
+					struct usb_gadget *gadget)
 {
-	struct twl4030_usb *twl;
-
-	if (!x)
+	if (!otg)
 		return -ENODEV;
 
-	twl = xceiv_to_twl(x);
-	twl->otg.gadget = gadget;
+	otg->gadget = gadget;
 	if (!gadget)
-		twl->otg.state = OTG_STATE_UNDEFINED;
+		otg->phy->state = OTG_STATE_UNDEFINED;
 
 	return 0;
 }
 
-static int twl4030_set_host(struct otg_transceiver *x, struct usb_bus *host)
+static int twl4030_set_host(struct usb_otg *otg, struct usb_bus *host)
 {
-	struct twl4030_usb *twl;
-
-	if (!x)
+	if (!otg)
 		return -ENODEV;
 
-	twl = xceiv_to_twl(x);
-	twl->otg.host = host;
+	otg->host = host;
 	if (!host)
-		twl->otg.state = OTG_STATE_UNDEFINED;
+		otg->phy->state = OTG_STATE_UNDEFINED;
 
 	return 0;
 }
@@ -596,6 +591,7 @@
 	struct twl4030_usb_data *pdata = pdev->dev.platform_data;
 	struct twl4030_usb	*twl;
 	int			status, err;
+	struct usb_otg		*otg;
 
 	if (!pdata) {
 		dev_dbg(&pdev->dev, "platform_data not available\n");
@@ -606,16 +602,26 @@
 	if (!twl)
 		return -ENOMEM;
 
+	otg = kzalloc(sizeof *otg, GFP_KERNEL);
+	if (!otg) {
+		kfree(twl);
+		return -ENOMEM;
+	}
+
 	twl->dev		= &pdev->dev;
 	twl->irq		= platform_get_irq(pdev, 0);
-	twl->otg.dev		= twl->dev;
-	twl->otg.label		= "twl4030";
-	twl->otg.set_host	= twl4030_set_host;
-	twl->otg.set_peripheral	= twl4030_set_peripheral;
-	twl->otg.set_suspend	= twl4030_set_suspend;
 	twl->usb_mode		= pdata->usb_mode;
 	twl->vbus_supplied	= false;
-	twl->asleep = 1;
+	twl->asleep		= 1;
+
+	twl->phy.dev		= twl->dev;
+	twl->phy.label		= "twl4030";
+	twl->phy.otg		= otg;
+	twl->phy.set_suspend	= twl4030_set_suspend;
+
+	otg->phy		= &twl->phy;
+	otg->set_host		= twl4030_set_host;
+	otg->set_peripheral	= twl4030_set_peripheral;
 
 	/* init spinlock for workqueue */
 	spin_lock_init(&twl->lock);
@@ -623,16 +629,17 @@
 	err = twl4030_usb_ldo_init(twl);
 	if (err) {
 		dev_err(&pdev->dev, "ldo init failed\n");
+		kfree(otg);
 		kfree(twl);
 		return err;
 	}
-	otg_set_transceiver(&twl->otg);
+	usb_set_transceiver(&twl->phy);
 
 	platform_set_drvdata(pdev, twl);
 	if (device_create_file(&pdev->dev, &dev_attr_vbus))
 		dev_warn(&pdev->dev, "could not create sysfs file\n");
 
-	ATOMIC_INIT_NOTIFIER_HEAD(&twl->otg.notifier);
+	ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier);
 
 	/* Our job is to use irqs and status from the power module
 	 * to keep the transceiver disabled when nothing's connected.
@@ -649,6 +656,7 @@
 	if (status < 0) {
 		dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
 			twl->irq, status);
+		kfree(otg);
 		kfree(twl);
 		return status;
 	}
@@ -693,6 +701,7 @@
 	regulator_put(twl->usb1v8);
 	regulator_put(twl->usb3v1);
 
+	kfree(twl->phy.otg);
 	kfree(twl);
 
 	return 0;
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c
index ed2b26c..e3fa387 100644
--- a/drivers/usb/otg/twl6030-usb.c
+++ b/drivers/usb/otg/twl6030-usb.c
@@ -87,7 +87,7 @@
 #define	VBUS_DET			BIT(2)
 
 struct twl6030_usb {
-	struct otg_transceiver	otg;
+	struct usb_phy		phy;
 	struct device		*dev;
 
 	/* for vbus reporting with irqs disabled */
@@ -107,7 +107,7 @@
 	unsigned long		features;
 };
 
-#define xceiv_to_twl(x)		container_of((x), struct twl6030_usb, otg)
+#define phy_to_twl(x)		container_of((x), struct twl6030_usb, phy)
 
 /*-------------------------------------------------------------------------*/
 
@@ -137,13 +137,13 @@
 	return ret;
 }
 
-static int twl6030_phy_init(struct otg_transceiver *x)
+static int twl6030_phy_init(struct usb_phy *x)
 {
 	struct twl6030_usb *twl;
 	struct device *dev;
 	struct twl4030_usb_data *pdata;
 
-	twl = xceiv_to_twl(x);
+	twl = phy_to_twl(x);
 	dev  = twl->dev;
 	pdata = dev->platform_data;
 
@@ -155,21 +155,21 @@
 	return 0;
 }
 
-static void twl6030_phy_shutdown(struct otg_transceiver *x)
+static void twl6030_phy_shutdown(struct usb_phy *x)
 {
 	struct twl6030_usb *twl;
 	struct device *dev;
 	struct twl4030_usb_data *pdata;
 
-	twl = xceiv_to_twl(x);
+	twl = phy_to_twl(x);
 	dev  = twl->dev;
 	pdata = dev->platform_data;
 	pdata->phy_power(twl->dev, 0, 0);
 }
 
-static int twl6030_phy_suspend(struct otg_transceiver *x, int suspend)
+static int twl6030_phy_suspend(struct usb_phy *x, int suspend)
 {
-	struct twl6030_usb *twl = xceiv_to_twl(x);
+	struct twl6030_usb *twl = phy_to_twl(x);
 	struct device *dev = twl->dev;
 	struct twl4030_usb_data *pdata = dev->platform_data;
 
@@ -178,9 +178,9 @@
 	return 0;
 }
 
-static int twl6030_start_srp(struct otg_transceiver *x)
+static int twl6030_start_srp(struct usb_otg *otg)
 {
-	struct twl6030_usb *twl = xceiv_to_twl(x);
+	struct twl6030_usb *twl = phy_to_twl(otg->phy);
 
 	twl6030_writeb(twl, TWL_MODULE_USB, 0x24, USB_VBUS_CTRL_SET);
 	twl6030_writeb(twl, TWL_MODULE_USB, 0x84, USB_VBUS_CTRL_SET);
@@ -256,6 +256,7 @@
 static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
 {
 	struct twl6030_usb *twl = _twl;
+	struct usb_otg *otg = twl->phy.otg;
 	int status;
 	u8 vbus_state, hw_state;
 
@@ -268,18 +269,18 @@
 			regulator_enable(twl->usb3v3);
 			twl->asleep = 1;
 			status = USB_EVENT_VBUS;
-			twl->otg.default_a = false;
-			twl->otg.state = OTG_STATE_B_IDLE;
+			otg->default_a = false;
+			twl->phy.state = OTG_STATE_B_IDLE;
 			twl->linkstat = status;
-			twl->otg.last_event = status;
-			atomic_notifier_call_chain(&twl->otg.notifier,
-						status, twl->otg.gadget);
+			twl->phy.last_event = status;
+			atomic_notifier_call_chain(&twl->phy.notifier,
+						status, otg->gadget);
 		} else {
 			status = USB_EVENT_NONE;
 			twl->linkstat = status;
-			twl->otg.last_event = status;
-			atomic_notifier_call_chain(&twl->otg.notifier,
-						status, twl->otg.gadget);
+			twl->phy.last_event = status;
+			atomic_notifier_call_chain(&twl->phy.notifier,
+						status, otg->gadget);
 			if (twl->asleep) {
 				regulator_disable(twl->usb3v3);
 				twl->asleep = 0;
@@ -294,6 +295,7 @@
 static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
 {
 	struct twl6030_usb *twl = _twl;
+	struct usb_otg *otg = twl->phy.otg;
 	int status = USB_EVENT_NONE;
 	u8 hw_state;
 
@@ -307,12 +309,12 @@
 		twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET,
 								0x10);
 		status = USB_EVENT_ID;
-		twl->otg.default_a = true;
-		twl->otg.state = OTG_STATE_A_IDLE;
+		otg->default_a = true;
+		twl->phy.state = OTG_STATE_A_IDLE;
 		twl->linkstat = status;
-		twl->otg.last_event = status;
-		atomic_notifier_call_chain(&twl->otg.notifier, status,
-							twl->otg.gadget);
+		twl->phy.last_event = status;
+		atomic_notifier_call_chain(&twl->phy.notifier, status,
+							otg->gadget);
 	} else  {
 		twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR,
 								0x10);
@@ -324,25 +326,22 @@
 	return IRQ_HANDLED;
 }
 
-static int twl6030_set_peripheral(struct otg_transceiver *x,
+static int twl6030_set_peripheral(struct usb_otg *otg,
 		struct usb_gadget *gadget)
 {
-	struct twl6030_usb *twl;
-
-	if (!x)
+	if (!otg)
 		return -ENODEV;
 
-	twl = xceiv_to_twl(x);
-	twl->otg.gadget = gadget;
+	otg->gadget = gadget;
 	if (!gadget)
-		twl->otg.state = OTG_STATE_UNDEFINED;
+		otg->phy->state = OTG_STATE_UNDEFINED;
 
 	return 0;
 }
 
-static int twl6030_enable_irq(struct otg_transceiver *x)
+static int twl6030_enable_irq(struct usb_phy *x)
 {
-	struct twl6030_usb *twl = xceiv_to_twl(x);
+	struct twl6030_usb *twl = phy_to_twl(x);
 
 	twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET, 0x1);
 	twl6030_interrupt_unmask(0x05, REG_INT_MSK_LINE_C);
@@ -376,9 +375,9 @@
 							CHARGERUSB_CTRL1);
 }
 
-static int twl6030_set_vbus(struct otg_transceiver *x, bool enabled)
+static int twl6030_set_vbus(struct usb_otg *otg, bool enabled)
 {
-	struct twl6030_usb *twl = xceiv_to_twl(x);
+	struct twl6030_usb *twl = phy_to_twl(otg->phy);
 
 	twl->vbus_enable = enabled;
 	schedule_work(&twl->set_vbus_work);
@@ -386,17 +385,14 @@
 	return 0;
 }
 
-static int twl6030_set_host(struct otg_transceiver *x, struct usb_bus *host)
+static int twl6030_set_host(struct usb_otg *otg, struct usb_bus *host)
 {
-	struct twl6030_usb *twl;
-
-	if (!x)
+	if (!otg)
 		return -ENODEV;
 
-	twl = xceiv_to_twl(x);
-	twl->otg.host = host;
+	otg->host = host;
 	if (!host)
-		twl->otg.state = OTG_STATE_UNDEFINED;
+		otg->phy->state = OTG_STATE_UNDEFINED;
 	return 0;
 }
 
@@ -405,6 +401,7 @@
 	struct twl6030_usb	*twl;
 	int			status, err;
 	struct twl4030_usb_data *pdata;
+	struct usb_otg		*otg;
 	struct device *dev = &pdev->dev;
 	pdata = dev->platform_data;
 
@@ -412,19 +409,29 @@
 	if (!twl)
 		return -ENOMEM;
 
+	otg = kzalloc(sizeof *otg, GFP_KERNEL);
+	if (!otg) {
+		kfree(twl);
+		return -ENOMEM;
+	}
+
 	twl->dev		= &pdev->dev;
 	twl->irq1		= platform_get_irq(pdev, 0);
 	twl->irq2		= platform_get_irq(pdev, 1);
 	twl->features		= pdata->features;
-	twl->otg.dev		= twl->dev;
-	twl->otg.label		= "twl6030";
-	twl->otg.set_host	= twl6030_set_host;
-	twl->otg.set_peripheral	= twl6030_set_peripheral;
-	twl->otg.set_vbus	= twl6030_set_vbus;
-	twl->otg.init		= twl6030_phy_init;
-	twl->otg.shutdown	= twl6030_phy_shutdown;
-	twl->otg.set_suspend	= twl6030_phy_suspend;
-	twl->otg.start_srp	= twl6030_start_srp;
+
+	twl->phy.dev		= twl->dev;
+	twl->phy.label		= "twl6030";
+	twl->phy.otg		= otg;
+	twl->phy.init		= twl6030_phy_init;
+	twl->phy.shutdown	= twl6030_phy_shutdown;
+	twl->phy.set_suspend	= twl6030_phy_suspend;
+
+	otg->phy		= &twl->phy;
+	otg->set_host		= twl6030_set_host;
+	otg->set_peripheral	= twl6030_set_peripheral;
+	otg->set_vbus		= twl6030_set_vbus;
+	otg->start_srp		= twl6030_start_srp;
 
 	/* init spinlock for workqueue */
 	spin_lock_init(&twl->lock);
@@ -432,16 +439,17 @@
 	err = twl6030_usb_ldo_init(twl);
 	if (err) {
 		dev_err(&pdev->dev, "ldo init failed\n");
+		kfree(otg);
 		kfree(twl);
 		return err;
 	}
-	otg_set_transceiver(&twl->otg);
+	usb_set_transceiver(&twl->phy);
 
 	platform_set_drvdata(pdev, twl);
 	if (device_create_file(&pdev->dev, &dev_attr_vbus))
 		dev_warn(&pdev->dev, "could not create sysfs file\n");
 
-	ATOMIC_INIT_NOTIFIER_HEAD(&twl->otg.notifier);
+	ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier);
 
 	INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work);
 
@@ -453,6 +461,7 @@
 		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
 			twl->irq1, status);
 		device_remove_file(twl->dev, &dev_attr_vbus);
+		kfree(otg);
 		kfree(twl);
 		return status;
 	}
@@ -465,14 +474,15 @@
 			twl->irq2, status);
 		free_irq(twl->irq1, twl);
 		device_remove_file(twl->dev, &dev_attr_vbus);
+		kfree(otg);
 		kfree(twl);
 		return status;
 	}
 
 	twl->asleep = 0;
 	pdata->phy_init(dev);
-	twl6030_phy_suspend(&twl->otg, 0);
-	twl6030_enable_irq(&twl->otg);
+	twl6030_phy_suspend(&twl->phy, 0);
+	twl6030_enable_irq(&twl->phy);
 	dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");
 
 	return 0;
@@ -496,6 +506,7 @@
 	pdata->phy_exit(twl->dev);
 	device_remove_file(twl->dev, &dev_attr_vbus);
 	cancel_work_sync(&twl->set_vbus_work);
+	kfree(twl->phy.otg);
 	kfree(twl);
 
 	return 0;
diff --git a/drivers/usb/otg/ulpi.c b/drivers/usb/otg/ulpi.c
index 0b04667..217339d 100644
--- a/drivers/usb/otg/ulpi.c
+++ b/drivers/usb/otg/ulpi.c
@@ -49,31 +49,31 @@
 	ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB331x"),
 };
 
-static int ulpi_set_otg_flags(struct otg_transceiver *otg)
+static int ulpi_set_otg_flags(struct usb_phy *phy)
 {
 	unsigned int flags = ULPI_OTG_CTRL_DP_PULLDOWN |
 			     ULPI_OTG_CTRL_DM_PULLDOWN;
 
-	if (otg->flags & ULPI_OTG_ID_PULLUP)
+	if (phy->flags & ULPI_OTG_ID_PULLUP)
 		flags |= ULPI_OTG_CTRL_ID_PULLUP;
 
 	/*
 	 * ULPI Specification rev.1.1 default
 	 * for Dp/DmPulldown is enabled.
 	 */
-	if (otg->flags & ULPI_OTG_DP_PULLDOWN_DIS)
+	if (phy->flags & ULPI_OTG_DP_PULLDOWN_DIS)
 		flags &= ~ULPI_OTG_CTRL_DP_PULLDOWN;
 
-	if (otg->flags & ULPI_OTG_DM_PULLDOWN_DIS)
+	if (phy->flags & ULPI_OTG_DM_PULLDOWN_DIS)
 		flags &= ~ULPI_OTG_CTRL_DM_PULLDOWN;
 
-	if (otg->flags & ULPI_OTG_EXTVBUSIND)
+	if (phy->flags & ULPI_OTG_EXTVBUSIND)
 		flags |= ULPI_OTG_CTRL_EXTVBUSIND;
 
-	return otg_io_write(otg, flags, ULPI_OTG_CTRL);
+	return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
 }
 
-static int ulpi_set_fc_flags(struct otg_transceiver *otg)
+static int ulpi_set_fc_flags(struct usb_phy *phy)
 {
 	unsigned int flags = 0;
 
@@ -81,27 +81,27 @@
 	 * ULPI Specification rev.1.1 default
 	 * for XcvrSelect is Full Speed.
 	 */
-	if (otg->flags & ULPI_FC_HS)
+	if (phy->flags & ULPI_FC_HS)
 		flags |= ULPI_FUNC_CTRL_HIGH_SPEED;
-	else if (otg->flags & ULPI_FC_LS)
+	else if (phy->flags & ULPI_FC_LS)
 		flags |= ULPI_FUNC_CTRL_LOW_SPEED;
-	else if (otg->flags & ULPI_FC_FS4LS)
+	else if (phy->flags & ULPI_FC_FS4LS)
 		flags |= ULPI_FUNC_CTRL_FS4LS;
 	else
 		flags |= ULPI_FUNC_CTRL_FULL_SPEED;
 
-	if (otg->flags & ULPI_FC_TERMSEL)
+	if (phy->flags & ULPI_FC_TERMSEL)
 		flags |= ULPI_FUNC_CTRL_TERMSELECT;
 
 	/*
 	 * ULPI Specification rev.1.1 default
 	 * for OpMode is Normal Operation.
 	 */
-	if (otg->flags & ULPI_FC_OP_NODRV)
+	if (phy->flags & ULPI_FC_OP_NODRV)
 		flags |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
-	else if (otg->flags & ULPI_FC_OP_DIS_NRZI)
+	else if (phy->flags & ULPI_FC_OP_DIS_NRZI)
 		flags |= ULPI_FUNC_CTRL_OPMODE_DISABLE_NRZI;
-	else if (otg->flags & ULPI_FC_OP_NSYNC_NEOP)
+	else if (phy->flags & ULPI_FC_OP_NSYNC_NEOP)
 		flags |= ULPI_FUNC_CTRL_OPMODE_NOSYNC_NOEOP;
 	else
 		flags |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
@@ -112,54 +112,54 @@
 	 */
 	flags |= ULPI_FUNC_CTRL_SUSPENDM;
 
-	return otg_io_write(otg, flags, ULPI_FUNC_CTRL);
+	return usb_phy_io_write(phy, flags, ULPI_FUNC_CTRL);
 }
 
-static int ulpi_set_ic_flags(struct otg_transceiver *otg)
+static int ulpi_set_ic_flags(struct usb_phy *phy)
 {
 	unsigned int flags = 0;
 
-	if (otg->flags & ULPI_IC_AUTORESUME)
+	if (phy->flags & ULPI_IC_AUTORESUME)
 		flags |= ULPI_IFC_CTRL_AUTORESUME;
 
-	if (otg->flags & ULPI_IC_EXTVBUS_INDINV)
+	if (phy->flags & ULPI_IC_EXTVBUS_INDINV)
 		flags |= ULPI_IFC_CTRL_EXTERNAL_VBUS;
 
-	if (otg->flags & ULPI_IC_IND_PASSTHRU)
+	if (phy->flags & ULPI_IC_IND_PASSTHRU)
 		flags |= ULPI_IFC_CTRL_PASSTHRU;
 
-	if (otg->flags & ULPI_IC_PROTECT_DIS)
+	if (phy->flags & ULPI_IC_PROTECT_DIS)
 		flags |= ULPI_IFC_CTRL_PROTECT_IFC_DISABLE;
 
-	return otg_io_write(otg, flags, ULPI_IFC_CTRL);
+	return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL);
 }
 
-static int ulpi_set_flags(struct otg_transceiver *otg)
+static int ulpi_set_flags(struct usb_phy *phy)
 {
 	int ret;
 
-	ret = ulpi_set_otg_flags(otg);
+	ret = ulpi_set_otg_flags(phy);
 	if (ret)
 		return ret;
 
-	ret = ulpi_set_ic_flags(otg);
+	ret = ulpi_set_ic_flags(phy);
 	if (ret)
 		return ret;
 
-	return ulpi_set_fc_flags(otg);
+	return ulpi_set_fc_flags(phy);
 }
 
-static int ulpi_check_integrity(struct otg_transceiver *otg)
+static int ulpi_check_integrity(struct usb_phy *phy)
 {
 	int ret, i;
 	unsigned int val = 0x55;
 
 	for (i = 0; i < 2; i++) {
-		ret = otg_io_write(otg, val, ULPI_SCRATCH);
+		ret = usb_phy_io_write(phy, val, ULPI_SCRATCH);
 		if (ret < 0)
 			return ret;
 
-		ret = otg_io_read(otg, ULPI_SCRATCH);
+		ret = usb_phy_io_read(phy, ULPI_SCRATCH);
 		if (ret < 0)
 			return ret;
 
@@ -175,13 +175,13 @@
 	return 0;
 }
 
-static int ulpi_init(struct otg_transceiver *otg)
+static int ulpi_init(struct usb_phy *phy)
 {
 	int i, vid, pid, ret;
 	u32 ulpi_id = 0;
 
 	for (i = 0; i < 4; i++) {
-		ret = otg_io_read(otg, ULPI_PRODUCT_ID_HIGH - i);
+		ret = usb_phy_io_read(phy, ULPI_PRODUCT_ID_HIGH - i);
 		if (ret < 0)
 			return ret;
 		ulpi_id = (ulpi_id << 8) | ret;
@@ -199,16 +199,17 @@
 		}
 	}
 
-	ret = ulpi_check_integrity(otg);
+	ret = ulpi_check_integrity(phy);
 	if (ret)
 		return ret;
 
-	return ulpi_set_flags(otg);
+	return ulpi_set_flags(phy);
 }
 
-static int ulpi_set_host(struct otg_transceiver *otg, struct usb_bus *host)
+static int ulpi_set_host(struct usb_otg *otg, struct usb_bus *host)
 {
-	unsigned int flags = otg_io_read(otg, ULPI_IFC_CTRL);
+	struct usb_phy *phy = otg->phy;
+	unsigned int flags = usb_phy_io_read(phy, ULPI_IFC_CTRL);
 
 	if (!host) {
 		otg->host = NULL;
@@ -221,51 +222,62 @@
 		   ULPI_IFC_CTRL_3_PIN_SERIAL_MODE |
 		   ULPI_IFC_CTRL_CARKITMODE);
 
-	if (otg->flags & ULPI_IC_6PIN_SERIAL)
+	if (phy->flags & ULPI_IC_6PIN_SERIAL)
 		flags |= ULPI_IFC_CTRL_6_PIN_SERIAL_MODE;
-	else if (otg->flags & ULPI_IC_3PIN_SERIAL)
+	else if (phy->flags & ULPI_IC_3PIN_SERIAL)
 		flags |= ULPI_IFC_CTRL_3_PIN_SERIAL_MODE;
-	else if (otg->flags & ULPI_IC_CARKIT)
+	else if (phy->flags & ULPI_IC_CARKIT)
 		flags |= ULPI_IFC_CTRL_CARKITMODE;
 
-	return otg_io_write(otg, flags, ULPI_IFC_CTRL);
+	return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL);
 }
 
-static int ulpi_set_vbus(struct otg_transceiver *otg, bool on)
+static int ulpi_set_vbus(struct usb_otg *otg, bool on)
 {
-	unsigned int flags = otg_io_read(otg, ULPI_OTG_CTRL);
+	struct usb_phy *phy = otg->phy;
+	unsigned int flags = usb_phy_io_read(phy, ULPI_OTG_CTRL);
 
 	flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT);
 
 	if (on) {
-		if (otg->flags & ULPI_OTG_DRVVBUS)
+		if (phy->flags & ULPI_OTG_DRVVBUS)
 			flags |= ULPI_OTG_CTRL_DRVVBUS;
 
-		if (otg->flags & ULPI_OTG_DRVVBUS_EXT)
+		if (phy->flags & ULPI_OTG_DRVVBUS_EXT)
 			flags |= ULPI_OTG_CTRL_DRVVBUS_EXT;
 	}
 
-	return otg_io_write(otg, flags, ULPI_OTG_CTRL);
+	return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
 }
 
-struct otg_transceiver *
-otg_ulpi_create(struct otg_io_access_ops *ops,
+struct usb_phy *
+otg_ulpi_create(struct usb_phy_io_ops *ops,
 		unsigned int flags)
 {
-	struct otg_transceiver *otg;
+	struct usb_phy *phy;
+	struct usb_otg *otg;
 
-	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
-	if (!otg)
+	phy = kzalloc(sizeof(*phy), GFP_KERNEL);
+	if (!phy)
 		return NULL;
 
-	otg->label	= "ULPI";
-	otg->flags	= flags;
-	otg->io_ops	= ops;
-	otg->init	= ulpi_init;
+	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
+	if (!otg) {
+		kfree(phy);
+		return NULL;
+	}
+
+	phy->label	= "ULPI";
+	phy->flags	= flags;
+	phy->io_ops	= ops;
+	phy->otg	= otg;
+	phy->init	= ulpi_init;
+
+	otg->phy	= phy;
 	otg->set_host	= ulpi_set_host;
 	otg->set_vbus	= ulpi_set_vbus;
 
-	return otg;
+	return phy;
 }
 EXPORT_SYMBOL_GPL(otg_ulpi_create);
 
diff --git a/drivers/usb/otg/ulpi_viewport.c b/drivers/usb/otg/ulpi_viewport.c
index e9a37f9..c5ba7e5 100644
--- a/drivers/usb/otg/ulpi_viewport.c
+++ b/drivers/usb/otg/ulpi_viewport.c
@@ -40,7 +40,7 @@
 	return -ETIMEDOUT;
 }
 
-static int ulpi_viewport_read(struct otg_transceiver *otg, u32 reg)
+static int ulpi_viewport_read(struct usb_phy *otg, u32 reg)
 {
 	int ret;
 	void __iomem *view = otg->io_priv;
@@ -58,7 +58,7 @@
 	return ULPI_VIEW_DATA_READ(readl(view));
 }
 
-static int ulpi_viewport_write(struct otg_transceiver *otg, u32 val, u32 reg)
+static int ulpi_viewport_write(struct usb_phy *otg, u32 val, u32 reg)
 {
 	int ret;
 	void __iomem *view = otg->io_priv;
@@ -74,7 +74,7 @@
 	return ulpi_viewport_wait(view, ULPI_VIEW_RUN);
 }
 
-struct otg_io_access_ops ulpi_viewport_access_ops = {
+struct usb_phy_io_ops ulpi_viewport_access_ops = {
 	.read	= ulpi_viewport_read,
 	.write	= ulpi_viewport_write,
 };
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index e9a5b1d..a165490 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -413,8 +413,7 @@
 	struct renesas_usbhs_platform_info *info = pdev->dev.platform_data;
 	struct renesas_usbhs_driver_callback *dfunc;
 	struct usbhs_priv *priv;
-	struct resource *res;
-	unsigned int irq;
+	struct resource *res, *irq_res;
 	int ret;
 
 	/* check platform information */
@@ -426,8 +425,8 @@
 
 	/* platform data */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	irq = platform_get_irq(pdev, 0);
-	if (!res || (int)irq <= 0) {
+	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res || !irq_res) {
 		dev_err(&pdev->dev, "Not enough Renesas USB platform resources.\n");
 		return -ENODEV;
 	}
@@ -476,7 +475,9 @@
 	/*
 	 * priv settings
 	 */
-	priv->irq	= irq;
+	priv->irq	= irq_res->start;
+	if (irq_res->flags & IORESOURCE_IRQ_SHAREABLE)
+		priv->irqflags = IRQF_SHARED;
 	priv->pdev	= pdev;
 	INIT_DELAYED_WORK(&priv->notify_hotplug_work, usbhsc_notify_hotplug);
 	spin_lock_init(usbhs_priv_to_lock(priv));
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index d79b3e2..3f3ccd3 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -242,6 +242,7 @@
 
 	void __iomem *base;
 	unsigned int irq;
+	unsigned long irqflags;
 
 	struct renesas_usbhs_platform_callback	pfunc;
 	struct renesas_usbhs_driver_param	dparam;
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 72339bd..3648c82 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -23,6 +23,7 @@
 #define usbhsf_get_cfifo(p)	(&((p)->fifo_info.cfifo))
 #define usbhsf_get_d0fifo(p)	(&((p)->fifo_info.d0fifo))
 #define usbhsf_get_d1fifo(p)	(&((p)->fifo_info.d1fifo))
+#define usbhsf_is_cfifo(p, f)	(usbhsf_get_cfifo(p) == f)
 
 #define usbhsf_fifo_is_busy(f)	((f)->pipe) /* see usbhs_pipe_select_fifo */
 
@@ -75,8 +76,7 @@
 		pipe->handler = &usbhsf_null_handler;
 	}
 
-	list_del_init(&pkt->node);
-	list_add_tail(&pkt->node, &pipe->list);
+	list_move_tail(&pkt->node, &pipe->list);
 
 	/*
 	 * each pkt must hold own handler.
@@ -106,7 +106,7 @@
 	if (list_empty(&pipe->list))
 		return NULL;
 
-	return list_entry(pipe->list.next, struct usbhs_pkt, node);
+	return list_first_entry(&pipe->list, struct usbhs_pkt, node);
 }
 
 struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt)
@@ -305,7 +305,10 @@
 	}
 
 	/* "base" will be used below  */
-	usbhs_write(priv, fifo->sel, base | MBW_32);
+	if (usbhs_get_dparam(priv, has_sudmac) && !usbhsf_is_cfifo(priv, fifo))
+		usbhs_write(priv, fifo->sel, base);
+	else
+		usbhs_write(priv, fifo->sel, base | MBW_32);
 
 	/* check ISEL and CURPIPE value */
 	while (timeout--) {
@@ -762,9 +765,9 @@
 }
 
 static void usbhsf_dma_complete(void *arg);
-static void usbhsf_dma_prepare_tasklet(unsigned long data)
+static void xfer_work(struct work_struct *work)
 {
-	struct usbhs_pkt *pkt = (struct usbhs_pkt *)data;
+	struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
 	struct usbhs_pipe *pipe = pkt->pipe;
 	struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe);
 	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
@@ -844,11 +847,8 @@
 
 	pkt->trans = len;
 
-	tasklet_init(&fifo->tasklet,
-		     usbhsf_dma_prepare_tasklet,
-		     (unsigned long)pkt);
-
-	tasklet_schedule(&fifo->tasklet);
+	INIT_WORK(&pkt->work, xfer_work);
+	schedule_work(&pkt->work);
 
 	return 0;
 
@@ -938,11 +938,8 @@
 
 	pkt->trans = len;
 
-	tasklet_init(&fifo->tasklet,
-		     usbhsf_dma_prepare_tasklet,
-		     (unsigned long)pkt);
-
-	tasklet_schedule(&fifo->tasklet);
+	INIT_WORK(&pkt->work, xfer_work);
+	schedule_work(&pkt->work);
 
 	return 0;
 
diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h
index f68609c..c31731a 100644
--- a/drivers/usb/renesas_usbhs/fifo.h
+++ b/drivers/usb/renesas_usbhs/fifo.h
@@ -19,6 +19,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/sh_dma.h>
+#include <linux/workqueue.h>
 #include <asm/dma.h>
 #include "pipe.h"
 
@@ -31,7 +32,6 @@
 	u32 ctr;	/* xFIFOCTR */
 
 	struct usbhs_pipe	*pipe;
-	struct tasklet_struct	tasklet;
 
 	struct dma_chan		*tx_chan;
 	struct dma_chan		*rx_chan;
@@ -53,6 +53,7 @@
 	struct usbhs_pkt_handle *handler;
 	void (*done)(struct usbhs_priv *priv,
 		     struct usbhs_pkt *pkt);
+	struct work_struct work;
 	dma_addr_t dma;
 	void *buf;
 	int length;
diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c
index 1b97fb1..0871e81 100644
--- a/drivers/usb/renesas_usbhs/mod.c
+++ b/drivers/usb/renesas_usbhs/mod.c
@@ -152,7 +152,7 @@
 
 	/* irq settings */
 	ret = request_irq(priv->irq, usbhs_interrupt,
-			  0, dev_name(dev), priv);
+			  priv->irqflags, dev_name(dev), priv);
 	if (ret) {
 		dev_err(dev, "irq request err\n");
 		goto mod_init_gadget_err;
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 7542aa9..00bd2a5 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -165,69 +165,32 @@
 /*
  *		dma map/unmap
  */
-static int usbhsg_dma_map(struct device *dev,
-			  struct usbhs_pkt *pkt,
-			  enum dma_data_direction dir)
-{
-	struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt);
-	struct usb_request *req = &ureq->req;
-
-	if (pkt->dma != DMA_ADDR_INVALID) {
-		dev_err(dev, "dma is already mapped\n");
-		return -EIO;
-	}
-
-	if (req->dma == DMA_ADDR_INVALID) {
-		pkt->dma = dma_map_single(dev, pkt->buf, pkt->length, dir);
-	} else {
-		dma_sync_single_for_device(dev, req->dma, req->length, dir);
-		pkt->dma = req->dma;
-	}
-
-	if (dma_mapping_error(dev, pkt->dma)) {
-		dev_err(dev, "dma mapping error %llx\n", (u64)pkt->dma);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int usbhsg_dma_unmap(struct device *dev,
-			    struct usbhs_pkt *pkt,
-			    enum dma_data_direction dir)
-{
-	struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt);
-	struct usb_request *req = &ureq->req;
-
-	if (pkt->dma == DMA_ADDR_INVALID) {
-		dev_err(dev, "dma is not mapped\n");
-		return -EIO;
-	}
-
-	if (req->dma == DMA_ADDR_INVALID)
-		dma_unmap_single(dev, pkt->dma, pkt->length, dir);
-	else
-		dma_sync_single_for_cpu(dev, req->dma, req->length, dir);
-
-	pkt->dma = DMA_ADDR_INVALID;
-
-	return 0;
-}
-
 static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
 {
+	struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt);
+	struct usb_request *req = &ureq->req;
 	struct usbhs_pipe *pipe = pkt->pipe;
 	struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe);
 	struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
-	struct device *dev = usbhsg_gpriv_to_dev(gpriv);
 	enum dma_data_direction dir;
+	int ret = 0;
 
-	dir = usbhs_pipe_is_dir_in(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+	dir = usbhs_pipe_is_dir_host(pipe);
 
-	if (map)
-		return usbhsg_dma_map(dev, pkt, dir);
-	else
-		return usbhsg_dma_unmap(dev, pkt, dir);
+	if (map) {
+		/* it can not use scatter/gather */
+		WARN_ON(req->num_sgs);
+
+		ret = usb_gadget_map_request(&gpriv->gadget, req, dir);
+		if (ret < 0)
+			return ret;
+
+		pkt->dma = req->dma;
+	} else {
+		usb_gadget_unmap_request(&gpriv->gadget, req, dir);
+	}
+
+	return ret;
 }
 
 /*
@@ -657,8 +620,6 @@
 
 	usbhs_pkt_init(usbhsg_ureq_to_pkt(ureq));
 
-	ureq->req.dma = DMA_ADDR_INVALID;
-
 	return &ureq->req;
 }
 
@@ -941,6 +902,11 @@
 	return usbhsg_try_stop(priv, USBHSG_STATUS_STARTED);
 }
 
+static void usbhs_mod_gadget_release(struct device *pdev)
+{
+	/* do nothing */
+}
+
 int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
 {
 	struct usbhsg_gpriv *gpriv;
@@ -989,6 +955,7 @@
 	 */
 	dev_set_name(&gpriv->gadget.dev, "gadget");
 	gpriv->gadget.dev.parent	= dev;
+	gpriv->gadget.dev.release	= usbhs_mod_gadget_release;
 	gpriv->gadget.name		= "renesas_usbhs_udc";
 	gpriv->gadget.ops		= &usbhsg_gadget_ops;
 	gpriv->gadget.max_speed		= USB_SPEED_HIGH;
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 677f577..7141d65 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -238,6 +238,15 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called io_ti.
 
+config USB_SERIAL_F81232
+	tristate "USB Fintek F81232 Single Port Serial Driver"
+	help
+	  Say Y here if you want to use the Fintek F81232 single
+	  port usb to serial adapter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called f81232.
+
 config USB_SERIAL_GARMIN
        tristate "USB Garmin GPS driver"
        help
@@ -417,6 +426,14 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called mct_u232.
 
+config USB_SERIAL_METRO
+	tristate "USB Metrologic Instruments USB-POS Barcode Scanner Driver"
+	---help---
+	  Say Y here if you want to use a USB POS Metrologic barcode scanner.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called metro-usb.
+
 config USB_SERIAL_MOS7720
 	tristate "USB Moschip 7720 Serial Driver"
 	---help---
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 9e536ee..07f198e 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -23,6 +23,7 @@
 obj-$(CONFIG_USB_SERIAL_EDGEPORT)		+= io_edgeport.o
 obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI)		+= io_ti.o
 obj-$(CONFIG_USB_SERIAL_EMPEG)			+= empeg.o
+obj-$(CONFIG_USB_SERIAL_F81232)			+= f81232.o
 obj-$(CONFIG_USB_SERIAL_FTDI_SIO)		+= ftdi_sio.o
 obj-$(CONFIG_USB_SERIAL_FUNSOFT)		+= funsoft.o
 obj-$(CONFIG_USB_SERIAL_GARMIN)			+= garmin_gps.o
@@ -36,6 +37,7 @@
 obj-$(CONFIG_USB_SERIAL_KLSI)			+= kl5kusb105.o
 obj-$(CONFIG_USB_SERIAL_KOBIL_SCT)		+= kobil_sct.o
 obj-$(CONFIG_USB_SERIAL_MCT_U232)		+= mct_u232.o
+obj-$(CONFIG_USB_SERIAL_METRO)			+= metro-usb.o
 obj-$(CONFIG_USB_SERIAL_MOS7720)		+= mos7720.o
 obj-$(CONFIG_USB_SERIAL_MOS7840)		+= mos7840.o
 obj-$(CONFIG_USB_SERIAL_MOTOROLA)		+= moto_modem.o
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 123bf91..eec4fb9 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -175,7 +175,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id =	1,
 };
 
 static struct usb_serial_driver aircable_device = {
@@ -183,7 +182,6 @@
 		.owner =	THIS_MODULE,
 		.name =		"aircable",
 	},
-	.usb_driver = 		&aircable_driver,
 	.id_table = 		id_table,
 	.num_ports =		1,
 	.bulk_out_size =	HCI_COMPLETE_FRAME,
@@ -194,36 +192,16 @@
 	.unthrottle =		usb_serial_generic_unthrottle,
 };
 
-static int __init aircable_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&aircable_device);
-	if (retval)
-		goto failed_serial_register;
-	retval = usb_register(&aircable_driver);
-	if (retval)
-		goto failed_usb_register;
-	return 0;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&aircable_device, NULL
+};
 
-failed_usb_register:
-	usb_serial_deregister(&aircable_device);
-failed_serial_register:
-	return retval;
-}
-
-static void __exit aircable_exit(void)
-{
-	usb_deregister(&aircable_driver);
-	usb_serial_deregister(&aircable_device);
-}
+module_usb_serial_driver(aircable_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 
-module_init(aircable_init);
-module_exit(aircable_exit);
-
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 69328dc..f99f471 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -719,7 +719,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id =	1,
 };
 
 static struct usb_serial_driver ark3116_device = {
@@ -728,7 +727,6 @@
 		.name =		"ark3116",
 	},
 	.id_table =		id_table,
-	.usb_driver =		&ark3116_driver,
 	.num_ports =		1,
 	.attach =		ark3116_attach,
 	.release =		ark3116_release,
@@ -745,32 +743,12 @@
 	.process_read_urb =	ark3116_process_read_urb,
 };
 
-static int __init ark3116_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&ark3116_device, NULL
+};
 
-	retval = usb_serial_register(&ark3116_device);
-	if (retval)
-		return retval;
-	retval = usb_register(&ark3116_driver);
-	if (retval == 0) {
-		printk(KERN_INFO "%s:"
-		       DRIVER_VERSION ":"
-		       DRIVER_DESC "\n",
-		       KBUILD_MODNAME);
-	} else
-		usb_serial_deregister(&ark3116_device);
-	return retval;
-}
+module_usb_serial_driver(ark3116_driver, serial_drivers);
 
-static void __exit ark3116_exit(void)
-{
-	usb_deregister(&ark3116_driver);
-	usb_serial_deregister(&ark3116_device);
-}
-
-module_init(ark3116_init);
-module_exit(ark3116_exit);
 MODULE_LICENSE("GPL");
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 29ffeb6..a52e0d2 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -78,7 +78,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table_combined,
-	.no_dynamic_id =	1,
 };
 
 /* All of the device info needed for the serial converters */
@@ -88,7 +87,6 @@
 		.name =		"belkin",
 	},
 	.description =		"Belkin / Peracom / GoHubs USB Serial Adapter",
-	.usb_driver =		&belkin_driver,
 	.id_table =		id_table_combined,
 	.num_ports =		1,
 	.open =			belkin_sa_open,
@@ -103,6 +101,10 @@
 	.release =		belkin_sa_release,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&belkin_device, NULL
+};
+
 struct belkin_sa_private {
 	spinlock_t		lock;
 	unsigned long		control_state;
@@ -522,34 +524,7 @@
 	return retval;
 }
 
-
-static int __init belkin_sa_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&belkin_device);
-	if (retval)
-		goto failed_usb_serial_register;
-	retval = usb_register(&belkin_driver);
-	if (retval)
-		goto failed_usb_register;
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&belkin_device);
-failed_usb_serial_register:
-	return retval;
-}
-
-static void __exit belkin_sa_exit (void)
-{
-	usb_deregister(&belkin_driver);
-	usb_serial_deregister(&belkin_device);
-}
-
-
-module_init(belkin_sa_init);
-module_exit(belkin_sa_exit);
+module_usb_serial_driver(belkin_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index 5e53cc5..aaab32d 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -625,7 +625,6 @@
 	.resume		= usb_serial_resume,
 	.reset_resume	= ch341_reset_resume,
 	.id_table	= id_table,
-	.no_dynamic_id	= 1,
 	.supports_autosuspend =	1,
 };
 
@@ -635,7 +634,6 @@
 		.name	= "ch341-uart",
 	},
 	.id_table          = id_table,
-	.usb_driver        = &ch341_driver,
 	.num_ports         = 1,
 	.open              = ch341_open,
 	.dtr_rts	   = ch341_dtr_rts,
@@ -650,30 +648,13 @@
 	.attach            = ch341_attach,
 };
 
-static int __init ch341_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&ch341_device, NULL
+};
 
-	retval = usb_serial_register(&ch341_device);
-	if (retval)
-		return retval;
-	retval = usb_register(&ch341_driver);
-	if (retval)
-		usb_serial_deregister(&ch341_device);
-	return retval;
-}
+module_usb_serial_driver(ch341_driver, serial_drivers);
 
-static void __exit ch341_exit(void)
-{
-	usb_deregister(&ch341_driver);
-	usb_serial_deregister(&ch341_device);
-}
-
-module_init(ch341_init);
-module_exit(ch341_exit);
 MODULE_LICENSE("GPL");
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
-
-/* EOF ch341.c */
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 08a5575..0310e2d 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -49,6 +49,7 @@
 		unsigned int, unsigned int);
 static void cp210x_break_ctl(struct tty_struct *, int);
 static int cp210x_startup(struct usb_serial *);
+static void cp210x_release(struct usb_serial *);
 static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
 
 static bool debug;
@@ -121,6 +122,8 @@
 	{ USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */
 	{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
 	{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
+	{ USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
+	{ USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */
 	{ USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */
 	{ USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
 	{ USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */
@@ -149,12 +152,15 @@
 
 MODULE_DEVICE_TABLE(usb, id_table);
 
+struct cp210x_port_private {
+	__u8			bInterfaceNumber;
+};
+
 static struct usb_driver cp210x_driver = {
 	.name		= "cp210x",
 	.probe		= usb_serial_probe,
 	.disconnect	= usb_serial_disconnect,
 	.id_table	= id_table,
-	.no_dynamic_id	= 	1,
 };
 
 static struct usb_serial_driver cp210x_device = {
@@ -162,7 +168,6 @@
 		.owner =	THIS_MODULE,
 		.name = 	"cp210x",
 	},
-	.usb_driver		= &cp210x_driver,
 	.id_table		= id_table,
 	.num_ports		= 1,
 	.bulk_in_size		= 256,
@@ -174,9 +179,14 @@
 	.tiocmget 		= cp210x_tiocmget,
 	.tiocmset		= cp210x_tiocmset,
 	.attach			= cp210x_startup,
+	.release		= cp210x_release,
 	.dtr_rts		= cp210x_dtr_rts
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&cp210x_device, NULL
+};
+
 /* Config request types */
 #define REQTYPE_HOST_TO_DEVICE	0x41
 #define REQTYPE_DEVICE_TO_HOST	0xc1
@@ -261,6 +271,7 @@
 		unsigned int *data, int size)
 {
 	struct usb_serial *serial = port->serial;
+	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
 	__le32 *buf;
 	int result, i, length;
 
@@ -276,7 +287,7 @@
 	/* Issue the request, attempting to read 'size' bytes */
 	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
 				request, REQTYPE_DEVICE_TO_HOST, 0x0000,
-				0, buf, size, 300);
+				port_priv->bInterfaceNumber, buf, size, 300);
 
 	/* Convert data into an array of integers */
 	for (i = 0; i < length; i++)
@@ -286,7 +297,7 @@
 
 	if (result != size) {
 		dbg("%s - Unable to send config request, "
-				"request=0x%x size=%d result=%d\n",
+				"request=0x%x size=%d result=%d",
 				__func__, request, size, result);
 		if (result > 0)
 			result = -EPROTO;
@@ -307,6 +318,7 @@
 		unsigned int *data, int size)
 {
 	struct usb_serial *serial = port->serial;
+	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
 	__le32 *buf;
 	int result, i, length;
 
@@ -328,19 +340,19 @@
 		result = usb_control_msg(serial->dev,
 				usb_sndctrlpipe(serial->dev, 0),
 				request, REQTYPE_HOST_TO_DEVICE, 0x0000,
-				0, buf, size, 300);
+				port_priv->bInterfaceNumber, buf, size, 300);
 	} else {
 		result = usb_control_msg(serial->dev,
 				usb_sndctrlpipe(serial->dev, 0),
 				request, REQTYPE_HOST_TO_DEVICE, data[0],
-				0, NULL, 0, 300);
+				port_priv->bInterfaceNumber, NULL, 0, 300);
 	}
 
 	kfree(buf);
 
 	if ((size > 2 && result != size) || result < 0) {
 		dbg("%s - Unable to send request, "
-				"request=0x%x size=%d result=%d\n",
+				"request=0x%x size=%d result=%d",
 				__func__, request, size, result);
 		if (result > 0)
 			result = -EPROTO;
@@ -683,13 +695,13 @@
 		default:
 			dbg("cp210x driver does not "
 					"support the number of bits requested,"
-					" using 8 bit mode\n");
+					" using 8 bit mode");
 				bits |= BITS_DATA_8;
 				break;
 		}
 		if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
 			dbg("Number of data bits requested "
-					"not supported by device\n");
+					"not supported by device");
 	}
 
 	if ((cflag     & (PARENB|PARODD|CMSPAR)) !=
@@ -716,8 +728,7 @@
 			}
 		}
 		if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
-			dbg("Parity mode not supported "
-					"by device\n");
+			dbg("Parity mode not supported by device");
 	}
 
 	if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
@@ -732,7 +743,7 @@
 		}
 		if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
 			dbg("Number of stop bits requested "
-					"not supported by device\n");
+					"not supported by device");
 	}
 
 	if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
@@ -844,40 +855,40 @@
 
 static int cp210x_startup(struct usb_serial *serial)
 {
+	struct cp210x_port_private *port_priv;
+	int i;
+
 	/* cp210x buffers behave strangely unless device is reset */
 	usb_reset_device(serial->dev);
-	return 0;
-}
 
-static int __init cp210x_init(void)
-{
-	int retval;
+	for (i = 0; i < serial->num_ports; i++) {
+		port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL);
+		if (!port_priv)
+			return -ENOMEM;
 
-	retval = usb_serial_register(&cp210x_device);
-	if (retval)
-		return retval; /* Failed to register */
+		memset(port_priv, 0x00, sizeof(*port_priv));
+		port_priv->bInterfaceNumber =
+		    serial->interface->cur_altsetting->desc.bInterfaceNumber;
 
-	retval = usb_register(&cp210x_driver);
-	if (retval) {
-		/* Failed to register */
-		usb_serial_deregister(&cp210x_device);
-		return retval;
+		usb_set_serial_port_data(serial->port[i], port_priv);
 	}
 
-	/* Success */
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
 	return 0;
 }
 
-static void __exit cp210x_exit(void)
+static void cp210x_release(struct usb_serial *serial)
 {
-	usb_deregister(&cp210x_driver);
-	usb_serial_deregister(&cp210x_device);
+	struct cp210x_port_private *port_priv;
+	int i;
+
+	for (i = 0; i < serial->num_ports; i++) {
+		port_priv = usb_get_serial_port_data(serial->port[i]);
+		kfree(port_priv);
+		usb_set_serial_port_data(serial->port[i], NULL);
+	}
 }
 
-module_init(cp210x_init);
-module_exit(cp210x_exit);
+module_usb_serial_driver(cp210x_driver, serial_drivers);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 6bc3802..d39b941 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -82,7 +82,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id = 	1,
 };
 
 static struct usb_serial_driver cyberjack_device = {
@@ -91,7 +90,6 @@
 		.name =		"cyberjack",
 	},
 	.description =		"Reiner SCT Cyberjack USB card reader",
-	.usb_driver = 		&cyberjack_driver,
 	.id_table =		id_table,
 	.num_ports =		1,
 	.attach =		cyberjack_startup,
@@ -106,6 +104,10 @@
 	.write_bulk_callback =	cyberjack_write_bulk_callback,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&cyberjack_device, NULL
+};
+
 struct cyberjack_private {
 	spinlock_t	lock;		/* Lock for SMP */
 	short		rdtodo;		/* Bytes still to read */
@@ -473,35 +475,7 @@
 	usb_serial_port_softint(port);
 }
 
-static int __init cyberjack_init(void)
-{
-	int retval;
-	retval  = usb_serial_register(&cyberjack_device);
-	if (retval)
-		goto failed_usb_serial_register;
-	retval = usb_register(&cyberjack_driver);
-	if (retval)
-		goto failed_usb_register;
-
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION " "
-	       DRIVER_AUTHOR "\n");
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
-
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&cyberjack_device);
-failed_usb_serial_register:
-	return retval;
-}
-
-static void __exit cyberjack_exit(void)
-{
-	usb_deregister(&cyberjack_driver);
-	usb_serial_deregister(&cyberjack_device);
-}
-
-module_init(cyberjack_init);
-module_exit(cyberjack_exit);
+module_usb_serial_driver(cyberjack_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 3bdeafa..afc886c 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -94,7 +94,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table_combined,
-	.no_dynamic_id = 	1,
 };
 
 enum packet_format {
@@ -163,7 +162,6 @@
 		.name =			"earthmate",
 	},
 	.description =			"DeLorme Earthmate USB",
-	.usb_driver = 			&cypress_driver,
 	.id_table =			id_table_earthmate,
 	.num_ports =			1,
 	.attach =			cypress_earthmate_startup,
@@ -190,7 +188,6 @@
 		.name =			"cyphidcom",
 	},
 	.description =			"HID->COM RS232 Adapter",
-	.usb_driver = 			&cypress_driver,
 	.id_table =			id_table_cyphidcomrs232,
 	.num_ports =			1,
 	.attach =			cypress_hidcom_startup,
@@ -217,7 +214,6 @@
 		.name =			"nokiaca42v2",
 	},
 	.description =			"Nokia CA-42 V2 Adapter",
-	.usb_driver = 			&cypress_driver,
 	.id_table =			id_table_nokiaca42v2,
 	.num_ports =			1,
 	.attach =			cypress_ca42v2_startup,
@@ -238,6 +234,11 @@
 	.write_int_callback =		cypress_write_int_callback,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&cypress_earthmate_device, &cypress_hidcom_device,
+	&cypress_ca42v2_device, NULL
+};
+
 /*****************************************************************************
  * Cypress serial helper functions
  *****************************************************************************/
@@ -800,7 +801,7 @@
 		cypress_write_int_callback, port, priv->write_urb_interval);
 	result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
 	if (result) {
-		dev_err(&port->dev,
+		dev_err_console(port,
 				"%s - failed submitting write urb, error %d\n",
 							__func__, result);
 		priv->write_urb_in_use = 0;
@@ -1345,58 +1346,7 @@
 	cypress_send(port);
 }
 
-
-/*****************************************************************************
- * Module functions
- *****************************************************************************/
-
-static int __init cypress_init(void)
-{
-	int retval;
-
-	dbg("%s", __func__);
-
-	retval = usb_serial_register(&cypress_earthmate_device);
-	if (retval)
-		goto failed_em_register;
-	retval = usb_serial_register(&cypress_hidcom_device);
-	if (retval)
-		goto failed_hidcom_register;
-	retval = usb_serial_register(&cypress_ca42v2_device);
-	if (retval)
-		goto failed_ca42v2_register;
-	retval = usb_register(&cypress_driver);
-	if (retval)
-		goto failed_usb_register;
-
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-
-failed_usb_register:
-	usb_serial_deregister(&cypress_ca42v2_device);
-failed_ca42v2_register:
-	usb_serial_deregister(&cypress_hidcom_device);
-failed_hidcom_register:
-	usb_serial_deregister(&cypress_earthmate_device);
-failed_em_register:
-	return retval;
-}
-
-
-static void __exit cypress_exit(void)
-{
-	dbg("%s", __func__);
-
-	usb_deregister(&cypress_driver);
-	usb_serial_deregister(&cypress_earthmate_device);
-	usb_serial_deregister(&cypress_hidcom_device);
-	usb_serial_deregister(&cypress_ca42v2_device);
-}
-
-
-module_init(cypress_init);
-module_exit(cypress_exit);
+module_usb_serial_driver(cypress_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index b23bebd..999f91b 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -276,7 +276,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table_combined,
-	.no_dynamic_id = 	1,
 };
 
 
@@ -288,7 +287,6 @@
 		.name =			"digi_2",
 	},
 	.description =			"Digi 2 port USB adapter",
-	.usb_driver = 			&digi_driver,
 	.id_table =			id_table_2,
 	.num_ports =			3,
 	.open =				digi_open,
@@ -316,7 +314,6 @@
 		.name =			"digi_4",
 	},
 	.description =			"Digi 4 port USB adapter",
-	.usb_driver = 			&digi_driver,
 	.id_table =			id_table_4,
 	.num_ports =			4,
 	.open =				digi_open,
@@ -337,6 +334,9 @@
 	.release =			digi_release,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&digi_acceleport_2_device, &digi_acceleport_4_device, NULL
+};
 
 /* Functions */
 
@@ -995,7 +995,7 @@
 	/* return length of new data written, or error */
 	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
 	if (ret < 0)
-		dev_err(&port->dev,
+		dev_err_console(port,
 			"%s: usb_submit_urb failed, ret=%d, port=%d\n",
 			__func__, ret, priv->dp_port_num);
 	dbg("digi_write: returning %d", ret);
@@ -1065,7 +1065,7 @@
 
 	spin_unlock(&priv->dp_port_lock);
 	if (ret && ret != -EPERM)
-		dev_err(&port->dev,
+		dev_err_console(port,
 			"%s: usb_submit_urb failed, ret=%d, port=%d\n",
 			__func__, ret, priv->dp_port_num);
 }
@@ -1580,40 +1580,7 @@
 
 }
 
-static int __init digi_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&digi_acceleport_2_device);
-	if (retval)
-		goto failed_acceleport_2_device;
-	retval = usb_serial_register(&digi_acceleport_4_device);
-	if (retval)
-		goto failed_acceleport_4_device;
-	retval = usb_register(&digi_driver);
-	if (retval)
-		goto failed_usb_register;
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&digi_acceleport_4_device);
-failed_acceleport_4_device:
-	usb_serial_deregister(&digi_acceleport_2_device);
-failed_acceleport_2_device:
-	return retval;
-}
-
-static void __exit digi_exit (void)
-{
-	usb_deregister(&digi_driver);
-	usb_serial_deregister(&digi_acceleport_2_device);
-	usb_serial_deregister(&digi_acceleport_4_device);
-}
-
-
-module_init(digi_init);
-module_exit(digi_exit);
-
+module_usb_serial_driver(digi_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index aced681..5b99fc0 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -56,7 +56,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id =	1,
 };
 
 static struct usb_serial_driver empeg_device = {
@@ -65,7 +64,6 @@
 		.name =		"empeg",
 	},
 	.id_table =		id_table,
-	.usb_driver =		&empeg_driver,
 	.num_ports =		1,
 	.bulk_out_size =	256,
 	.throttle =		usb_serial_generic_throttle,
@@ -74,6 +72,10 @@
 	.init_termios =		empeg_init_termios,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&empeg_device, NULL
+};
+
 static int empeg_startup(struct usb_serial *serial)
 {
 	int r;
@@ -136,33 +138,7 @@
 	tty_encode_baud_rate(tty, 115200, 115200);
 }
 
-static int __init empeg_init(void)
-{
-	int retval;
-
-	retval = usb_serial_register(&empeg_device);
-	if (retval)
-		return retval;
-	retval = usb_register(&empeg_driver);
-	if (retval) {
-		usb_serial_deregister(&empeg_device);
-		return retval;
-	}
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-
-	return 0;
-}
-
-static void __exit empeg_exit(void)
-{
-	usb_deregister(&empeg_driver);
-	usb_serial_deregister(&empeg_device);
-}
-
-
-module_init(empeg_init);
-module_exit(empeg_exit);
+module_usb_serial_driver(empeg_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
new file mode 100644
index 0000000..88c0b19
--- /dev/null
+++ b/drivers/usb/serial/f81232.c
@@ -0,0 +1,405 @@
+/*
+ * Fintek F81232 USB to serial adaptor driver
+ *
+ * Copyright (C) 2012 Greg Kroah-Hartman (gregkh@linuxfoundation.org)
+ * Copyright (C) 2012 Linux Foundation
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+static bool debug;
+
+static const struct usb_device_id id_table[] = {
+	{ USB_DEVICE(0x1934, 0x0706) },
+	{ }					/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+#define CONTROL_DTR			0x01
+#define CONTROL_RTS			0x02
+
+#define UART_STATE			0x08
+#define UART_STATE_TRANSIENT_MASK	0x74
+#define UART_DCD			0x01
+#define UART_DSR			0x02
+#define UART_BREAK_ERROR		0x04
+#define UART_RING			0x08
+#define UART_FRAME_ERROR		0x10
+#define UART_PARITY_ERROR		0x20
+#define UART_OVERRUN_ERROR		0x40
+#define UART_CTS			0x80
+
+struct f81232_private {
+	spinlock_t lock;
+	wait_queue_head_t delta_msr_wait;
+	u8 line_control;
+	u8 line_status;
+};
+
+static void f81232_update_line_status(struct usb_serial_port *port,
+				      unsigned char *data,
+				      unsigned int actual_length)
+{
+}
+
+static void f81232_read_int_callback(struct urb *urb)
+{
+	struct usb_serial_port *port =  urb->context;
+	unsigned char *data = urb->transfer_buffer;
+	unsigned int actual_length = urb->actual_length;
+	int status = urb->status;
+	int retval;
+
+	dbg("%s (%d)", __func__, port->number);
+
+	switch (status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d", __func__,
+		    status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d", __func__,
+		    status);
+		goto exit;
+	}
+
+	usb_serial_debug_data(debug, &port->dev, __func__,
+			      urb->actual_length, urb->transfer_buffer);
+
+	f81232_update_line_status(port, data, actual_length);
+
+exit:
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		dev_err(&urb->dev->dev,
+			"%s - usb_submit_urb failed with result %d\n",
+			__func__, retval);
+}
+
+static void f81232_process_read_urb(struct urb *urb)
+{
+	struct usb_serial_port *port = urb->context;
+	struct f81232_private *priv = usb_get_serial_port_data(port);
+	struct tty_struct *tty;
+	unsigned char *data = urb->transfer_buffer;
+	char tty_flag = TTY_NORMAL;
+	unsigned long flags;
+	u8 line_status;
+	int i;
+
+	/* update line status */
+	spin_lock_irqsave(&priv->lock, flags);
+	line_status = priv->line_status;
+	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
+	spin_unlock_irqrestore(&priv->lock, flags);
+	wake_up_interruptible(&priv->delta_msr_wait);
+
+	if (!urb->actual_length)
+		return;
+
+	tty = tty_port_tty_get(&port->port);
+	if (!tty)
+		return;
+
+	/* break takes precedence over parity, */
+	/* which takes precedence over framing errors */
+	if (line_status & UART_BREAK_ERROR)
+		tty_flag = TTY_BREAK;
+	else if (line_status & UART_PARITY_ERROR)
+		tty_flag = TTY_PARITY;
+	else if (line_status & UART_FRAME_ERROR)
+		tty_flag = TTY_FRAME;
+	dbg("%s - tty_flag = %d", __func__, tty_flag);
+
+	/* overrun is special, not associated with a char */
+	if (line_status & UART_OVERRUN_ERROR)
+		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+	if (port->port.console && port->sysrq) {
+		for (i = 0; i < urb->actual_length; ++i)
+			if (!usb_serial_handle_sysrq_char(port, data[i]))
+				tty_insert_flip_char(tty, data[i], tty_flag);
+	} else {
+		tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
+							urb->actual_length);
+	}
+
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
+}
+
+static int set_control_lines(struct usb_device *dev, u8 value)
+{
+	/* FIXME - Stubbed out for now */
+	return 0;
+}
+
+static void f81232_break_ctl(struct tty_struct *tty, int break_state)
+{
+	/* FIXME - Stubbed out for now */
+
+	/*
+	 * break_state = -1 to turn on break, and 0 to turn off break
+	 * see drivers/char/tty_io.c to see it used.
+	 * last_set_data_urb_value NEVER has the break bit set in it.
+	 */
+}
+
+static void f81232_set_termios(struct tty_struct *tty,
+		struct usb_serial_port *port, struct ktermios *old_termios)
+{
+	/* FIXME - Stubbed out for now */
+
+	/* Don't change anything if nothing has changed */
+	if (!tty_termios_hw_change(tty->termios, old_termios))
+		return;
+
+	/* Do the real work here... */
+}
+
+static int f81232_tiocmget(struct tty_struct *tty)
+{
+	/* FIXME - Stubbed out for now */
+	return 0;
+}
+
+static int f81232_tiocmset(struct tty_struct *tty,
+			unsigned int set, unsigned int clear)
+{
+	/* FIXME - Stubbed out for now */
+	return 0;
+}
+
+static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+	struct ktermios tmp_termios;
+	int result;
+
+	/* Setup termios */
+	if (tty)
+		f81232_set_termios(tty, port, &tmp_termios);
+
+	dbg("%s - submitting interrupt urb", __func__);
+	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+	if (result) {
+		dev_err(&port->dev, "%s - failed submitting interrupt urb,"
+			" error %d\n", __func__, result);
+		return result;
+	}
+
+	result = usb_serial_generic_open(tty, port);
+	if (result) {
+		usb_kill_urb(port->interrupt_in_urb);
+		return result;
+	}
+
+	port->port.drain_delay = 256;
+	return 0;
+}
+
+static void f81232_close(struct usb_serial_port *port)
+{
+	usb_serial_generic_close(port);
+	usb_kill_urb(port->interrupt_in_urb);
+}
+
+static void f81232_dtr_rts(struct usb_serial_port *port, int on)
+{
+	struct f81232_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
+	u8 control;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	/* Change DTR and RTS */
+	if (on)
+		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
+	else
+		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
+	control = priv->line_control;
+	spin_unlock_irqrestore(&priv->lock, flags);
+	set_control_lines(port->serial->dev, control);
+}
+
+static int f81232_carrier_raised(struct usb_serial_port *port)
+{
+	struct f81232_private *priv = usb_get_serial_port_data(port);
+	if (priv->line_status & UART_DCD)
+		return 1;
+	return 0;
+}
+
+static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+{
+	struct f81232_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
+	unsigned int prevstatus;
+	unsigned int status;
+	unsigned int changed;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	prevstatus = priv->line_status;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	while (1) {
+		interruptible_sleep_on(&priv->delta_msr_wait);
+		/* see if a signal did it */
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+
+		spin_lock_irqsave(&priv->lock, flags);
+		status = priv->line_status;
+		spin_unlock_irqrestore(&priv->lock, flags);
+
+		changed = prevstatus ^ status;
+
+		if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
+		    ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
+		    ((arg & TIOCM_CD)  && (changed & UART_DCD)) ||
+		    ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
+			return 0;
+		}
+		prevstatus = status;
+	}
+	/* NOTREACHED */
+	return 0;
+}
+
+static int f81232_ioctl(struct tty_struct *tty,
+			unsigned int cmd, unsigned long arg)
+{
+	struct serial_struct ser;
+	struct usb_serial_port *port = tty->driver_data;
+	dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
+
+	switch (cmd) {
+	case TIOCGSERIAL:
+		memset(&ser, 0, sizeof ser);
+		ser.type = PORT_16654;
+		ser.line = port->serial->minor;
+		ser.port = port->number;
+		ser.baud_base = 460800;
+
+		if (copy_to_user((void __user *)arg, &ser, sizeof ser))
+			return -EFAULT;
+
+		return 0;
+
+	case TIOCMIWAIT:
+		dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
+		return wait_modem_info(port, arg);
+	default:
+		dbg("%s not supported = 0x%04x", __func__, cmd);
+		break;
+	}
+	return -ENOIOCTLCMD;
+}
+
+static int f81232_startup(struct usb_serial *serial)
+{
+	struct f81232_private *priv;
+	int i;
+
+	for (i = 0; i < serial->num_ports; ++i) {
+		priv = kzalloc(sizeof(struct f81232_private), GFP_KERNEL);
+		if (!priv)
+			goto cleanup;
+		spin_lock_init(&priv->lock);
+		init_waitqueue_head(&priv->delta_msr_wait);
+		usb_set_serial_port_data(serial->port[i], priv);
+	}
+	return 0;
+
+cleanup:
+	for (--i; i >= 0; --i) {
+		priv = usb_get_serial_port_data(serial->port[i]);
+		kfree(priv);
+		usb_set_serial_port_data(serial->port[i], NULL);
+	}
+	return -ENOMEM;
+}
+
+static void f81232_release(struct usb_serial *serial)
+{
+	int i;
+	struct f81232_private *priv;
+
+	for (i = 0; i < serial->num_ports; ++i) {
+		priv = usb_get_serial_port_data(serial->port[i]);
+		kfree(priv);
+	}
+}
+
+static struct usb_driver f81232_driver = {
+	.name =		"f81232",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	id_table,
+	.suspend =      usb_serial_suspend,
+	.resume =       usb_serial_resume,
+	.no_dynamic_id = 	1,
+	.supports_autosuspend =	1,
+};
+
+static struct usb_serial_driver f81232_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"f81232",
+	},
+	.id_table =		id_table,
+	.usb_driver = 		&f81232_driver,
+	.num_ports =		1,
+	.bulk_in_size =		256,
+	.bulk_out_size =	256,
+	.open =			f81232_open,
+	.close =		f81232_close,
+	.dtr_rts = 		f81232_dtr_rts,
+	.carrier_raised =	f81232_carrier_raised,
+	.ioctl =		f81232_ioctl,
+	.break_ctl =		f81232_break_ctl,
+	.set_termios =		f81232_set_termios,
+	.tiocmget =		f81232_tiocmget,
+	.tiocmset =		f81232_tiocmset,
+	.process_read_urb =	f81232_process_read_urb,
+	.read_int_callback =	f81232_read_int_callback,
+	.attach =		f81232_startup,
+	.release =		f81232_release,
+};
+
+static struct usb_serial_driver * const serial_drivers[] = {
+	&f81232_device,
+	NULL,
+};
+
+module_usb_serial_driver(f81232_driver, serial_drivers);
+
+MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
+MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org");
+MODULE_LICENSE("GPL v2");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index f770415..7c229d3 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -188,6 +188,7 @@
 		.driver_info = (kernel_ulong_t)&ftdi_8u2232c_quirk },
 	{ USB_DEVICE(FTDI_VID, FTDI_4232H_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_232H_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_FTX_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) },
@@ -536,6 +537,10 @@
 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_6_PID) },
 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) },
 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) },
+	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_1_PID) },
+	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_2_PID) },
+	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_3_PID) },
+	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_4_PID) },
 	{ USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) },
 	{ USB_DEVICE(OCT_VID, OCT_US101_PID) },
 	{ USB_DEVICE(OCT_VID, OCT_DK201_PID) },
@@ -797,7 +802,7 @@
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	{ USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
-	{ USB_DEVICE(HORNBY_VID, HORNBY_ELITE_PID) },
+	{ USB_DEVICE(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID) },
 	{ USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
 	{ USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
@@ -846,6 +851,9 @@
 	{ USB_DEVICE(ST_VID, ST_STMCLT1030_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk },
 	{ USB_DEVICE(FTDI_VID, FTDI_RF_R106) },
+	{ USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID),
+		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+	{ USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) },
 	{ },					/* Optional parameter entry */
 	{ }					/* Terminating entry */
 };
@@ -857,7 +865,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table_combined,
-	.no_dynamic_id =	1,
 };
 
 static const char *ftdi_chip_name[] = {
@@ -868,7 +875,8 @@
 	[FT232RL] = "FT232RL",
 	[FT2232H] = "FT2232H",
 	[FT4232H] = "FT4232H",
-	[FT232H]  = "FT232H"
+	[FT232H]  = "FT232H",
+	[FTX]     = "FT-X"
 };
 
 
@@ -915,7 +923,6 @@
 		.name =		"ftdi_sio",
 	},
 	.description =		"FTDI USB Serial Device",
-	.usb_driver = 		&ftdi_driver,
 	.id_table =		id_table_combined,
 	.num_ports =		1,
 	.bulk_in_size =		512,
@@ -938,6 +945,10 @@
 	.break_ctl =		ftdi_break_ctl,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&ftdi_sio_device, NULL
+};
+
 
 #define WDR_TIMEOUT 5000 /* default urb timeout */
 #define WDR_SHORT_TIMEOUT 1000	/* shorter urb timeout */
@@ -1169,7 +1180,8 @@
 		break;
 	case FT232BM: /* FT232BM chip */
 	case FT2232C: /* FT2232C chip */
-	case FT232RL:
+	case FT232RL: /* FT232RL chip */
+	case FTX:     /* FT-X series */
 		if (baud <= 3000000) {
 			__u16 product_id = le16_to_cpu(
 				port->serial->dev->descriptor.idProduct);
@@ -1458,10 +1470,14 @@
 	} else if (version < 0x900) {
 		/* Assume it's an FT232RL */
 		priv->chip_type = FT232RL;
-	} else {
+	} else if (version < 0x1000) {
 		/* Assume it's an FT232H */
 		priv->chip_type = FT232H;
+	} else {
+		/* Assume it's an FT-X series device */
+		priv->chip_type = FTX;
 	}
+
 	dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]);
 }
 
@@ -1589,7 +1605,8 @@
 		     priv->chip_type == FT232RL ||
 		     priv->chip_type == FT2232H ||
 		     priv->chip_type == FT4232H ||
-		     priv->chip_type == FT232H)) {
+		     priv->chip_type == FT232H ||
+		     priv->chip_type == FTX)) {
 			retval = device_create_file(&port->dev,
 						    &dev_attr_latency_timer);
 		}
@@ -1611,7 +1628,8 @@
 		    priv->chip_type == FT232RL ||
 		    priv->chip_type == FT2232H ||
 		    priv->chip_type == FT4232H ||
-                    priv->chip_type == FT232H) {
+		    priv->chip_type == FT232H ||
+		    priv->chip_type == FTX) {
 			device_remove_file(&port->dev, &dev_attr_latency_timer);
 		}
 	}
@@ -1763,7 +1781,8 @@
 
 	dbg("%s", __func__);
 
-	if (strcmp(udev->manufacturer, "CALAO Systems") == 0)
+	if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) ||
+	    (udev->product && !strcmp(udev->product, "BeagleBone/XDS100")))
 		return ftdi_jtag_probe(serial);
 
 	return 0;
@@ -2288,6 +2307,7 @@
 	case FT2232H:
 	case FT4232H:
 	case FT232H:
+	case FTX:
 		len = 2;
 		break;
 	default:
@@ -2420,19 +2440,10 @@
 		id_table_combined[i].idVendor = vendor;
 		id_table_combined[i].idProduct = product;
 	}
-	retval = usb_serial_register(&ftdi_sio_device);
-	if (retval)
-		goto failed_sio_register;
-	retval = usb_register(&ftdi_driver);
-	if (retval)
-		goto failed_usb_register;
-
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&ftdi_sio_device);
-failed_sio_register:
+	retval = usb_serial_register_drivers(&ftdi_driver, serial_drivers);
+	if (retval == 0)
+		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+			       DRIVER_DESC "\n");
 	return retval;
 }
 
@@ -2440,8 +2451,7 @@
 {
 	dbg("%s", __func__);
 
-	usb_deregister(&ftdi_driver);
-	usb_serial_deregister(&ftdi_sio_device);
+	usb_serial_deregister_drivers(&ftdi_driver, serial_drivers);
 }
 
 
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 19584fa..ed58c6f 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -157,7 +157,8 @@
 	FT232RL = 5,
 	FT2232H = 6,
 	FT4232H = 7,
-	FT232H  = 8
+	FT232H  = 8,
+	FTX     = 9,
 };
 
 enum ftdi_sio_baudrate {
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 6f6058f..0838baf8 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -23,12 +23,15 @@
 #define FTDI_8U2232C_PID 0x6010 /* Dual channel device */
 #define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */
 #define FTDI_232H_PID  0x6014 /* Single channel hi-speed device */
+#define FTDI_FTX_PID   0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */
 #define FTDI_SIO_PID	0x8372	/* Product Id SIO application of 8U100AX */
 #define FTDI_232RL_PID  0xFBFA  /* Product ID for FT232RL */
 
 
 /*** third-party PIDs (using FTDI_VID) ***/
 
+#define FTDI_LUMEL_PD12_PID	0x6002
+
 /*
  * Marvell OpenRD Base, Client
  * http://www.open-rd.org
@@ -97,6 +100,8 @@
 #define FTDI_TACTRIX_OPENPORT_13S_PID	0xCC49	/* OpenPort 1.3 Subaru */
 #define FTDI_TACTRIX_OPENPORT_13U_PID	0xCC4A	/* OpenPort 1.3 Universal */
 
+#define FTDI_DISTORTEC_JTAG_LOCK_PICK_PID	0xCFF8
+
 /* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */
 /* the VID is the standard ftdi vid (FTDI_VID) */
 #define FTDI_SCS_DEVICE_0_PID 0xD010    /* SCS PTC-IIusb */
@@ -532,10 +537,14 @@
 #define ADI_GNICEPLUS_PID	0xF001
 
 /*
- * Hornby Elite
+ * Microchip Technology, Inc.
+ *
+ * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are also used by:
+ * Hornby Elite - Digital Command Control Console
+ * http://www.hornby.com/hornby-dcc/controllers/
  */
-#define HORNBY_VID		0x04D8
-#define HORNBY_ELITE_PID	0x000A
+#define MICROCHIP_VID		0x04D8
+#define MICROCHIP_USB_BOARD_PID	0x000A /* CDC RS-232 Emulation Demo */
 
 /*
  * RATOC REX-USB60F
@@ -680,6 +689,10 @@
 #define SEALEVEL_2803_6_PID	0X2863	/* SeaLINK+8 (2803) Port 6 */
 #define SEALEVEL_2803_7_PID	0X2873	/* SeaLINK+8 (2803) Port 7 */
 #define SEALEVEL_2803_8_PID	0X2883	/* SeaLINK+8 (2803) Port 8 */
+#define SEALEVEL_2803R_1_PID	0Xa02a	/* SeaLINK+8 (2803-ROHS) Port 1+2 */
+#define SEALEVEL_2803R_2_PID	0Xa02b	/* SeaLINK+8 (2803-ROHS) Port 3+4 */
+#define SEALEVEL_2803R_3_PID	0Xa02c	/* SeaLINK+8 (2803-ROHS) Port 5+6 */
+#define SEALEVEL_2803R_4_PID	0Xa02d	/* SeaLINK+8 (2803-ROHS) Port 7+8 */
 
 /*
  * JETI SPECTROMETER SPECBOS 1201
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 5d4b099..4577b36 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -29,7 +29,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id = 	1,
 };
 
 static struct usb_serial_driver funsoft_device = {
@@ -38,31 +37,15 @@
 		.name =		"funsoft",
 	},
 	.id_table =		id_table,
-	.usb_driver = 		&funsoft_driver,
 	.num_ports =		1,
 };
 
-static int __init funsoft_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&funsoft_device, NULL
+};
 
-	retval = usb_serial_register(&funsoft_device);
-	if (retval)
-		return retval;
-	retval = usb_register(&funsoft_driver);
-	if (retval)
-		usb_serial_deregister(&funsoft_device);
-	return retval;
-}
+module_usb_serial_driver(funsoft_driver, serial_drivers);
 
-static void __exit funsoft_exit(void)
-{
-	usb_deregister(&funsoft_driver);
-	usb_serial_deregister(&funsoft_device);
-}
-
-module_init(funsoft_init);
-module_exit(funsoft_exit);
 MODULE_LICENSE("GPL");
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 2134337..e8eb634 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -224,7 +224,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id = 1,
 };
 
 
@@ -1497,7 +1496,6 @@
 		.name        = "garmin_gps",
 	},
 	.description         = "Garmin GPS usb/tty",
-	.usb_driver          = &garmin_driver,
 	.id_table            = id_table,
 	.num_ports           = 1,
 	.open                = garmin_open,
@@ -1514,40 +1512,11 @@
 	.read_int_callback   = garmin_read_int_callback,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&garmin_device, NULL
+};
 
-
-static int __init garmin_init(void)
-{
-	int retval;
-
-	retval = usb_serial_register(&garmin_device);
-	if (retval)
-		goto failed_garmin_register;
-	retval = usb_register(&garmin_driver);
-	if (retval)
-		goto failed_usb_register;
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&garmin_device);
-failed_garmin_register:
-	return retval;
-}
-
-
-static void __exit garmin_exit(void)
-{
-	usb_deregister(&garmin_driver);
-	usb_serial_deregister(&garmin_device);
-}
-
-
-
-
-module_init(garmin_init);
-module_exit(garmin_exit);
+module_usb_serial_driver(garmin_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -1557,4 +1526,3 @@
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 module_param(initial_mode, int, S_IRUGO);
 MODULE_PARM_DESC(initial_mode, "Initial mode");
-
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index f740357..664deb6 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -54,7 +54,6 @@
 	.probe =	generic_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	generic_serial_ids,
-	.no_dynamic_id =	1,
 };
 
 /* All of the device info needed for the Generic Serial Converter */
@@ -64,7 +63,6 @@
 		.name =		"generic",
 	},
 	.id_table =		generic_device_ids,
-	.usb_driver = 		&generic_driver,
 	.num_ports =		1,
 	.disconnect =		usb_serial_generic_disconnect,
 	.release =		usb_serial_generic_release,
@@ -73,6 +71,10 @@
 	.resume =		usb_serial_generic_resume,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&usb_serial_generic_device, NULL
+};
+
 static int generic_probe(struct usb_interface *interface,
 			       const struct usb_device_id *id)
 {
@@ -97,13 +99,7 @@
 		USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT;
 
 	/* register our generic driver with ourselves */
-	retval = usb_serial_register(&usb_serial_generic_device);
-	if (retval)
-		goto exit;
-	retval = usb_register(&generic_driver);
-	if (retval)
-		usb_serial_deregister(&usb_serial_generic_device);
-exit:
+	retval = usb_serial_register_drivers(&generic_driver, serial_drivers);
 #endif
 	return retval;
 }
@@ -112,8 +108,7 @@
 {
 #ifdef CONFIG_USB_SERIAL_GENERIC
 	/* remove our generic driver */
-	usb_deregister(&generic_driver);
-	usb_serial_deregister(&usb_serial_generic_device);
+	usb_serial_deregister_drivers(&generic_driver, serial_drivers);
 #endif
 }
 
@@ -217,7 +212,7 @@
 	clear_bit(i, &port->write_urbs_free);
 	result = usb_submit_urb(urb, GFP_ATOMIC);
 	if (result) {
-		dev_err(&port->dev, "%s - error submitting urb: %d\n",
+		dev_err_console(port, "%s - error submitting urb: %d\n",
 						__func__, result);
 		set_bit(i, &port->write_urbs_free);
 		spin_lock_irqsave(&port->lock, flags);
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
index 8093791..2563e78 100644
--- a/drivers/usb/serial/hp4x.c
+++ b/drivers/usb/serial/hp4x.c
@@ -41,7 +41,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id = 	1,
 };
 
 static struct usb_serial_driver hp49gp_device = {
@@ -50,36 +49,14 @@
 		.name =		"hp4X",
 	},
 	.id_table =		id_table,
-	.usb_driver = 		&hp49gp_driver,
 	.num_ports =		1,
 };
 
-static int __init hp49gp_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&hp49gp_device);
-	if (retval)
-		goto failed_usb_serial_register;
-	retval = usb_register(&hp49gp_driver);
-	if (retval)
-		goto failed_usb_register;
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&hp49gp_device);
-failed_usb_serial_register:
-	return retval;
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+	&hp49gp_device, NULL
+};
 
-static void __exit hp49gp_exit(void)
-{
-	usb_deregister(&hp49gp_driver);
-	usb_serial_deregister(&hp49gp_device);
-}
-
-module_init(hp49gp_init);
-module_exit(hp49gp_exit);
+module_usb_serial_driver(hp49gp_driver, serial_drivers);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 0497575..323e872 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -193,7 +193,8 @@
 /* local variables */
 static bool debug;
 
-static atomic_t CmdUrbs;	/* Number of outstanding Command Write Urbs */
+/* Number of outstanding Command Write Urbs */
+static atomic_t CmdUrbs = ATOMIC_INIT(0);
 
 
 /* local function prototypes */
@@ -1286,7 +1287,7 @@
 	count = fifo->count;
 	buffer = kmalloc(count+2, GFP_ATOMIC);
 	if (buffer == NULL) {
-		dev_err(&edge_port->port->dev,
+		dev_err_console(edge_port->port,
 				"%s - no more kernel memory...\n", __func__);
 		edge_port->write_in_progress = false;
 		goto exit_send;
@@ -1331,7 +1332,7 @@
 	status = usb_submit_urb(urb, GFP_ATOMIC);
 	if (status) {
 		/* something went wrong */
-		dev_err(&edge_port->port->dev,
+		dev_err_console(edge_port->port,
 			"%s - usb_submit_urb(write bulk) failed, status = %d, data lost\n",
 				__func__, status);
 		edge_port->write_in_progress = false;
@@ -3180,65 +3181,8 @@
 	kfree(edge_serial);
 }
 
+module_usb_serial_driver(io_driver, serial_drivers);
 
-/****************************************************************************
- * edgeport_init
- *	This is called by the module subsystem, or on startup to initialize us
- ****************************************************************************/
-static int __init edgeport_init(void)
-{
-	int retval;
-
-	retval = usb_serial_register(&edgeport_2port_device);
-	if (retval)
-		goto failed_2port_device_register;
-	retval = usb_serial_register(&edgeport_4port_device);
-	if (retval)
-		goto failed_4port_device_register;
-	retval = usb_serial_register(&edgeport_8port_device);
-	if (retval)
-		goto failed_8port_device_register;
-	retval = usb_serial_register(&epic_device);
-	if (retval)
-		goto failed_epic_device_register;
-	retval = usb_register(&io_driver);
-	if (retval)
-		goto failed_usb_register;
-	atomic_set(&CmdUrbs, 0);
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-
-failed_usb_register:
-	usb_serial_deregister(&epic_device);
-failed_epic_device_register:
-	usb_serial_deregister(&edgeport_8port_device);
-failed_8port_device_register:
-	usb_serial_deregister(&edgeport_4port_device);
-failed_4port_device_register:
-	usb_serial_deregister(&edgeport_2port_device);
-failed_2port_device_register:
-	return retval;
-}
-
-
-/****************************************************************************
- * edgeport_exit
- *	Called when the driver is about to be unloaded.
- ****************************************************************************/
-static void __exit edgeport_exit (void)
-{
-	usb_deregister(&io_driver);
-	usb_serial_deregister(&edgeport_2port_device);
-	usb_serial_deregister(&edgeport_4port_device);
-	usb_serial_deregister(&edgeport_8port_device);
-	usb_serial_deregister(&epic_device);
-}
-
-module_init(edgeport_init);
-module_exit(edgeport_exit);
-
-/* Module information */
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index 178b22e..d0e7c9a 100644
--- a/drivers/usb/serial/io_tables.h
+++ b/drivers/usb/serial/io_tables.h
@@ -100,7 +100,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table_combined,
-	.no_dynamic_id = 	1,
 };
 
 static struct usb_serial_driver edgeport_2port_device = {
@@ -109,7 +108,6 @@
 		.name		= "edgeport_2",
 	},
 	.description		= "Edgeport 2 port adapter",
-	.usb_driver		= &io_driver,
 	.id_table		= edgeport_2port_id_table,
 	.num_ports		= 2,
 	.open			= edge_open,
@@ -139,7 +137,6 @@
 		.name		= "edgeport_4",
 	},
 	.description		= "Edgeport 4 port adapter",
-	.usb_driver		= &io_driver,
 	.id_table		= edgeport_4port_id_table,
 	.num_ports		= 4,
 	.open			= edge_open,
@@ -169,7 +166,6 @@
 		.name		= "edgeport_8",
 	},
 	.description		= "Edgeport 8 port adapter",
-	.usb_driver		= &io_driver,
 	.id_table		= edgeport_8port_id_table,
 	.num_ports		= 8,
 	.open			= edge_open,
@@ -199,7 +195,6 @@
 		.name		= "epic",
 	},
 	.description		= "EPiC device",
-	.usb_driver		= &io_driver,
 	.id_table		= Epic_port_id_table,
 	.num_ports		= 1,
 	.open			= edge_open,
@@ -223,5 +218,10 @@
 	.write_bulk_callback	= edge_bulk_out_data_callback,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&edgeport_2port_device, &edgeport_4port_device,
+	&edgeport_8port_device, &epic_device, NULL
+};
+
 #endif
 
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 5818bfc..40a95a7 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -202,7 +202,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table_combined,
-	.no_dynamic_id = 	1,
 };
 
 
@@ -1817,7 +1816,7 @@
 		    __func__, status);
 		return;
 	default:
-		dev_err(&urb->dev->dev, "%s - nonzero write bulk status "
+		dev_err_console(port, "%s - nonzero write bulk status "
 			"received: %d\n", __func__, status);
 	}
 
@@ -2111,7 +2110,7 @@
 	/* send the data out the bulk port */
 	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
 	if (result) {
-		dev_err(&port->dev,
+		dev_err_console(port,
 			"%s - failed submitting write urb, error %d\n",
 				__func__, result);
 		edge_port->ep_write_urb_in_use = 0;
@@ -2725,7 +2724,6 @@
 		.name		= "edgeport_ti_1",
 	},
 	.description		= "Edgeport TI 1 port adapter",
-	.usb_driver		= &io_driver,
 	.id_table		= edgeport_1port_id_table,
 	.num_ports		= 1,
 	.open			= edge_open,
@@ -2757,7 +2755,6 @@
 		.name		= "edgeport_ti_2",
 	},
 	.description		= "Edgeport TI 2 port adapter",
-	.usb_driver		= &io_driver,
 	.id_table		= edgeport_2port_id_table,
 	.num_ports		= 2,
 	.open			= edge_open,
@@ -2782,41 +2779,12 @@
 	.write_bulk_callback	= edge_bulk_out_callback,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&edgeport_1port_device, &edgeport_2port_device, NULL
+};
 
-static int __init edgeport_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&edgeport_1port_device);
-	if (retval)
-		goto failed_1port_device_register;
-	retval = usb_serial_register(&edgeport_2port_device);
-	if (retval)
-		goto failed_2port_device_register;
-	retval = usb_register(&io_driver);
-	if (retval)
-		goto failed_usb_register;
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&edgeport_2port_device);
-failed_2port_device_register:
-	usb_serial_deregister(&edgeport_1port_device);
-failed_1port_device_register:
-	return retval;
-}
+module_usb_serial_driver(io_driver, serial_drivers);
 
-static void __exit edgeport_exit(void)
-{
-	usb_deregister(&io_driver);
-	usb_serial_deregister(&edgeport_1port_device);
-	usb_serial_deregister(&edgeport_2port_device);
-}
-
-module_init(edgeport_init);
-module_exit(edgeport_exit);
-
-/* Module information */
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 06053a9..10c02b8 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -510,7 +510,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	ipaq_id_table,
-	.no_dynamic_id =	1,
 };
 
 
@@ -521,7 +520,6 @@
 		.name =		"ipaq",
 	},
 	.description =		"PocketPC PDA",
-	.usb_driver =		&ipaq_driver,
 	.id_table =		ipaq_id_table,
 	.bulk_in_size =		256,
 	.bulk_out_size =	256,
@@ -530,6 +528,10 @@
 	.calc_num_ports =	ipaq_calc_num_ports,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&ipaq_device, NULL
+};
+
 static int ipaq_open(struct tty_struct *tty,
 			struct usb_serial_port *port)
 {
@@ -624,30 +626,22 @@
 static int __init ipaq_init(void)
 {
 	int retval;
-	retval = usb_serial_register(&ipaq_device);
-	if (retval)
-		goto failed_usb_serial_register;
+
 	if (vendor) {
 		ipaq_id_table[0].idVendor = vendor;
 		ipaq_id_table[0].idProduct = product;
 	}
-	retval = usb_register(&ipaq_driver);
-	if (retval)
-		goto failed_usb_register;
 
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&ipaq_device);
-failed_usb_serial_register:
+	retval = usb_serial_register_drivers(&ipaq_driver, serial_drivers);
+	if (retval == 0)
+		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+			       DRIVER_DESC "\n");
 	return retval;
 }
 
 static void __exit ipaq_exit(void)
 {
-	usb_deregister(&ipaq_driver);
-	usb_serial_deregister(&ipaq_device);
+	usb_serial_deregister_drivers(&ipaq_driver, serial_drivers);
 }
 
 
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 6f9356f3..76a0640 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -144,7 +144,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	usb_ipw_ids,
-	.no_dynamic_id = 	1,
 };
 
 static bool debug;
@@ -318,7 +317,6 @@
 		.name =		"ipw",
 	},
 	.description =		"IPWireless converter",
-	.usb_driver =		&usb_ipw_driver,
 	.id_table =		usb_ipw_ids,
 	.num_ports =		1,
 	.disconnect =		usb_wwan_disconnect,
@@ -331,33 +329,11 @@
 	.write =		usb_wwan_write,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&ipw_device, NULL
+};
 
-
-static int __init usb_ipw_init(void)
-{
-	int retval;
-
-	retval = usb_serial_register(&ipw_device);
-	if (retval)
-		return retval;
-	retval = usb_register(&usb_ipw_driver);
-	if (retval) {
-		usb_serial_deregister(&ipw_device);
-		return retval;
-	}
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-}
-
-static void __exit usb_ipw_exit(void)
-{
-	usb_deregister(&usb_ipw_driver);
-	usb_serial_deregister(&ipw_device);
-}
-
-module_init(usb_ipw_init);
-module_exit(usb_ipw_exit);
+module_usb_serial_driver(usb_ipw_driver, serial_drivers);
 
 /* Module information */
 MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 84a396e..84965cd 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -82,7 +82,6 @@
 	.probe		= usb_serial_probe,
 	.disconnect	= usb_serial_disconnect,
 	.id_table	= ir_id_table,
-	.no_dynamic_id	= 1,
 };
 
 static struct usb_serial_driver ir_device = {
@@ -91,7 +90,6 @@
 		.name	= "ir-usb",
 	},
 	.description		= "IR Dongle",
-	.usb_driver		= &ir_driver,
 	.id_table		= ir_id_table,
 	.num_ports		= 1,
 	.set_termios		= ir_set_termios,
@@ -101,6 +99,10 @@
 	.process_read_urb	= ir_process_read_urb,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&ir_device, NULL
+};
+
 static inline void irda_usb_dump_class_desc(struct usb_irda_cs_descriptor *desc)
 {
 	dbg("bLength=%x", desc->bLength);
@@ -445,30 +447,16 @@
 		ir_device.bulk_out_size = buffer_size;
 	}
 
-	retval = usb_serial_register(&ir_device);
-	if (retval)
-		goto failed_usb_serial_register;
-
-	retval = usb_register(&ir_driver);
-	if (retval)
-		goto failed_usb_register;
-
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-
-	return 0;
-
-failed_usb_register:
-	usb_serial_deregister(&ir_device);
-
-failed_usb_serial_register:
+	retval = usb_serial_register_drivers(&ir_driver, serial_drivers);
+	if (retval == 0)
+		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+			       DRIVER_DESC "\n");
 	return retval;
 }
 
 static void __exit ir_exit(void)
 {
-	usb_deregister(&ir_driver);
-	usb_serial_deregister(&ir_device);
+	usb_serial_deregister_drivers(&ir_driver, serial_drivers);
 }
 
 
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 3077a44..f2192d5 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -56,7 +56,6 @@
 	.probe = usb_serial_probe,
 	.disconnect = usb_serial_disconnect,
 	.id_table = id_table,
-	.no_dynamic_id = 1,
 };
 
 /* turbo parameter */
@@ -1274,7 +1273,6 @@
 		   .name = "iuu_phoenix",
 		   },
 	.id_table = id_table,
-	.usb_driver = &iuu_driver,
 	.num_ports = 1,
 	.bulk_in_size = 512,
 	.bulk_out_size = 512,
@@ -1292,32 +1290,11 @@
 	.release = iuu_release,
 };
 
-static int __init iuu_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&iuu_device);
-	if (retval)
-		goto failed_usb_serial_register;
-	retval = usb_register(&iuu_driver);
-	if (retval)
-		goto failed_usb_register;
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&iuu_device);
-failed_usb_serial_register:
-	return retval;
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+	&iuu_device, NULL
+};
 
-static void __exit iuu_exit(void)
-{
-	usb_deregister(&iuu_driver);
-	usb_serial_deregister(&iuu_device);
-}
-
-module_init(iuu_init);
-module_exit(iuu_exit);
+module_usb_serial_driver(iuu_driver, serial_drivers);
 
 MODULE_AUTHOR("Alain Degreffe eczema@ecze.com");
 
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 4cc36c7..a39ddd1 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -130,53 +130,7 @@
 #include "keyspan_usa67msg.h"
 
 
-/* Functions used by new usb-serial code. */
-static int __init keyspan_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&keyspan_pre_device);
-	if (retval)
-		goto failed_pre_device_register;
-	retval = usb_serial_register(&keyspan_1port_device);
-	if (retval)
-		goto failed_1port_device_register;
-	retval = usb_serial_register(&keyspan_2port_device);
-	if (retval)
-		goto failed_2port_device_register;
-	retval = usb_serial_register(&keyspan_4port_device);
-	if (retval)
-		goto failed_4port_device_register;
-	retval = usb_register(&keyspan_driver);
-	if (retval)
-		goto failed_usb_register;
-
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&keyspan_4port_device);
-failed_4port_device_register:
-	usb_serial_deregister(&keyspan_2port_device);
-failed_2port_device_register:
-	usb_serial_deregister(&keyspan_1port_device);
-failed_1port_device_register:
-	usb_serial_deregister(&keyspan_pre_device);
-failed_pre_device_register:
-	return retval;
-}
-
-static void __exit keyspan_exit(void)
-{
-	usb_deregister(&keyspan_driver);
-	usb_serial_deregister(&keyspan_pre_device);
-	usb_serial_deregister(&keyspan_1port_device);
-	usb_serial_deregister(&keyspan_2port_device);
-	usb_serial_deregister(&keyspan_4port_device);
-}
-
-module_init(keyspan_init);
-module_exit(keyspan_exit);
+module_usb_serial_driver(keyspan_driver, serial_drivers);
 
 static void keyspan_break_ctl(struct tty_struct *tty, int break_state)
 {
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index 13fa1d1..622853c 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -492,7 +492,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	keyspan_ids_combined,
-	.no_dynamic_id = 	1,
 };
 
 /* usb_device_id table for the pre-firmware download keyspan devices */
@@ -545,7 +544,6 @@
 		.name		= "keyspan_no_firm",
 	},
 	.description		= "Keyspan - (without firmware)",
-	.usb_driver		= &keyspan_driver,
 	.id_table		= keyspan_pre_ids,
 	.num_ports		= 1,
 	.attach			= keyspan_fake_startup,
@@ -557,7 +555,6 @@
 		.name		= "keyspan_1",
 	},
 	.description		= "Keyspan 1 port adapter",
-	.usb_driver		= &keyspan_driver,
 	.id_table		= keyspan_1port_ids,
 	.num_ports		= 1,
 	.open			= keyspan_open,
@@ -580,7 +577,6 @@
 		.name		= "keyspan_2",
 	},
 	.description		= "Keyspan 2 port adapter",
-	.usb_driver		= &keyspan_driver,
 	.id_table		= keyspan_2port_ids,
 	.num_ports		= 2,
 	.open			= keyspan_open,
@@ -603,7 +599,6 @@
 		.name		= "keyspan_4",
 	},
 	.description		= "Keyspan 4 port adapter",
-	.usb_driver		= &keyspan_driver,
 	.id_table		= keyspan_4port_ids,
 	.num_ports		= 4,
 	.open			= keyspan_open,
@@ -620,4 +615,9 @@
 	.release		= keyspan_release,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&keyspan_pre_device, &keyspan_1port_device,
+	&keyspan_2port_device, &keyspan_4port_device, NULL
+};
+
 #endif
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 7c62a70..693bcdf 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -91,7 +91,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table_combined,
-	.no_dynamic_id = 	1,
 };
 
 static const struct usb_device_id id_table_std[] = {
@@ -779,7 +778,6 @@
 		.name =		"keyspan_pda_pre",
 	},
 	.description =		"Keyspan PDA - (prerenumeration)",
-	.usb_driver = 		&keyspan_pda_driver,
 	.id_table =		id_table_fake,
 	.num_ports =		1,
 	.attach =		keyspan_pda_fake_startup,
@@ -793,7 +791,6 @@
 		.name =		"xircom_no_firm",
 	},
 	.description =		"Xircom / Entregra PGS - (prerenumeration)",
-	.usb_driver = 		&keyspan_pda_driver,
 	.id_table =		id_table_fake_xircom,
 	.num_ports =		1,
 	.attach =		keyspan_pda_fake_startup,
@@ -806,7 +803,6 @@
 		.name =		"keyspan_pda",
 	},
 	.description =		"Keyspan PDA",
-	.usb_driver = 		&keyspan_pda_driver,
 	.id_table =		id_table_std,
 	.num_ports =		1,
 	.dtr_rts =		keyspan_pda_dtr_rts,
@@ -827,61 +823,18 @@
 	.release =		keyspan_pda_release,
 };
 
-
-static int __init keyspan_pda_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&keyspan_pda_device);
-	if (retval)
-		goto failed_pda_register;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&keyspan_pda_device,
 #ifdef KEYSPAN
-	retval = usb_serial_register(&keyspan_pda_fake_device);
-	if (retval)
-		goto failed_pda_fake_register;
+	&keyspan_pda_fake_device,
 #endif
 #ifdef XIRCOM
-	retval = usb_serial_register(&xircom_pgs_fake_device);
-	if (retval)
-		goto failed_xircom_register;
+	&xircom_pgs_fake_device,
 #endif
-	retval = usb_register(&keyspan_pda_driver);
-	if (retval)
-		goto failed_usb_register;
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-failed_usb_register:
-#ifdef XIRCOM
-	usb_serial_deregister(&xircom_pgs_fake_device);
-failed_xircom_register:
-#endif /* XIRCOM */
-#ifdef KEYSPAN
-	usb_serial_deregister(&keyspan_pda_fake_device);
-#endif
-#ifdef KEYSPAN
-failed_pda_fake_register:
-#endif
-	usb_serial_deregister(&keyspan_pda_device);
-failed_pda_register:
-	return retval;
-}
+	NULL
+};
 
-
-static void __exit keyspan_pda_exit(void)
-{
-	usb_deregister(&keyspan_pda_driver);
-	usb_serial_deregister(&keyspan_pda_device);
-#ifdef KEYSPAN
-	usb_serial_deregister(&keyspan_pda_fake_device);
-#endif
-#ifdef XIRCOM
-	usb_serial_deregister(&xircom_pgs_fake_device);
-#endif
-}
-
-
-module_init(keyspan_pda_init);
-module_exit(keyspan_pda_exit);
+module_usb_serial_driver(keyspan_pda_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -889,4 +842,3 @@
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
-
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index fc064e1..10f0540 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -91,7 +91,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id =	1,
 };
 
 static struct usb_serial_driver kl5kusb105d_device = {
@@ -100,7 +99,6 @@
 		.name =		"kl5kusb105d",
 	},
 	.description =		"KL5KUSB105D / PalmConnect",
-	.usb_driver =		&kl5kusb105d_driver,
 	.id_table =		id_table,
 	.num_ports =		1,
 	.bulk_out_size =	64,
@@ -118,6 +116,10 @@
 	.prepare_write_buffer =	klsi_105_prepare_write_buffer,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&kl5kusb105d_device, NULL
+};
+
 struct klsi_105_port_settings {
 	__u8	pktlen;		/* always 5, it seems */
 	__u8	baudrate;
@@ -690,40 +692,11 @@
 	return retval;
 }
 
-
-static int __init klsi_105_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&kl5kusb105d_device);
-	if (retval)
-		goto failed_usb_serial_register;
-	retval = usb_register(&kl5kusb105d_driver);
-	if (retval)
-		goto failed_usb_register;
-
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&kl5kusb105d_device);
-failed_usb_serial_register:
-	return retval;
-}
-
-static void __exit klsi_105_exit(void)
-{
-	usb_deregister(&kl5kusb105d_driver);
-	usb_serial_deregister(&kl5kusb105d_device);
-}
-
-
-module_init(klsi_105_init);
-module_exit(klsi_105_exit);
+module_usb_serial_driver(kl5kusb105d_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "enable extensive debugging messages");
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index a92a3ef..4a9a75e 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -90,7 +90,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id = 	1,
 };
 
 
@@ -100,7 +99,6 @@
 		.name =		"kobil",
 	},
 	.description =		"KOBIL USB smart card terminal",
-	.usb_driver = 		&kobil_driver,
 	.id_table =		id_table,
 	.num_ports =		1,
 	.attach =		kobil_startup,
@@ -117,6 +115,9 @@
 	.read_int_callback =	kobil_read_int_callback,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&kobil_device, NULL
+};
 
 struct kobil_private {
 	int write_int_endpoint_address;
@@ -682,35 +683,7 @@
 	}
 }
 
-static int __init kobil_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&kobil_device);
-	if (retval)
-		goto failed_usb_serial_register;
-	retval = usb_register(&kobil_driver);
-	if (retval)
-		goto failed_usb_register;
-
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&kobil_device);
-failed_usb_serial_register:
-	return retval;
-}
-
-
-static void __exit kobil_exit(void)
-{
-	usb_deregister(&kobil_driver);
-	usb_serial_deregister(&kobil_device);
-}
-
-module_init(kobil_init);
-module_exit(kobil_exit);
+module_usb_serial_driver(kobil_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 27fa9c8..6edd261 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -88,7 +88,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table_combined,
-	.no_dynamic_id = 	1,
 };
 
 static struct usb_serial_driver mct_u232_device = {
@@ -97,7 +96,6 @@
 		.name =		"mct_u232",
 	},
 	.description =	     "MCT U232",
-	.usb_driver = 	     &mct_u232_driver,
 	.id_table =	     id_table_combined,
 	.num_ports =	     1,
 	.open =		     mct_u232_open,
@@ -116,6 +114,10 @@
 	.get_icount =        mct_u232_get_icount,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&mct_u232_device, NULL
+};
+
 struct mct_u232_private {
 	spinlock_t lock;
 	unsigned int	     control_state; /* Modem Line Setting (TIOCM) */
@@ -904,33 +906,7 @@
 	return 0;
 }
 
-static int __init mct_u232_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&mct_u232_device);
-	if (retval)
-		goto failed_usb_serial_register;
-	retval = usb_register(&mct_u232_driver);
-	if (retval)
-		goto failed_usb_register;
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&mct_u232_device);
-failed_usb_serial_register:
-	return retval;
-}
-
-
-static void __exit mct_u232_exit(void)
-{
-	usb_deregister(&mct_u232_driver);
-	usb_serial_deregister(&mct_u232_device);
-}
-
-module_init(mct_u232_init);
-module_exit(mct_u232_exit);
+module_usb_serial_driver(mct_u232_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
new file mode 100644
index 0000000..6e1622f
--- /dev/null
+++ b/drivers/usb/serial/metro-usb.c
@@ -0,0 +1,402 @@
+/*
+  Some of this code is credited to Linux USB open source files that are
+  distributed with Linux.
+
+  Copyright:	2007 Metrologic Instruments. All rights reserved.
+  Copyright:	2011 Azimut Ltd. <http://azimutrzn.ru/>
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/uaccess.h>
+#include <linux/usb/serial.h>
+
+/* Version Information */
+#define DRIVER_VERSION "v1.2.0.0"
+#define DRIVER_DESC "Metrologic Instruments Inc. - USB-POS driver"
+
+/* Product information. */
+#define FOCUS_VENDOR_ID			0x0C2E
+#define FOCUS_PRODUCT_ID		0x0720
+#define FOCUS_PRODUCT_ID_UNI		0x0710
+
+#define METROUSB_SET_REQUEST_TYPE	0x40
+#define METROUSB_SET_MODEM_CTRL_REQUEST	10
+#define METROUSB_SET_BREAK_REQUEST	0x40
+#define METROUSB_MCR_NONE		0x08	/* Deactivate DTR and RTS. */
+#define METROUSB_MCR_RTS		0x0a	/* Activate RTS. */
+#define METROUSB_MCR_DTR		0x09	/* Activate DTR. */
+#define WDR_TIMEOUT			5000	/* default urb timeout. */
+
+/* Private data structure. */
+struct metrousb_private {
+	spinlock_t lock;
+	int throttled;
+	unsigned long control_state;
+};
+
+/* Device table list. */
+static struct usb_device_id id_table[] = {
+	{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID) },
+	{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_UNI) },
+	{ }, /* Terminating entry. */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+/* Input parameter constants. */
+static bool debug;
+
+static void metrousb_read_int_callback(struct urb *urb)
+{
+	struct usb_serial_port *port = urb->context;
+	struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
+	struct tty_struct *tty;
+	unsigned char *data = urb->transfer_buffer;
+	int throttled = 0;
+	int result = 0;
+	unsigned long flags = 0;
+
+	dev_dbg(&port->dev, "%s\n", __func__);
+
+	switch (urb->status) {
+	case 0:
+		/* Success status, read from the port. */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* urb has been terminated. */
+		dev_dbg(&port->dev,
+			"%s - urb shutting down, error code=%d\n",
+			__func__, result);
+		return;
+	default:
+		dev_dbg(&port->dev,
+			"%s - non-zero urb received, error code=%d\n",
+			__func__, result);
+		goto exit;
+	}
+
+
+	/* Set the data read from the usb port into the serial port buffer. */
+	tty = tty_port_tty_get(&port->port);
+	if (!tty) {
+		dev_dbg(&port->dev, "%s - bad tty pointer - exiting\n",
+			__func__);
+		return;
+	}
+
+	if (tty && urb->actual_length) {
+		/* Loop through the data copying each byte to the tty layer. */
+		tty_insert_flip_string(tty, data, urb->actual_length);
+
+		/* Force the data to the tty layer. */
+		tty_flip_buffer_push(tty);
+	}
+	tty_kref_put(tty);
+
+	/* Set any port variables. */
+	spin_lock_irqsave(&metro_priv->lock, flags);
+	throttled = metro_priv->throttled;
+	spin_unlock_irqrestore(&metro_priv->lock, flags);
+
+	/* Continue trying to read if set. */
+	if (!throttled) {
+		usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
+				 usb_rcvintpipe(port->serial->dev, port->interrupt_in_endpointAddress),
+				 port->interrupt_in_urb->transfer_buffer,
+				 port->interrupt_in_urb->transfer_buffer_length,
+				 metrousb_read_int_callback, port, 1);
+
+		result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
+
+		if (result)
+			dev_dbg(&port->dev,
+				"%s - failed submitting interrupt in urb, error code=%d\n",
+				__func__, result);
+	}
+	return;
+
+exit:
+	/* Try to resubmit the urb. */
+	result = usb_submit_urb(urb, GFP_ATOMIC);
+	if (result)
+		dev_dbg(&port->dev,
+			"%s - failed submitting interrupt in urb, error code=%d\n",
+			__func__, result);
+}
+
+static void metrousb_cleanup(struct usb_serial_port *port)
+{
+	dev_dbg(&port->dev, "%s\n", __func__);
+
+	if (port->serial->dev) {
+		/* Shutdown any interrupt in urbs. */
+		if (port->interrupt_in_urb) {
+			usb_unlink_urb(port->interrupt_in_urb);
+			usb_kill_urb(port->interrupt_in_urb);
+		}
+	}
+}
+
+static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+	struct usb_serial *serial = port->serial;
+	struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
+	unsigned long flags = 0;
+	int result = 0;
+
+	dev_dbg(&port->dev, "%s\n", __func__);
+
+	/* Make sure the urb is initialized. */
+	if (!port->interrupt_in_urb) {
+		dev_dbg(&port->dev, "%s - interrupt urb not initialized\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	/* Set the private data information for the port. */
+	spin_lock_irqsave(&metro_priv->lock, flags);
+	metro_priv->control_state = 0;
+	metro_priv->throttled = 0;
+	spin_unlock_irqrestore(&metro_priv->lock, flags);
+
+	/*
+	 * Force low_latency on so that our tty_push actually forces the data
+	 * through, otherwise it is scheduled, and with high data rates (like
+	 * with OHCI) data can get lost.
+	 */
+	if (tty)
+		tty->low_latency = 1;
+
+	/* Clear the urb pipe. */
+	usb_clear_halt(serial->dev, port->interrupt_in_urb->pipe);
+
+	/* Start reading from the device */
+	usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
+			  usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
+			   port->interrupt_in_urb->transfer_buffer,
+			   port->interrupt_in_urb->transfer_buffer_length,
+			   metrousb_read_int_callback, port, 1);
+	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+
+	if (result) {
+		dev_dbg(&port->dev,
+			"%s - failed submitting interrupt in urb, error code=%d\n",
+			__func__, result);
+		goto exit;
+	}
+
+	dev_dbg(&port->dev, "%s - port open\n", __func__);
+exit:
+	return result;
+}
+
+static int metrousb_set_modem_ctrl(struct usb_serial *serial, unsigned int control_state)
+{
+	int retval = 0;
+	unsigned char mcr = METROUSB_MCR_NONE;
+
+	dev_dbg(&serial->dev->dev, "%s - control state = %d\n",
+		__func__, control_state);
+
+	/* Set the modem control value. */
+	if (control_state & TIOCM_DTR)
+		mcr |= METROUSB_MCR_DTR;
+	if (control_state & TIOCM_RTS)
+		mcr |= METROUSB_MCR_RTS;
+
+	/* Send the command to the usb port. */
+	retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+				METROUSB_SET_REQUEST_TYPE, METROUSB_SET_MODEM_CTRL_REQUEST,
+				control_state, 0, NULL, 0, WDR_TIMEOUT);
+	if (retval < 0)
+		dev_dbg(&serial->dev->dev,
+			"%s - set modem ctrl=0x%x failed, error code=%d\n",
+			__func__, mcr, retval);
+
+	return retval;
+}
+
+static void metrousb_shutdown(struct usb_serial *serial)
+{
+	int i = 0;
+
+	dev_dbg(&serial->dev->dev, "%s\n", __func__);
+
+	/* Stop reading and writing on all ports. */
+	for (i = 0; i < serial->num_ports; ++i) {
+		/* Close any open urbs. */
+		metrousb_cleanup(serial->port[i]);
+
+		/* Free memory. */
+		kfree(usb_get_serial_port_data(serial->port[i]));
+		usb_set_serial_port_data(serial->port[i], NULL);
+
+		dev_dbg(&serial->dev->dev, "%s - freed port number=%d\n",
+			__func__, serial->port[i]->number);
+	}
+}
+
+static int metrousb_startup(struct usb_serial *serial)
+{
+	struct metrousb_private *metro_priv;
+	struct usb_serial_port *port;
+	int i = 0;
+
+	dev_dbg(&serial->dev->dev, "%s\n", __func__);
+
+	/* Loop through the serial ports setting up the private structures.
+	 * Currently we only use one port. */
+	for (i = 0; i < serial->num_ports; ++i) {
+		port = serial->port[i];
+
+		/* Declare memory. */
+		metro_priv = kzalloc(sizeof(struct metrousb_private), GFP_KERNEL);
+		if (!metro_priv)
+			return -ENOMEM;
+
+		/* Initialize memory. */
+		spin_lock_init(&metro_priv->lock);
+		usb_set_serial_port_data(port, metro_priv);
+
+		dev_dbg(&serial->dev->dev, "%s - port number=%d\n ",
+			__func__, port->number);
+	}
+
+	return 0;
+}
+
+static void metrousb_throttle(struct tty_struct *tty)
+{
+	struct usb_serial_port *port = tty->driver_data;
+	struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
+	unsigned long flags = 0;
+
+	dev_dbg(tty->dev, "%s\n", __func__);
+
+	/* Set the private information for the port to stop reading data. */
+	spin_lock_irqsave(&metro_priv->lock, flags);
+	metro_priv->throttled = 1;
+	spin_unlock_irqrestore(&metro_priv->lock, flags);
+}
+
+static int metrousb_tiocmget(struct tty_struct *tty)
+{
+	unsigned long control_state = 0;
+	struct usb_serial_port *port = tty->driver_data;
+	struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
+	unsigned long flags = 0;
+
+	dev_dbg(tty->dev, "%s\n", __func__);
+
+	spin_lock_irqsave(&metro_priv->lock, flags);
+	control_state = metro_priv->control_state;
+	spin_unlock_irqrestore(&metro_priv->lock, flags);
+
+	return control_state;
+}
+
+static int metrousb_tiocmset(struct tty_struct *tty,
+			     unsigned int set, unsigned int clear)
+{
+	struct usb_serial_port *port = tty->driver_data;
+	struct usb_serial *serial = port->serial;
+	struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
+	unsigned long flags = 0;
+	unsigned long control_state = 0;
+
+	dev_dbg(tty->dev, "%s - set=%d, clear=%d\n", __func__, set, clear);
+
+	spin_lock_irqsave(&metro_priv->lock, flags);
+	control_state = metro_priv->control_state;
+
+	/* Set the RTS and DTR values. */
+	if (set & TIOCM_RTS)
+		control_state |= TIOCM_RTS;
+	if (set & TIOCM_DTR)
+		control_state |= TIOCM_DTR;
+	if (clear & TIOCM_RTS)
+		control_state &= ~TIOCM_RTS;
+	if (clear & TIOCM_DTR)
+		control_state &= ~TIOCM_DTR;
+
+	metro_priv->control_state = control_state;
+	spin_unlock_irqrestore(&metro_priv->lock, flags);
+	return metrousb_set_modem_ctrl(serial, control_state);
+}
+
+static void metrousb_unthrottle(struct tty_struct *tty)
+{
+	struct usb_serial_port *port = tty->driver_data;
+	struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
+	unsigned long flags = 0;
+	int result = 0;
+
+	dev_dbg(tty->dev, "%s\n", __func__);
+
+	/* Set the private information for the port to resume reading data. */
+	spin_lock_irqsave(&metro_priv->lock, flags);
+	metro_priv->throttled = 0;
+	spin_unlock_irqrestore(&metro_priv->lock, flags);
+
+	/* Submit the urb to read from the port. */
+	port->interrupt_in_urb->dev = port->serial->dev;
+	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
+	if (result)
+		dev_dbg(tty->dev,
+			"failed submitting interrupt in urb error code=%d\n",
+			result);
+}
+
+static struct usb_driver metrousb_driver = {
+	.name =		"metro-usb",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	id_table
+};
+
+static struct usb_serial_driver metrousb_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"metro-usb",
+	},
+	.description		= "Metrologic USB to serial converter.",
+	.id_table		= id_table,
+	.num_ports		= 1,
+	.open			= metrousb_open,
+	.close			= metrousb_cleanup,
+	.read_int_callback	= metrousb_read_int_callback,
+	.attach			= metrousb_startup,
+	.release		= metrousb_shutdown,
+	.throttle		= metrousb_throttle,
+	.unthrottle		= metrousb_unthrottle,
+	.tiocmget		= metrousb_tiocmget,
+	.tiocmset		= metrousb_tiocmset,
+};
+
+static struct usb_serial_driver * const serial_drivers[] = {
+	&metrousb_device,
+	NULL,
+};
+
+module_usb_serial_driver(metrousb_driver, serial_drivers);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Philip Nicastro");
+MODULE_AUTHOR("Aleksey Babahin <tamerlan311@gmail.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+
+/* Module input parameters */
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Print debug info (bool 1=on, 0=off)");
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 4554ee4..bdce820 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -1294,7 +1294,7 @@
 		urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
 					       GFP_KERNEL);
 		if (urb->transfer_buffer == NULL) {
-			dev_err(&port->dev, "%s no more kernel memory...\n",
+			dev_err_console(port, "%s no more kernel memory...\n",
 				__func__);
 			goto exit;
 		}
@@ -1315,7 +1315,7 @@
 	/* send it down the pipe */
 	status = usb_submit_urb(urb, GFP_ATOMIC);
 	if (status) {
-		dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
+		dev_err_console(port, "%s - usb_submit_urb(write bulk) failed "
 			"with status = %d\n", __func__, status);
 		bytes_sent = status;
 		goto exit;
@@ -2169,7 +2169,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	moschip_port_id_table,
-	.no_dynamic_id =	1,
 };
 
 static struct usb_serial_driver moschip7720_2port_driver = {
@@ -2178,7 +2177,6 @@
 		.name =		"moschip7720",
 	},
 	.description		= "Moschip 2 port adapter",
-	.usb_driver		= &usb_driver,
 	.id_table		= moschip_port_id_table,
 	.calc_num_ports		= mos77xx_calc_num_ports,
 	.open			= mos7720_open,
@@ -2201,44 +2199,12 @@
 	.read_int_callback	= NULL  /* dynamically assigned in probe() */
 };
 
-static int __init moschip7720_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&moschip7720_2port_driver, NULL
+};
 
-	dbg("%s: Entering ..........", __func__);
+module_usb_serial_driver(usb_driver, serial_drivers);
 
-	/* Register with the usb serial */
-	retval = usb_serial_register(&moschip7720_2port_driver);
-	if (retval)
-		goto failed_port_device_register;
-
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-
-	/* Register with the usb */
-	retval = usb_register(&usb_driver);
-	if (retval)
-		goto failed_usb_register;
-
-	return 0;
-
-failed_usb_register:
-	usb_serial_deregister(&moschip7720_2port_driver);
-
-failed_port_device_register:
-	return retval;
-}
-
-static void __exit moschip7720_exit(void)
-{
-	usb_deregister(&usb_driver);
-	usb_serial_deregister(&moschip7720_2port_driver);
-}
-
-module_init(moschip7720_init);
-module_exit(moschip7720_exit);
-
-/* Module information */
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 03b5e24..c526550 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -174,6 +174,7 @@
 
 #define CLK_MULTI_REGISTER         ((__u16)(0x02))
 #define CLK_START_VALUE_REGISTER   ((__u16)(0x03))
+#define GPIO_REGISTER              ((__u16)(0x07))
 
 #define SERIAL_LCR_DLAB            ((__u16)(0x0080))
 
@@ -1101,14 +1102,25 @@
 	mos7840_port->read_urb = port->read_urb;
 
 	/* set up our bulk in urb */
-
-	usb_fill_bulk_urb(mos7840_port->read_urb,
-			  serial->dev,
-			  usb_rcvbulkpipe(serial->dev,
-					  port->bulk_in_endpointAddress),
-			  port->bulk_in_buffer,
-			  mos7840_port->read_urb->transfer_buffer_length,
-			  mos7840_bulk_in_callback, mos7840_port);
+	if ((serial->num_ports == 2)
+		&& ((((__u16)port->number -
+			(__u16)(port->serial->minor)) % 2) != 0)) {
+		usb_fill_bulk_urb(mos7840_port->read_urb,
+			serial->dev,
+			usb_rcvbulkpipe(serial->dev,
+				(port->bulk_in_endpointAddress) + 2),
+			port->bulk_in_buffer,
+			mos7840_port->read_urb->transfer_buffer_length,
+			mos7840_bulk_in_callback, mos7840_port);
+	} else {
+		usb_fill_bulk_urb(mos7840_port->read_urb,
+			serial->dev,
+			usb_rcvbulkpipe(serial->dev,
+				port->bulk_in_endpointAddress),
+			port->bulk_in_buffer,
+			mos7840_port->read_urb->transfer_buffer_length,
+			mos7840_bulk_in_callback, mos7840_port);
+	}
 
 	dbg("mos7840_open: bulkin endpoint is %d",
 	    port->bulk_in_endpointAddress);
@@ -1509,7 +1521,7 @@
 		    kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
 
 		if (urb->transfer_buffer == NULL) {
-			dev_err(&port->dev, "%s no more kernel memory...\n",
+			dev_err_console(port, "%s no more kernel memory...\n",
 				__func__);
 			goto exit;
 		}
@@ -1519,13 +1531,25 @@
 	memcpy(urb->transfer_buffer, current_position, transfer_size);
 
 	/* fill urb with data and submit  */
-	usb_fill_bulk_urb(urb,
-			  serial->dev,
-			  usb_sndbulkpipe(serial->dev,
-					  port->bulk_out_endpointAddress),
-			  urb->transfer_buffer,
-			  transfer_size,
-			  mos7840_bulk_out_data_callback, mos7840_port);
+	if ((serial->num_ports == 2)
+		&& ((((__u16)port->number -
+			(__u16)(port->serial->minor)) % 2) != 0)) {
+		usb_fill_bulk_urb(urb,
+			serial->dev,
+			usb_sndbulkpipe(serial->dev,
+				(port->bulk_out_endpointAddress) + 2),
+			urb->transfer_buffer,
+			transfer_size,
+			mos7840_bulk_out_data_callback, mos7840_port);
+	} else {
+		usb_fill_bulk_urb(urb,
+			serial->dev,
+			usb_sndbulkpipe(serial->dev,
+				port->bulk_out_endpointAddress),
+			urb->transfer_buffer,
+			transfer_size,
+			mos7840_bulk_out_data_callback, mos7840_port);
+	}
 
 	data1 = urb->transfer_buffer;
 	dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress);
@@ -1535,7 +1559,7 @@
 
 	if (status) {
 		mos7840_port->busy[i] = 0;
-		dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
+		dev_err_console(port, "%s - usb_submit_urb(write bulk) failed "
 			"with status = %d\n", __func__, status);
 		bytes_sent = status;
 		goto exit;
@@ -1838,7 +1862,7 @@
 
 	} else {
 #ifdef HW_flow_control
-		/ *setting h/w flow control bit to 0 */
+		/* setting h/w flow control bit to 0 */
 		Data = 0xb;
 		mos7840_port->shadowMCR = Data;
 		status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
@@ -2305,19 +2329,26 @@
 
 static int mos7840_calc_num_ports(struct usb_serial *serial)
 {
-	int mos7840_num_ports = 0;
+	__u16 Data = 0x00;
+	int ret = 0;
+	int mos7840_num_ports;
 
-	dbg("numberofendpoints: cur %d, alt %d",
-	    (int)serial->interface->cur_altsetting->desc.bNumEndpoints,
-	    (int)serial->interface->altsetting->desc.bNumEndpoints);
-	if (serial->interface->cur_altsetting->desc.bNumEndpoints == 5) {
-		mos7840_num_ports = serial->num_ports = 2;
-	} else if (serial->interface->cur_altsetting->desc.bNumEndpoints == 9) {
+	ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+		MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &Data,
+		VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+
+	if ((Data & 0x01) == 0) {
+		mos7840_num_ports = 2;
+		serial->num_bulk_in = 2;
+		serial->num_bulk_out = 2;
+		serial->num_ports = 2;
+	} else {
+		mos7840_num_ports = 4;
 		serial->num_bulk_in = 4;
 		serial->num_bulk_out = 4;
-		mos7840_num_ports = serial->num_ports = 4;
+		serial->num_ports = 4;
 	}
-	dbg ("mos7840_num_ports = %d", mos7840_num_ports);
+
 	return mos7840_num_ports;
 }
 
@@ -2638,7 +2669,6 @@
 	.probe = usb_serial_probe,
 	.disconnect = usb_serial_disconnect,
 	.id_table = moschip_id_table_combined,
-	.no_dynamic_id = 1,
 };
 
 static struct usb_serial_driver moschip7840_4port_device = {
@@ -2647,7 +2677,6 @@
 		   .name = "mos7840",
 		   },
 	.description = DRIVER_DESC,
-	.usb_driver = &io_driver,
 	.id_table = moschip_port_id_table,
 	.num_ports = 4,
 	.open = mos7840_open,
@@ -2674,57 +2703,12 @@
 	.read_int_callback = mos7840_interrupt_callback,
 };
 
-/****************************************************************************
- * moschip7840_init
- *	This is called by the module subsystem, or on startup to initialize us
- ****************************************************************************/
-static int __init moschip7840_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&moschip7840_4port_device, NULL
+};
 
-	dbg("%s", " mos7840_init :entering..........");
+module_usb_serial_driver(io_driver, serial_drivers);
 
-	/* Register with the usb serial */
-	retval = usb_serial_register(&moschip7840_4port_device);
-
-	if (retval)
-		goto failed_port_device_register;
-
-	dbg("%s", "Entering...");
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-
-	/* Register with the usb */
-	retval = usb_register(&io_driver);
-	if (retval == 0) {
-		dbg("%s", "Leaving...");
-		return 0;
-	}
-	usb_serial_deregister(&moschip7840_4port_device);
-failed_port_device_register:
-	return retval;
-}
-
-/****************************************************************************
- * moschip7840_exit
- *	Called when the driver is about to be unloaded.
- ****************************************************************************/
-static void __exit moschip7840_exit(void)
-{
-
-	dbg("%s", " mos7840_exit :entering..........");
-
-	usb_deregister(&io_driver);
-
-	usb_serial_deregister(&moschip7840_4port_device);
-
-	dbg("%s", "Entering...");
-}
-
-module_init(moschip7840_init);
-module_exit(moschip7840_exit);
-
-/* Module information */
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c
index e2bfecc..3ab6214 100644
--- a/drivers/usb/serial/moto_modem.c
+++ b/drivers/usb/serial/moto_modem.c
@@ -36,7 +36,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id = 	1,
 };
 
 static struct usb_serial_driver moto_device = {
@@ -45,29 +44,12 @@
 		.name =		"moto-modem",
 	},
 	.id_table =		id_table,
-	.usb_driver =		&moto_driver,
 	.num_ports =		1,
 };
 
-static int __init moto_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&moto_device, NULL
+};
 
-	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_usb_serial_driver(moto_driver, serial_drivers);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index b28f1db..29ab6eb 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -35,7 +35,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id = 	1,
 };
 
 static void navman_read_int_callback(struct urb *urb)
@@ -122,7 +121,6 @@
 		.name =		"navman",
 	},
 	.id_table =		id_table,
-	.usb_driver =		&navman_driver,
 	.num_ports =		1,
 	.open =			navman_open,
 	.close = 		navman_close,
@@ -130,27 +128,12 @@
 	.read_int_callback =	navman_read_int_callback,
 };
 
-static int __init navman_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&navman_device, NULL
+};
 
-	retval = usb_serial_register(&navman_device);
-	if (retval)
-		return retval;
-	retval = usb_register(&navman_driver);
-	if (retval)
-		usb_serial_deregister(&navman_device);
-	return retval;
-}
+module_usb_serial_driver(navman_driver, serial_drivers);
 
-static void __exit navman_exit(void)
-{
-	usb_deregister(&navman_driver);
-	usb_serial_deregister(&navman_device);
-}
-
-module_init(navman_init);
-module_exit(navman_exit);
 MODULE_LICENSE("GPL");
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 8b8d58a..88dc785 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -62,7 +62,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id = 	1,
 };
 
 
@@ -72,7 +71,6 @@
 		.name =		"omninet",
 	},
 	.description =		"ZyXEL - omni.net lcd plus usb",
-	.usb_driver =		&omninet_driver,
 	.id_table =		id_table,
 	.num_ports =		1,
 	.attach =		omninet_attach,
@@ -86,6 +84,10 @@
 	.release =		omninet_release,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&zyxel_omninet_device, NULL
+};
+
 
 /* The protocol.
  *
@@ -254,7 +256,7 @@
 	result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
 	if (result) {
 		set_bit(0, &wport->write_urbs_free);
-		dev_err(&port->dev,
+		dev_err_console(port,
 			"%s - failed submitting write urb, error %d\n",
 			__func__, result);
 	} else
@@ -319,35 +321,7 @@
 	kfree(usb_get_serial_port_data(port));
 }
 
-
-static int __init omninet_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&zyxel_omninet_device);
-	if (retval)
-		goto failed_usb_serial_register;
-	retval = usb_register(&omninet_driver);
-	if (retval)
-		goto failed_usb_register;
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&zyxel_omninet_device);
-failed_usb_serial_register:
-	return retval;
-}
-
-
-static void __exit omninet_exit(void)
-{
-	usb_deregister(&omninet_driver);
-	usb_serial_deregister(&zyxel_omninet_device);
-}
-
-
-module_init(omninet_init);
-module_exit(omninet_exit);
+module_usb_serial_driver(omninet_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index 262ded9..82cc9d2 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -604,7 +604,6 @@
 	.suspend =	opticon_suspend,
 	.resume =	opticon_resume,
 	.id_table =	id_table,
-	.no_dynamic_id = 	1,
 };
 
 static struct usb_serial_driver opticon_device = {
@@ -613,7 +612,6 @@
 		.name =		"opticon",
 	},
 	.id_table =		id_table,
-	.usb_driver = 		&opticon_driver,
 	.num_ports =		1,
 	.attach =		opticon_startup,
 	.open =			opticon_open,
@@ -629,27 +627,12 @@
 	.tiocmset =		opticon_tiocmset,
 };
 
-static int __init opticon_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&opticon_device, NULL
+};
 
-	retval = usb_serial_register(&opticon_device);
-	if (retval)
-		return retval;
-	retval = usb_register(&opticon_driver);
-	if (retval)
-		usb_serial_deregister(&opticon_device);
-	return retval;
-}
+module_usb_serial_driver(opticon_driver, serial_drivers);
 
-static void __exit opticon_exit(void)
-{
-	usb_deregister(&opticon_driver);
-	usb_serial_deregister(&opticon_device);
-}
-
-module_init(opticon_init);
-module_exit(opticon_exit);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index b54afce..6815701 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -307,6 +307,9 @@
 #define TELIT_VENDOR_ID				0x1bc7
 #define TELIT_PRODUCT_UC864E			0x1003
 #define TELIT_PRODUCT_UC864G			0x1004
+#define TELIT_PRODUCT_CC864_DUAL		0x1005
+#define TELIT_PRODUCT_CC864_SINGLE		0x1006
+#define TELIT_PRODUCT_DE910_DUAL		0x1010
 
 /* ZTE PRODUCTS */
 #define ZTE_VENDOR_ID				0x19d2
@@ -484,6 +487,9 @@
 #define LG_VENDOR_ID				0x1004
 #define LG_PRODUCT_L02C				0x618f
 
+/* MediaTek products */
+#define MEDIATEK_VENDOR_ID			0x0e8d
+
 /* some devices interfaces need special handling due to a number of reasons */
 enum option_blacklist_reason {
 		OPTION_BLACKLIST_NONE = 0,
@@ -768,6 +774,9 @@
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) },
 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff),
 		.driver_info = (kernel_ulong_t)&net_intf1_blacklist },
@@ -892,6 +901,8 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0162, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0164, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) },
@@ -1198,6 +1209,10 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(VIETTEL_VENDOR_ID, VIETTEL_PRODUCT_VT1000, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZD_VENDOR_ID, ZD_PRODUCT_7000, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE(LG_VENDOR_ID, LG_PRODUCT_L02C) }, /* docomo L-02C modem */
+	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x00, 0x00) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x02, 0x01) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x00, 0x00) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x02, 0x01) },        /* MediaTek MT6276M modem & app port */
 	{ } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
@@ -1212,7 +1227,6 @@
 	.supports_autosuspend =	1,
 #endif
 	.id_table   = option_ids,
-	.no_dynamic_id = 	1,
 };
 
 /* The card has three separate interfaces, which the serial driver
@@ -1225,7 +1239,6 @@
 		.name =		"option1",
 	},
 	.description       = "GSM modem (1-port)",
-	.usb_driver        = &option_driver,
 	.id_table          = option_ids,
 	.num_ports         = 1,
 	.probe             = option_probe,
@@ -1249,6 +1262,10 @@
 #endif
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&option_1port_device, NULL
+};
+
 static bool debug;
 
 /* per port private data */
@@ -1280,36 +1297,7 @@
 	unsigned long tx_start_time[N_OUT_URB];
 };
 
-/* Functions used by new usb-serial code. */
-static int __init option_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&option_1port_device);
-	if (retval)
-		goto failed_1port_device_register;
-	retval = usb_register(&option_driver);
-	if (retval)
-		goto failed_driver_register;
-
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-
-	return 0;
-
-failed_driver_register:
-	usb_serial_deregister(&option_1port_device);
-failed_1port_device_register:
-	return retval;
-}
-
-static void __exit option_exit(void)
-{
-	usb_deregister(&option_driver);
-	usb_serial_deregister(&option_1port_device);
-}
-
-module_init(option_init);
-module_exit(option_exit);
+module_usb_serial_driver(option_driver, serial_drivers);
 
 static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason,
 			   const struct option_blacklist_info *blacklist)
@@ -1360,6 +1348,7 @@
 		serial->interface->cur_altsetting->desc.bInterfaceNumber,
 		OPTION_BLACKLIST_RESERVED_IF,
 		(const struct option_blacklist_info *) id->driver_info))
+		return -ENODEV;
 
 	/* Don't bind network interface on Samsung GT-B3730, it is handled by a separate module */
 	if (serial->dev->descriptor.idVendor == SAMSUNG_VENDOR_ID &&
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index e287fd3..5fdc33c 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -71,7 +71,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id = 	1,
 };
 
 static bool debug;
@@ -157,7 +156,6 @@
 		.name =		"oti6858",
 	},
 	.id_table =		id_table,
-	.usb_driver =		&oti6858_driver,
 	.num_ports =		1,
 	.open =			oti6858_open,
 	.close =		oti6858_close,
@@ -176,6 +174,10 @@
 	.release =		oti6858_release,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&oti6858_device, NULL
+};
+
 struct oti6858_private {
 	spinlock_t lock;
 
@@ -302,7 +304,7 @@
 	if (count != 0) {
 		allow = kmalloc(1, GFP_KERNEL);
 		if (!allow) {
-			dev_err(&port->dev, "%s(): kmalloc failed\n",
+			dev_err_console(port, "%s(): kmalloc failed\n",
 					__func__);
 			return;
 		}
@@ -334,7 +336,7 @@
 	port->write_urb->transfer_buffer_length = count;
 	result = usb_submit_urb(port->write_urb, GFP_NOIO);
 	if (result != 0) {
-		dev_err(&port->dev, "%s(): usb_submit_urb() failed"
+		dev_err_console(port, "%s(): usb_submit_urb() failed"
 			       " with error %d\n", __func__, result);
 		priv->flags.write_urb_in_use = 0;
 	}
@@ -938,7 +940,7 @@
 		port->write_urb->transfer_buffer_length = 1;
 		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
 		if (result) {
-			dev_err(&port->dev, "%s(): usb_submit_urb() failed,"
+			dev_err_console(port, "%s(): usb_submit_urb() failed,"
 					" error %d\n", __func__, result);
 		} else {
 			return;
@@ -956,29 +958,7 @@
 	}
 }
 
-/* module description and (de)initialization */
-
-static int __init oti6858_init(void)
-{
-	int retval;
-
-	retval = usb_serial_register(&oti6858_device);
-	if (retval == 0) {
-		retval = usb_register(&oti6858_driver);
-		if (retval)
-			usb_serial_deregister(&oti6858_device);
-	}
-	return retval;
-}
-
-static void __exit oti6858_exit(void)
-{
-	usb_deregister(&oti6858_driver);
-	usb_serial_deregister(&oti6858_device);
-}
-
-module_init(oti6858_init);
-module_exit(oti6858_exit);
+module_usb_serial_driver(oti6858_driver, serial_drivers);
 
 MODULE_DESCRIPTION(OTI6858_DESCRIPTION);
 MODULE_AUTHOR(OTI6858_AUTHOR);
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 3d8cda5..ff4a174 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -104,7 +104,6 @@
 	.id_table =	id_table,
 	.suspend =      usb_serial_suspend,
 	.resume =       usb_serial_resume,
-	.no_dynamic_id = 	1,
 	.supports_autosuspend =	1,
 };
 
@@ -834,7 +833,6 @@
 		.name =		"pl2303",
 	},
 	.id_table =		id_table,
-	.usb_driver = 		&pl2303_driver,
 	.num_ports =		1,
 	.bulk_in_size =		256,
 	.bulk_out_size =	256,
@@ -853,32 +851,11 @@
 	.release =		pl2303_release,
 };
 
-static int __init pl2303_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&pl2303_device, NULL
+};
 
-	retval = usb_serial_register(&pl2303_device);
-	if (retval)
-		goto failed_usb_serial_register;
-	retval = usb_register(&pl2303_driver);
-	if (retval)
-		goto failed_usb_register;
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&pl2303_device);
-failed_usb_serial_register:
-	return retval;
-}
-
-static void __exit pl2303_exit(void)
-{
-	usb_deregister(&pl2303_driver);
-	usb_serial_deregister(&pl2303_device);
-}
-
-module_init(pl2303_init);
-module_exit(pl2303_exit);
+module_usb_serial_driver(pl2303_driver, serial_drivers);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c
index a348198..9662456 100644
--- a/drivers/usb/serial/qcaux.c
+++ b/drivers/usb/serial/qcaux.c
@@ -82,7 +82,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id = 	1,
 };
 
 static struct usb_serial_driver qcaux_device = {
@@ -91,29 +90,12 @@
 		.name =		"qcaux",
 	},
 	.id_table =		id_table,
-	.usb_driver =		&qcaux_driver,
 	.num_ports =		1,
 };
 
-static int __init qcaux_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&qcaux_device, NULL
+};
 
-	retval = usb_serial_register(&qcaux_device);
-	if (retval)
-		return retval;
-	retval = usb_register(&qcaux_driver);
-	if (retval)
-		usb_serial_deregister(&qcaux_device);
-	return retval;
-}
-
-static void __exit qcaux_exit(void)
-{
-	usb_deregister(&qcaux_driver);
-	usb_serial_deregister(&qcaux_device);
-}
-
-module_init(qcaux_init);
-module_exit(qcaux_exit);
+module_usb_serial_driver(qcaux_driver, serial_drivers);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index f98800f..0206b10 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -24,39 +24,44 @@
 
 static bool debug;
 
+#define DEVICE_G1K(v, p) \
+	USB_DEVICE(v, p), .driver_info = 1
+
 static const struct usb_device_id id_table[] = {
-	{USB_DEVICE(0x05c6, 0x9211)},	/* Acer Gobi QDL device */
-	{USB_DEVICE(0x05c6, 0x9212)},	/* Acer Gobi Modem Device */
-	{USB_DEVICE(0x03f0, 0x1f1d)},	/* HP un2400 Gobi Modem Device */
-	{USB_DEVICE(0x03f0, 0x201d)},	/* HP un2400 Gobi QDL Device */
-	{USB_DEVICE(0x03f0, 0x371d)},	/* HP un2430 Mobile Broadband Module */
-	{USB_DEVICE(0x04da, 0x250d)},	/* Panasonic Gobi Modem device */
-	{USB_DEVICE(0x04da, 0x250c)},	/* Panasonic Gobi QDL device */
-	{USB_DEVICE(0x413c, 0x8172)},	/* Dell Gobi Modem device */
-	{USB_DEVICE(0x413c, 0x8171)},	/* Dell Gobi QDL device */
-	{USB_DEVICE(0x1410, 0xa001)},	/* Novatel Gobi Modem device */
-	{USB_DEVICE(0x1410, 0xa008)},	/* Novatel Gobi QDL device */
-	{USB_DEVICE(0x1410, 0xa010)},	/* Novatel Gobi QDL device */
-	{USB_DEVICE(0x1410, 0xa011)},	/* Novatel Gobi QDL device */
-	{USB_DEVICE(0x1410, 0xa012)},	/* Novatel Gobi QDL device */
-	{USB_DEVICE(0x1410, 0xa013)},	/* Novatel Gobi QDL device */
-	{USB_DEVICE(0x1410, 0xa014)},	/* Novatel Gobi QDL device */
-	{USB_DEVICE(0x0b05, 0x1776)},	/* Asus Gobi Modem device */
-	{USB_DEVICE(0x0b05, 0x1774)},	/* Asus Gobi QDL device */
-	{USB_DEVICE(0x19d2, 0xfff3)},	/* ONDA Gobi Modem device */
-	{USB_DEVICE(0x19d2, 0xfff2)},	/* ONDA Gobi QDL device */
-	{USB_DEVICE(0x1557, 0x0a80)},	/* OQO Gobi QDL device */
-	{USB_DEVICE(0x05c6, 0x9001)},   /* Generic Gobi Modem device */
-	{USB_DEVICE(0x05c6, 0x9002)},	/* Generic Gobi Modem device */
-	{USB_DEVICE(0x05c6, 0x9202)},	/* Generic Gobi Modem device */
-	{USB_DEVICE(0x05c6, 0x9203)},	/* Generic Gobi Modem device */
-	{USB_DEVICE(0x05c6, 0x9222)},	/* Generic Gobi Modem device */
-	{USB_DEVICE(0x05c6, 0x9008)},	/* Generic Gobi QDL device */
-	{USB_DEVICE(0x05c6, 0x9009)},	/* Generic Gobi Modem device */
-	{USB_DEVICE(0x05c6, 0x9201)},	/* Generic Gobi QDL device */
-	{USB_DEVICE(0x05c6, 0x9221)},	/* Generic Gobi QDL device */
-	{USB_DEVICE(0x05c6, 0x9231)},	/* Generic Gobi QDL device */
-	{USB_DEVICE(0x1f45, 0x0001)},	/* Unknown Gobi QDL device */
+	/* Gobi 1000 devices */
+	{DEVICE_G1K(0x05c6, 0x9211)},	/* Acer Gobi QDL device */
+	{DEVICE_G1K(0x05c6, 0x9212)},	/* Acer Gobi Modem Device */
+	{DEVICE_G1K(0x03f0, 0x1f1d)},	/* HP un2400 Gobi Modem Device */
+	{DEVICE_G1K(0x03f0, 0x201d)},	/* HP un2400 Gobi QDL Device */
+	{DEVICE_G1K(0x04da, 0x250d)},	/* Panasonic Gobi Modem device */
+	{DEVICE_G1K(0x04da, 0x250c)},	/* Panasonic Gobi QDL device */
+	{DEVICE_G1K(0x413c, 0x8172)},	/* Dell Gobi Modem device */
+	{DEVICE_G1K(0x413c, 0x8171)},	/* Dell Gobi QDL device */
+	{DEVICE_G1K(0x1410, 0xa001)},	/* Novatel Gobi Modem device */
+	{DEVICE_G1K(0x1410, 0xa008)},	/* Novatel Gobi QDL device */
+	{DEVICE_G1K(0x0b05, 0x1776)},	/* Asus Gobi Modem device */
+	{DEVICE_G1K(0x0b05, 0x1774)},	/* Asus Gobi QDL device */
+	{DEVICE_G1K(0x19d2, 0xfff3)},	/* ONDA Gobi Modem device */
+	{DEVICE_G1K(0x19d2, 0xfff2)},	/* ONDA Gobi QDL device */
+	{DEVICE_G1K(0x1557, 0x0a80)},	/* OQO Gobi QDL device */
+	{DEVICE_G1K(0x05c6, 0x9001)},   /* Generic Gobi Modem device */
+	{DEVICE_G1K(0x05c6, 0x9002)},	/* Generic Gobi Modem device */
+	{DEVICE_G1K(0x05c6, 0x9202)},	/* Generic Gobi Modem device */
+	{DEVICE_G1K(0x05c6, 0x9203)},	/* Generic Gobi Modem device */
+	{DEVICE_G1K(0x05c6, 0x9222)},	/* Generic Gobi Modem device */
+	{DEVICE_G1K(0x05c6, 0x9008)},	/* Generic Gobi QDL device */
+	{DEVICE_G1K(0x05c6, 0x9009)},	/* Generic Gobi Modem device */
+	{DEVICE_G1K(0x05c6, 0x9201)},	/* Generic Gobi QDL device */
+	{DEVICE_G1K(0x05c6, 0x9221)},	/* Generic Gobi QDL device */
+	{DEVICE_G1K(0x05c6, 0x9231)},	/* Generic Gobi QDL device */
+	{DEVICE_G1K(0x1f45, 0x0001)},	/* Unknown Gobi QDL device */
+
+	/* Gobi 2000 devices */
+	{USB_DEVICE(0x1410, 0xa010)},	/* Novatel Gobi 2000 QDL device */
+	{USB_DEVICE(0x1410, 0xa011)},	/* Novatel Gobi 2000 QDL device */
+	{USB_DEVICE(0x1410, 0xa012)},	/* Novatel Gobi 2000 QDL device */
+	{USB_DEVICE(0x1410, 0xa013)},	/* Novatel Gobi 2000 QDL device */
+	{USB_DEVICE(0x1410, 0xa014)},	/* Novatel Gobi 2000 QDL device */
 	{USB_DEVICE(0x413c, 0x8185)},	/* Dell Gobi 2000 QDL device (N0218, VU936) */
 	{USB_DEVICE(0x413c, 0x8186)},	/* Dell Gobi 2000 Modem device (N0218, VU936) */
 	{USB_DEVICE(0x05c6, 0x9208)},	/* Generic Gobi 2000 QDL device */
@@ -92,6 +97,8 @@
 	{USB_DEVICE(0x05c6, 0x9204)},	/* Gobi 2000 QDL device */
 	{USB_DEVICE(0x05c6, 0x9205)},	/* Gobi 2000 Modem device */
 
+	/* Gobi 3000 devices */
+	{USB_DEVICE(0x03f0, 0x371d)},	/* HP un2430 Gobi 3000 QDL */
 	{USB_DEVICE(0x05c6, 0x920c)},	/* Gobi 3000 QDL */
 	{USB_DEVICE(0x05c6, 0x920d)},	/* Gobi 3000 Composite */
 	{USB_DEVICE(0x1410, 0xa020)},   /* Novatel Gobi 3000 QDL */
@@ -122,8 +129,10 @@
 	int retval = -ENODEV;
 	__u8 nintf;
 	__u8 ifnum;
+	bool is_gobi1k = id->driver_info ? true : false;
 
 	dbg("%s", __func__);
+	dbg("Is Gobi 1000 = %d", is_gobi1k);
 
 	nintf = serial->dev->actconfig->desc.bNumInterfaces;
 	dbg("Num Interfaces = %d", nintf);
@@ -169,15 +178,25 @@
 
 	case 3:
 	case 4:
-		/* Composite mode */
-		/* ifnum == 0 is a broadband network adapter */
-		if (ifnum == 1) {
-			/*
-			 * Diagnostics Monitor (serial line 9600 8N1)
-			 * Qualcomm DM protocol
-			 * use "libqcdm" (ModemManager) for communication
-			 */
-			dbg("Diagnostics Monitor found");
+		/* Composite mode; don't bind to the QMI/net interface as that
+		 * gets handled by other drivers.
+		 */
+
+		/* Gobi 1K USB layout:
+		 * 0: serial port (doesn't respond)
+		 * 1: serial port (doesn't respond)
+		 * 2: AT-capable modem port
+		 * 3: QMI/net
+		 *
+		 * Gobi 2K+ USB layout:
+		 * 0: QMI/net
+		 * 1: DM/DIAG (use libqcdm from ModemManager for communication)
+		 * 2: AT-capable modem port
+		 * 3: NMEA
+		 */
+
+		if (ifnum == 1 && !is_gobi1k) {
+			dbg("Gobi 2K+ DM/DIAG interface found");
 			retval = usb_set_interface(serial->dev, ifnum, 0);
 			if (retval < 0) {
 				dev_err(&serial->dev->dev,
@@ -196,13 +215,13 @@
 				retval = -ENODEV;
 				kfree(data);
 			}
-		} else if (ifnum==3) {
+		} else if (ifnum==3 && !is_gobi1k) {
 			/*
 			 * NMEA (serial line 9600 8N1)
 			 * # echo "\$GPS_START" > /dev/ttyUSBx
 			 * # echo "\$GPS_STOP"  > /dev/ttyUSBx
 			 */
-			dbg("NMEA GPS interface found");
+			dbg("Gobi 2K+ NMEA GPS interface found");
 			retval = usb_set_interface(serial->dev, ifnum, 0);
 			if (retval < 0) {
 				dev_err(&serial->dev->dev,
@@ -246,7 +265,6 @@
 	},
 	.description         = "Qualcomm USB modem",
 	.id_table            = id_table,
-	.usb_driver          = &qcdriver,
 	.num_ports           = 1,
 	.probe               = qcprobe,
 	.open		     = usb_wwan_open,
@@ -263,31 +281,11 @@
 #endif
 };
 
-static int __init qcinit(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&qcdevice, NULL
+};
 
-	retval = usb_serial_register(&qcdevice);
-	if (retval)
-		return retval;
-
-	retval = usb_register(&qcdriver);
-	if (retval) {
-		usb_serial_deregister(&qcdevice);
-		return retval;
-	}
-
-	return 0;
-}
-
-static void __exit qcexit(void)
-{
-	usb_deregister(&qcdriver);
-	usb_serial_deregister(&qcdevice);
-}
-
-module_init(qcinit);
-module_exit(qcexit);
+module_usb_serial_driver(qcdriver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index d074b37..ae4ee30 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -156,7 +156,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id = 	1,
 };
 
 static const __u16 crc10_table[256] = {
@@ -309,16 +308,19 @@
 		.name =		"safe_serial",
 	},
 	.id_table =		id_table,
-	.usb_driver =		&safe_driver,
 	.num_ports =		1,
 	.process_read_urb =	safe_process_read_urb,
 	.prepare_write_buffer =	safe_prepare_write_buffer,
 	.attach =		safe_startup,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&safe_device, NULL
+};
+
 static int __init safe_init(void)
 {
-	int i, retval;
+	int i;
 
 	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
 	       DRIVER_DESC "\n");
@@ -337,24 +339,12 @@
 		}
 	}
 
-	retval = usb_serial_register(&safe_device);
-	if (retval)
-		goto failed_usb_serial_register;
-	retval = usb_register(&safe_driver);
-	if (retval)
-		goto failed_usb_register;
-
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&safe_device);
-failed_usb_serial_register:
-	return retval;
+	return usb_serial_register_drivers(&safe_driver, serial_drivers);
 }
 
 static void __exit safe_exit(void)
 {
-	usb_deregister(&safe_driver);
-	usb_serial_deregister(&safe_device);
+	usb_serial_deregister_drivers(&safe_driver, serial_drivers);
 }
 
 module_init(safe_init);
diff --git a/drivers/usb/serial/siemens_mpi.c b/drivers/usb/serial/siemens_mpi.c
index 74cd4cc..46c0430 100644
--- a/drivers/usb/serial/siemens_mpi.c
+++ b/drivers/usb/serial/siemens_mpi.c
@@ -42,37 +42,15 @@
 		.name =		"siemens_mpi",
 	},
 	.id_table =		id_table,
-	.usb_driver =		&siemens_usb_mpi_driver,
 	.num_ports =		1,
 };
 
-static int __init siemens_usb_mpi_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&siemens_usb_mpi_device, NULL
+};
 
-	retval = usb_serial_register(&siemens_usb_mpi_device);
-	if (retval)
-		goto failed_usb_serial_register;
-	retval = usb_register(&siemens_usb_mpi_driver);
-	if (retval)
-		goto failed_usb_register;
-	printk(KERN_INFO DRIVER_DESC "\n");
-	printk(KERN_INFO DRIVER_VERSION " " DRIVER_AUTHOR "\n");
-	return retval;
-failed_usb_register:
-	usb_serial_deregister(&siemens_usb_mpi_device);
-failed_usb_serial_register:
-	return retval;
-}
+module_usb_serial_driver(siemens_usb_mpi_driver, serial_drivers);
 
-static void __exit siemens_usb_mpi_exit(void)
-{
-	usb_deregister(&siemens_usb_mpi_driver);
-	usb_serial_deregister(&siemens_usb_mpi_device);
-}
-
-module_init(siemens_usb_mpi_init);
-module_exit(siemens_usb_mpi_exit);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index fdae0a4..f14465a 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -1084,7 +1084,6 @@
 	.resume     = usb_serial_resume,
 	.reset_resume = sierra_reset_resume,
 	.id_table   = id_table,
-	.no_dynamic_id = 	1,
 	.supports_autosuspend =	1,
 };
 
@@ -1095,7 +1094,6 @@
 	},
 	.description       = "Sierra USB modem",
 	.id_table          = id_table,
-	.usb_driver        = &sierra_driver,
 	.calc_num_ports	   = sierra_calc_num_ports,
 	.probe		   = sierra_probe,
 	.open              = sierra_open,
@@ -1113,38 +1111,11 @@
 	.read_int_callback = sierra_instat_callback,
 };
 
-/* Functions used by new usb-serial code. */
-static int __init sierra_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&sierra_device);
-	if (retval)
-		goto failed_device_register;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&sierra_device, NULL
+};
 
-
-	retval = usb_register(&sierra_driver);
-	if (retval)
-		goto failed_driver_register;
-
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-
-	return 0;
-
-failed_driver_register:
-	usb_serial_deregister(&sierra_device);
-failed_device_register:
-	return retval;
-}
-
-static void __exit sierra_exit(void)
-{
-	usb_deregister(&sierra_driver);
-	usb_serial_deregister(&sierra_device);
-}
-
-module_init(sierra_init);
-module_exit(sierra_exit);
+module_usb_serial_driver(sierra_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index d7f5eee..f06c9a8 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -156,7 +156,6 @@
 	.probe =		usb_serial_probe,
 	.disconnect =		usb_serial_disconnect,
 	.id_table =		id_table,
-	.no_dynamic_id =	1,
 };
 
 
@@ -649,7 +648,6 @@
 		.name =		"SPCP8x5",
 	},
 	.id_table		= id_table,
-	.usb_driver		= &spcp8x5_driver,
 	.num_ports		= 1,
 	.open 			= spcp8x5_open,
 	.dtr_rts		= spcp8x5_dtr_rts,
@@ -664,32 +662,11 @@
 	.process_read_urb	= spcp8x5_process_read_urb,
 };
 
-static int __init spcp8x5_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&spcp8x5_device);
-	if (retval)
-		goto failed_usb_serial_register;
-	retval = usb_register(&spcp8x5_driver);
-	if (retval)
-		goto failed_usb_register;
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&spcp8x5_device);
-failed_usb_serial_register:
-	return retval;
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+	&spcp8x5_device, NULL
+};
 
-static void __exit spcp8x5_exit(void)
-{
-	usb_deregister(&spcp8x5_driver);
-	usb_serial_deregister(&spcp8x5_device);
-}
-
-module_init(spcp8x5_init);
-module_exit(spcp8x5_exit);
+module_usb_serial_driver(spcp8x5_driver, serial_drivers);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index 7697858..3cdc8a5 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -70,7 +70,6 @@
 	.id_table		       = id_table,
 	.suspend		       = usb_serial_suspend,
 	.resume			       = usb_serial_resume,
-	.no_dynamic_id		       = 1,
 	.supports_autosuspend	       = 1,
 };
 
@@ -677,7 +676,6 @@
 	},
 	.description	     = DRIVER_DESC,
 	.id_table	     = id_table,
-	.usb_driver	     = &ssu100_driver,
 	.num_ports	     = 1,
 	.open		     = ssu100_open,
 	.close		     = ssu100_close,
@@ -693,41 +691,11 @@
 	.disconnect          = usb_serial_generic_disconnect,
 };
 
-static int __init ssu100_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&ssu100_device, NULL
+};
 
-	dbg("%s", __func__);
-
-	/* register with usb-serial */
-	retval = usb_serial_register(&ssu100_device);
-
-	if (retval)
-		goto failed_usb_sio_register;
-
-	retval = usb_register(&ssu100_driver);
-	if (retval)
-		goto failed_usb_register;
-
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-
-	return 0;
-
-failed_usb_register:
-	usb_serial_deregister(&ssu100_device);
-failed_usb_sio_register:
-	return retval;
-}
-
-static void __exit ssu100_exit(void)
-{
-	usb_deregister(&ssu100_driver);
-	usb_serial_deregister(&ssu100_device);
-}
-
-module_init(ssu100_init);
-module_exit(ssu100_exit);
+module_usb_serial_driver(ssu100_driver, serial_drivers);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c
index 50651cf..1a5be13 100644
--- a/drivers/usb/serial/symbolserial.c
+++ b/drivers/usb/serial/symbolserial.c
@@ -287,7 +287,6 @@
 	.probe =		usb_serial_probe,
 	.disconnect =		usb_serial_disconnect,
 	.id_table =		id_table,
-	.no_dynamic_id = 	1,
 };
 
 static struct usb_serial_driver symbol_device = {
@@ -296,7 +295,6 @@
 		.name =		"symbol",
 	},
 	.id_table =		id_table,
-	.usb_driver = 		&symbol_driver,
 	.num_ports =		1,
 	.attach =		symbol_startup,
 	.open =			symbol_open,
@@ -307,27 +305,12 @@
 	.unthrottle =		symbol_unthrottle,
 };
 
-static int __init symbol_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&symbol_device, NULL
+};
 
-	retval = usb_serial_register(&symbol_device);
-	if (retval)
-		return retval;
-	retval = usb_register(&symbol_driver);
-	if (retval)
-		usb_serial_deregister(&symbol_device);
-	return retval;
-}
+module_usb_serial_driver(symbol_driver, serial_drivers);
 
-static void __exit symbol_exit(void)
-{
-	usb_deregister(&symbol_driver);
-	usb_serial_deregister(&symbol_device);
-}
-
-module_init(symbol_init);
-module_exit(symbol_exit);
 MODULE_LICENSE("GPL");
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 75b838e..ab74123 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -216,7 +216,6 @@
 	.probe			= usb_serial_probe,
 	.disconnect		= usb_serial_disconnect,
 	.id_table		= ti_id_table_combined,
-	.no_dynamic_id = 	1,
 };
 
 static struct usb_serial_driver ti_1port_device = {
@@ -225,7 +224,6 @@
 		.name		= "ti_usb_3410_5052_1",
 	},
 	.description		= "TI USB 3410 1 port adapter",
-	.usb_driver		= &ti_usb_driver,
 	.id_table		= ti_id_table_3410,
 	.num_ports		= 1,
 	.attach			= ti_startup,
@@ -254,7 +252,6 @@
 		.name		= "ti_usb_3410_5052_2",
 	},
 	.description		= "TI USB 5052 2 port adapter",
-	.usb_driver		= &ti_usb_driver,
 	.id_table		= ti_id_table_5052,
 	.num_ports		= 2,
 	.attach			= ti_startup,
@@ -277,6 +274,9 @@
 	.write_bulk_callback	= ti_bulk_out_callback,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&ti_1port_device, &ti_2port_device, NULL
+};
 
 /* Module */
 
@@ -344,36 +344,17 @@
 		ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
 	}
 
-	ret = usb_serial_register(&ti_1port_device);
-	if (ret)
-		goto failed_1port;
-	ret = usb_serial_register(&ti_2port_device);
-	if (ret)
-		goto failed_2port;
-
-	ret = usb_register(&ti_usb_driver);
-	if (ret)
-		goto failed_usb;
-
-	printk(KERN_INFO KBUILD_MODNAME ": " TI_DRIVER_VERSION ":"
-	       TI_DRIVER_DESC "\n");
-
-	return 0;
-
-failed_usb:
-	usb_serial_deregister(&ti_2port_device);
-failed_2port:
-	usb_serial_deregister(&ti_1port_device);
-failed_1port:
+	ret = usb_serial_register_drivers(&ti_usb_driver, serial_drivers);
+	if (ret == 0)
+		printk(KERN_INFO KBUILD_MODNAME ": " TI_DRIVER_VERSION ":"
+			       TI_DRIVER_DESC "\n");
 	return ret;
 }
 
 
 static void __exit ti_exit(void)
 {
-	usb_deregister(&ti_usb_driver);
-	usb_serial_deregister(&ti_1port_device);
-	usb_serial_deregister(&ti_2port_device);
+	usb_serial_deregister_drivers(&ti_usb_driver, serial_drivers);
 }
 
 
@@ -1250,7 +1231,6 @@
 {
 	struct ti_port *tport = urb->context;
 	struct usb_serial_port *port = tport->tp_port;
-	struct device *dev = &urb->dev->dev;
 	int status = urb->status;
 
 	dbg("%s - port %d", __func__, port->number);
@@ -1268,7 +1248,7 @@
 		wake_up_interruptible(&tport->tp_write_wait);
 		return;
 	default:
-		dev_err(dev, "%s - nonzero urb status, %d\n",
+		dev_err_console(port, "%s - nonzero urb status, %d\n",
 			__func__, status);
 		tport->tp_tdev->td_urb_error = 1;
 		wake_up_interruptible(&tport->tp_write_wait);
@@ -1337,7 +1317,7 @@
 
 	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
 	if (result) {
-		dev_err(&port->dev, "%s - submit write urb failed, %d\n",
+		dev_err_console(port, "%s - submit write urb failed, %d\n",
 							__func__, result);
 		tport->tp_write_urb_in_use = 0;
 		/* TODO: reschedule ti_send */
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 611b206..69230f0 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -214,15 +214,14 @@
 	if (!try_module_get(serial->type->driver.owner))
 		goto error_module_get;
 
-	/* perform the standard setup */
-	retval = tty_init_termios(tty);
-	if (retval)
-		goto error_init_termios;
-
 	retval = usb_autopm_get_interface(serial->interface);
 	if (retval)
 		goto error_get_interface;
 
+	retval = tty_standard_install(driver, tty);
+	if (retval)
+		goto error_init_termios;
+
 	mutex_unlock(&serial->disc_mutex);
 
 	/* allow the driver to update the settings */
@@ -231,14 +230,11 @@
 
 	tty->driver_data = port;
 
-	/* Final install (we use the default method) */
-	tty_driver_kref_get(driver);
-	tty->count++;
-	driver->ttys[idx] = tty;
 	return retval;
 
- error_get_interface:
  error_init_termios:
+	usb_autopm_put_interface(serial->interface);
+ error_get_interface:
 	module_put(serial->type->driver.owner);
  error_module_get:
  error_no_port:
@@ -1239,7 +1235,6 @@
 		goto exit_bus;
 	}
 
-	usb_serial_tty_driver->owner = THIS_MODULE;
 	usb_serial_tty_driver->driver_name = "usbserial";
 	usb_serial_tty_driver->name = "ttyUSB";
 	usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
@@ -1338,7 +1333,7 @@
 	set_to_generic_if_null(device, prepare_write_buffer);
 }
 
-int usb_serial_register(struct usb_serial_driver *driver)
+static int usb_serial_register(struct usb_serial_driver *driver)
 {
 	int retval;
 
@@ -1372,10 +1367,8 @@
 	mutex_unlock(&table_lock);
 	return retval;
 }
-EXPORT_SYMBOL_GPL(usb_serial_register);
 
-
-void usb_serial_deregister(struct usb_serial_driver *device)
+static void usb_serial_deregister(struct usb_serial_driver *device)
 {
 	printk(KERN_INFO "USB Serial deregistering driver %s\n",
 	       device->description);
@@ -1384,7 +1377,76 @@
 	usb_serial_bus_deregister(device);
 	mutex_unlock(&table_lock);
 }
-EXPORT_SYMBOL_GPL(usb_serial_deregister);
+
+/**
+ * usb_serial_register_drivers - register drivers for a usb-serial module
+ * @udriver: usb_driver used for matching devices/interfaces
+ * @serial_drivers: NULL-terminated array of pointers to drivers to be registered
+ *
+ * Registers @udriver and all the drivers in the @serial_drivers array.
+ * Automatically fills in the .no_dynamic_id field in @udriver and
+ * the .usb_driver field in each serial driver.
+ */
+int usb_serial_register_drivers(struct usb_driver *udriver,
+		struct usb_serial_driver * const serial_drivers[])
+{
+	int rc;
+	const struct usb_device_id *saved_id_table;
+	struct usb_serial_driver * const *sd;
+
+	/*
+	 * udriver must be registered before any of the serial drivers,
+	 * because the store_new_id() routine for the serial drivers (in
+	 * bus.c) probes udriver.
+	 *
+	 * Performance hack: We don't want udriver to be probed until
+	 * the serial drivers are registered, because the probe would
+	 * simply fail for lack of a matching serial driver.
+	 * Therefore save off udriver's id_table until we are all set.
+	 */
+	saved_id_table = udriver->id_table;
+	udriver->id_table = NULL;
+
+	udriver->no_dynamic_id = 1;
+	rc = usb_register(udriver);
+	if (rc)
+		return rc;
+
+	for (sd = serial_drivers; *sd; ++sd) {
+		(*sd)->usb_driver = udriver;
+		rc = usb_serial_register(*sd);
+		if (rc)
+			goto failed;
+	}
+
+	/* Now restore udriver's id_table and look for matches */
+	udriver->id_table = saved_id_table;
+	rc = driver_attach(&udriver->drvwrap.driver);
+	return 0;
+
+ failed:
+	while (sd-- > serial_drivers)
+		usb_serial_deregister(*sd);
+	usb_deregister(udriver);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(usb_serial_register_drivers);
+
+/**
+ * usb_serial_deregister_drivers - deregister drivers for a usb-serial module
+ * @udriver: usb_driver to unregister
+ * @serial_drivers: NULL-terminated array of pointers to drivers to be deregistered
+ *
+ * Deregisters @udriver and all the drivers in the @serial_drivers array.
+ */
+void usb_serial_deregister_drivers(struct usb_driver *udriver,
+		struct usb_serial_driver * const serial_drivers[])
+{
+	for (; *serial_drivers; ++serial_drivers)
+		usb_serial_deregister(*serial_drivers);
+	usb_deregister(udriver);
+}
+EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers);
 
 /* Module information */
 MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
index 9b632e7..e3e8995 100644
--- a/drivers/usb/serial/usb_debug.c
+++ b/drivers/usb/serial/usb_debug.c
@@ -40,7 +40,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id =	1,
 };
 
 /* This HW really does not support a serial break, so one will be
@@ -74,32 +73,15 @@
 		.name =		"debug",
 	},
 	.id_table =		id_table,
-	.usb_driver =		&debug_driver,
 	.num_ports =		1,
 	.bulk_out_size =	USB_DEBUG_MAX_PACKET_SIZE,
 	.break_ctl =		usb_debug_break_ctl,
 	.process_read_urb =	usb_debug_process_read_urb,
 };
 
-static int __init debug_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&debug_device, NULL
+};
 
-	retval = usb_serial_register(&debug_device);
-	if (retval)
-		return retval;
-	retval = usb_register(&debug_driver);
-	if (retval)
-		usb_serial_deregister(&debug_device);
-	return retval;
-}
-
-static void __exit debug_exit(void)
-{
-	usb_deregister(&debug_driver);
-	usb_serial_deregister(&debug_device);
-}
-
-module_init(debug_init);
-module_exit(debug_exit);
+module_usb_serial_driver(debug_driver, serial_drivers);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 210e4b1..71d6964 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -173,7 +173,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table_combined,
-	.no_dynamic_id = 	1,
 };
 
 /* All of the device info needed for the Handspring Visor,
@@ -184,7 +183,6 @@
 		.name =		"visor",
 	},
 	.description =		"Handspring Visor / Palm OS",
-	.usb_driver =		&visor_driver,
 	.id_table =		id_table,
 	.num_ports =		2,
 	.bulk_out_size =	256,
@@ -205,7 +203,6 @@
 		.name =		"clie_5",
 	},
 	.description =		"Sony Clie 5.0",
-	.usb_driver =		&visor_driver,
 	.id_table =		clie_id_5_table,
 	.num_ports =		2,
 	.bulk_out_size =	256,
@@ -226,7 +223,6 @@
 		.name =		"clie_3.5",
 	},
 	.description =		"Sony Clie 3.5",
-	.usb_driver =		&visor_driver,
 	.id_table =		clie_id_3_5_table,
 	.num_ports =		1,
 	.bulk_out_size =	256,
@@ -237,6 +233,10 @@
 	.attach =		clie_3_5_startup,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&handspring_device, &clie_5_device, &clie_3_5_device, NULL
+};
+
 /******************************************************************************
  * Handspring Visor specific driver functions
  ******************************************************************************/
@@ -685,38 +685,17 @@
 		       ": Adding Palm OS protocol 4.x support for unknown device: 0x%x/0x%x\n",
 			vendor, product);
 	}
-	retval = usb_serial_register(&handspring_device);
-	if (retval)
-		goto failed_handspring_register;
-	retval = usb_serial_register(&clie_3_5_device);
-	if (retval)
-		goto failed_clie_3_5_register;
-	retval = usb_serial_register(&clie_5_device);
-	if (retval)
-		goto failed_clie_5_register;
-	retval = usb_register(&visor_driver);
-	if (retval)
-		goto failed_usb_register;
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
 
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&clie_5_device);
-failed_clie_5_register:
-	usb_serial_deregister(&clie_3_5_device);
-failed_clie_3_5_register:
-	usb_serial_deregister(&handspring_device);
-failed_handspring_register:
+	retval = usb_serial_register_drivers(&visor_driver, serial_drivers);
+	if (retval == 0)
+		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
 	return retval;
 }
 
 
 static void __exit visor_exit (void)
 {
-	usb_deregister(&visor_driver);
-	usb_serial_deregister(&handspring_device);
-	usb_serial_deregister(&clie_3_5_device);
-	usb_serial_deregister(&clie_5_device);
+	usb_serial_deregister_drivers(&visor_driver, serial_drivers);
 }
 
 
diff --git a/drivers/usb/serial/vivopay-serial.c b/drivers/usb/serial/vivopay-serial.c
index f719d00..078f338 100644
--- a/drivers/usb/serial/vivopay-serial.c
+++ b/drivers/usb/serial/vivopay-serial.c
@@ -30,7 +30,6 @@
 	.probe =		usb_serial_probe,
 	.disconnect =		usb_serial_disconnect,
 	.id_table =		id_table,
-	.no_dynamic_id =	1,
 };
 
 static struct usb_serial_driver vivopay_serial_device = {
@@ -39,36 +38,14 @@
 		.name =		"vivopay-serial",
 	},
 	.id_table =		id_table,
-	.usb_driver =		&vivopay_serial_driver,
 	.num_ports =		1,
 };
 
-static int __init vivopay_serial_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&vivopay_serial_device);
-	if (retval)
-		goto failed_usb_serial_register;
-	retval = usb_register(&vivopay_serial_driver);
-	if (retval)
-		goto failed_usb_register;
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	    DRIVER_DESC "\n");
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&vivopay_serial_device);
-failed_usb_serial_register:
-	return retval;
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+	&vivopay_serial_device, NULL
+};
 
-static void __exit vivopay_serial_exit(void)
-{
-	usb_deregister(&vivopay_serial_driver);
-	usb_serial_deregister(&vivopay_serial_device);
-}
-
-module_init(vivopay_serial_init);
-module_exit(vivopay_serial_exit);
+module_usb_serial_driver(vivopay_serial_driver, serial_drivers);
 
 MODULE_AUTHOR("Forest Bond <forest.bond@outpostembedded.com>");
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 7e0acf5..407e23c 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -83,7 +83,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table_combined,
-	.no_dynamic_id = 	1,
 };
 
 /* function prototypes for the Connect Tech WhiteHEAT prerenumeration device */
@@ -121,7 +120,6 @@
 		.name =		"whiteheatnofirm",
 	},
 	.description =		"Connect Tech - WhiteHEAT - (prerenumeration)",
-	.usb_driver =		&whiteheat_driver,
 	.id_table =		id_table_prerenumeration,
 	.num_ports =		1,
 	.probe =		whiteheat_firmware_download,
@@ -134,7 +132,6 @@
 		.name =		"whiteheat",
 	},
 	.description =		"Connect Tech - WhiteHEAT",
-	.usb_driver =		&whiteheat_driver,
 	.id_table =		id_table_std,
 	.num_ports =		4,
 	.attach =		whiteheat_attach,
@@ -155,6 +152,9 @@
 	.write_bulk_callback =	whiteheat_write_callback,
 };
 
+static struct usb_serial_driver * const serial_drivers[] = {
+	&whiteheat_fake_device, &whiteheat_device, NULL
+};
 
 struct whiteheat_command_private {
 	struct mutex		mutex;
@@ -740,7 +740,7 @@
 		urb->transfer_buffer_length = bytes;
 		result = usb_submit_urb(urb, GFP_ATOMIC);
 		if (result) {
-			dev_err(&port->dev,
+			dev_err_console(port,
 				"%s - failed submitting write urb, error %d\n",
 				__func__, result);
 			sent = result;
@@ -1454,44 +1454,7 @@
 	tty_kref_put(tty);
 }
 
-
-/*****************************************************************************
- * Connect Tech's White Heat module functions
- *****************************************************************************/
-static int __init whiteheat_init(void)
-{
-	int retval;
-	retval = usb_serial_register(&whiteheat_fake_device);
-	if (retval)
-		goto failed_fake_register;
-	retval = usb_serial_register(&whiteheat_device);
-	if (retval)
-		goto failed_device_register;
-	retval = usb_register(&whiteheat_driver);
-	if (retval)
-		goto failed_usb_register;
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-failed_usb_register:
-	usb_serial_deregister(&whiteheat_device);
-failed_device_register:
-	usb_serial_deregister(&whiteheat_fake_device);
-failed_fake_register:
-	return retval;
-}
-
-
-static void __exit whiteheat_exit(void)
-{
-	usb_deregister(&whiteheat_driver);
-	usb_serial_deregister(&whiteheat_fake_device);
-	usb_serial_deregister(&whiteheat_device);
-}
-
-
-module_init(whiteheat_init);
-module_exit(whiteheat_exit);
+module_usb_serial_driver(whiteheat_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/zio.c b/drivers/usb/serial/zio.c
index f579672..9d0bb37 100644
--- a/drivers/usb/serial/zio.c
+++ b/drivers/usb/serial/zio.c
@@ -27,7 +27,6 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id =	1,
 };
 
 static struct usb_serial_driver zio_device = {
@@ -36,29 +35,12 @@
 		.name =		"zio",
 	},
 	.id_table =		id_table,
-	.usb_driver =		&zio_driver,
 	.num_ports =		1,
 };
 
-static int __init zio_init(void)
-{
-	int retval;
+static struct usb_serial_driver * const serial_drivers[] = {
+	&zio_device, NULL
+};
 
-	retval = usb_serial_register(&zio_device);
-	if (retval)
-		return retval;
-	retval = usb_register(&zio_driver);
-	if (retval)
-		usb_serial_deregister(&zio_device);
-	return retval;
-}
-
-static void __exit zio_exit(void)
-{
-	usb_deregister(&zio_driver);
-	usb_serial_deregister(&zio_device);
-}
-
-module_init(zio_init);
-module_exit(zio_exit);
+module_usb_serial_driver(zio_driver, serial_drivers);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c
index 51af2fe..bab8c8f 100644
--- a/drivers/usb/storage/alauda.c
+++ b/drivers/usb/storage/alauda.c
@@ -1276,6 +1276,7 @@
 	.post_reset =	usb_stor_post_reset,
 	.id_table =	alauda_usb_ids,
 	.soft_unbind =	1,
+	.no_dynamic_id = 1,
 };
 
 module_usb_driver(alauda_driver);
diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c
index 387cbd47..5fe451d 100644
--- a/drivers/usb/storage/cypress_atacb.c
+++ b/drivers/usb/storage/cypress_atacb.c
@@ -272,6 +272,7 @@
 	.post_reset =	usb_stor_post_reset,
 	.id_table =	cypress_usb_ids,
 	.soft_unbind =	1,
+	.no_dynamic_id = 1,
 };
 
 module_usb_driver(cypress_driver);
diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c
index 15d41f2..35e9c51 100644
--- a/drivers/usb/storage/datafab.c
+++ b/drivers/usb/storage/datafab.c
@@ -751,6 +751,7 @@
 	.post_reset =	usb_stor_post_reset,
 	.id_table =	datafab_usb_ids,
 	.soft_unbind =	1,
+	.no_dynamic_id = 1,
 };
 
 module_usb_driver(datafab_driver);
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index a6ade40..e7e6781 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -674,7 +674,7 @@
 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 	bcb->DataTransferLength = blenByte;
-	bcb->Flags  = 0x80;
+	bcb->Flags  = US_BULK_FLAG_IN;
 	bcb->CDB[0] = 0xF1;
 	bcb->CDB[5] = (unsigned char)(bnByte);
 	bcb->CDB[4] = (unsigned char)(bnByte>>8);
@@ -858,7 +858,7 @@
 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 	bcb->DataTransferLength = 0x200;
-	bcb->Flags      = 0x80;
+	bcb->Flags      = US_BULK_FLAG_IN;
 	bcb->CDB[0]     = 0xF1;
 
 	bcb->CDB[1]     = 0x02; /* in init.c ENE_MSInit() is 0x01 */
@@ -877,7 +877,7 @@
 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 	bcb->DataTransferLength = 0x4;
-	bcb->Flags      = 0x80;
+	bcb->Flags      = US_BULK_FLAG_IN;
 	bcb->CDB[0]     = 0xF1;
 	bcb->CDB[1]     = 0x03;
 
@@ -1170,7 +1170,7 @@
 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 	bcb->DataTransferLength = 0x200;
-	bcb->Flags = 0x80;
+	bcb->Flags = US_BULK_FLAG_IN;
 	bcb->CDB[0] = 0xF2;
 	bcb->CDB[1] = 0x06;
 	bcb->CDB[4] = (unsigned char)(bn);
@@ -1249,7 +1249,7 @@
 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 	bcb->DataTransferLength = 0x4;
-	bcb->Flags = 0x80;
+	bcb->Flags = US_BULK_FLAG_IN;
 	bcb->CDB[0] = 0xF2;
 	bcb->CDB[1] = 0x05;
 	bcb->CDB[5] = (unsigned char)(PageNum);
@@ -1331,7 +1331,7 @@
 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 	bcb->DataTransferLength = 0x4;
-	bcb->Flags      = 0x80;
+	bcb->Flags      = US_BULK_FLAG_IN;
 	bcb->CDB[0]     = 0xF1;
 	bcb->CDB[1]     = 0x03;
 	bcb->CDB[5]     = (unsigned char)(PageNum);
@@ -1533,7 +1533,7 @@
 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 	bcb->DataTransferLength = 0x4 * blen;
-	bcb->Flags      = 0x80;
+	bcb->Flags      = US_BULK_FLAG_IN;
 	bcb->CDB[0]     = 0xF1;
 	bcb->CDB[1]     = 0x03;
 	bcb->CDB[5]     = (unsigned char)(PageNum);
@@ -1650,7 +1650,7 @@
 		memset(bcb, 0, sizeof(struct bulk_cb_wrap));
 		bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 		bcb->DataTransferLength = blenByte;
-		bcb->Flags  = 0x80;
+		bcb->Flags  = US_BULK_FLAG_IN;
 		bcb->CDB[0] = 0xF1;
 		bcb->CDB[1] = 0x02;
 		bcb->CDB[5] = (unsigned char)(bn);
@@ -1694,7 +1694,7 @@
 			memset(bcb, 0, sizeof(struct bulk_cb_wrap));
 			bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 			bcb->DataTransferLength = 0x200 * len;
-			bcb->Flags  = 0x80;
+			bcb->Flags  = US_BULK_FLAG_IN;
 			bcb->CDB[0] = 0xF1;
 			bcb->CDB[1] = 0x02;
 			bcb->CDB[5] = (unsigned char)(blkno);
@@ -1827,7 +1827,7 @@
 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 	bcb->DataTransferLength	= 0x01;
-	bcb->Flags			= 0x80;
+	bcb->Flags			= US_BULK_FLAG_IN;
 	bcb->CDB[0]			= 0xED;
 	bcb->CDB[2]			= (unsigned char)(index>>8);
 	bcb->CDB[3]			= (unsigned char)index;
@@ -2083,7 +2083,7 @@
 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 	bcb->DataTransferLength = 0x200;
-	bcb->Flags      = 0x80;
+	bcb->Flags      = US_BULK_FLAG_IN;
 	bcb->CDB[0]     = 0xF1;
 	bcb->CDB[1]     = 0x01;
 
@@ -2134,7 +2134,7 @@
 
 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
-	bcb->Flags = 0x80;
+	bcb->Flags = US_BULK_FLAG_IN;
 	bcb->CDB[0] = 0xF2;
 
 	result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
@@ -2153,7 +2153,7 @@
 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 	bcb->DataTransferLength = 0x200;
-	bcb->Flags              = 0x80;
+	bcb->Flags              = US_BULK_FLAG_IN;
 	bcb->CDB[0]             = 0xF1;
 
 	result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0);
@@ -2407,6 +2407,7 @@
 	.post_reset =	usb_stor_post_reset,
 	.id_table =	ene_ub6250_usb_ids,
 	.soft_unbind =	1,
+	.no_dynamic_id = 1,
 };
 
 module_usb_driver(ene_ub6250_driver);
diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
index fa16157..042cf9e 100644
--- a/drivers/usb/storage/freecom.c
+++ b/drivers/usb/storage/freecom.c
@@ -553,6 +553,7 @@
 	.post_reset =	usb_stor_post_reset,
 	.id_table =	freecom_usb_ids,
 	.soft_unbind =	1,
+	.no_dynamic_id = 1,
 };
 
 module_usb_driver(freecom_driver);
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index bd55027..31fa24e 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -1566,6 +1566,7 @@
 	.post_reset =	usb_stor_post_reset,
 	.id_table =	isd200_usb_ids,
 	.soft_unbind =	1,
+	.no_dynamic_id = 1,
 };
 
 module_usb_driver(isd200_driver);
diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
index a19211b..e3b9738 100644
--- a/drivers/usb/storage/jumpshot.c
+++ b/drivers/usb/storage/jumpshot.c
@@ -677,6 +677,7 @@
 	.post_reset =	usb_stor_post_reset,
 	.id_table =	jumpshot_usb_ids,
 	.soft_unbind =	1,
+	.no_dynamic_id = 1,
 };
 
 module_usb_driver(jumpshot_driver);
diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c
index e720f8e..a8708ea 100644
--- a/drivers/usb/storage/karma.c
+++ b/drivers/usb/storage/karma.c
@@ -230,6 +230,7 @@
 	.post_reset =	usb_stor_post_reset,
 	.id_table =	karma_usb_ids,
 	.soft_unbind =	1,
+	.no_dynamic_id = 1,
 };
 
 module_usb_driver(karma_driver);
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index d75155c..886567a 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -312,6 +312,7 @@
 	.post_reset =	usb_stor_post_reset,
 	.id_table =	onetouch_usb_ids,
 	.soft_unbind =	1,
+	.no_dynamic_id = 1,
 };
 
 module_usb_driver(onetouch_driver);
diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c
index d32f720..63cf282 100644
--- a/drivers/usb/storage/realtek_cr.c
+++ b/drivers/usb/storage/realtek_cr.c
@@ -219,7 +219,7 @@
 	/* set up the command wrapper */
 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 	bcb->DataTransferLength = cpu_to_le32(buf_len);
-	bcb->Flags = (dir == DMA_FROM_DEVICE) ? 1 << 7 : 0;
+	bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : 0;
 	bcb->Tag = ++us->tag;
 	bcb->Lun = lun;
 	bcb->Length = cmd_len;
@@ -305,7 +305,7 @@
 	/* set up the command wrapper */
 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 	bcb->DataTransferLength = cpu_to_le32(buf_len);
-	bcb->Flags = (dir == DMA_FROM_DEVICE) ? 1 << 7 : 0;
+	bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : 0;
 	bcb->Tag = ++us->tag;
 	bcb->Lun = lun;
 	bcb->Length = cmd_len;
@@ -507,9 +507,14 @@
 {
 	int retval;
 	u8 cmnd[12] = {0};
+	u8 *buf;
 
 	US_DEBUGP("%s, addr = 0xfe47, len = %d\n", __FUNCTION__, len);
 
+	buf = kmemdup(data, len, GFP_NOIO);
+	if (!buf)
+		return USB_STOR_TRANSPORT_ERROR;
+
 	cmnd[0] = 0xF0;
 	cmnd[1] = 0x0E;
 	cmnd[2] = 0xfe;
@@ -517,7 +522,8 @@
 	cmnd[4] = (u8)(len >> 8);
 	cmnd[5] = (u8)len;
 
-	retval = rts51x_bulk_transport_special(us, 0, cmnd, 12, data, len, DMA_TO_DEVICE, NULL);
+	retval = rts51x_bulk_transport_special(us, 0, cmnd, 12, buf, len, DMA_TO_DEVICE, NULL);
+	kfree(buf);
 	if (retval != USB_STOR_TRANSPORT_GOOD) {
 		return -EIO;
 	}
@@ -1100,6 +1106,7 @@
 	.id_table = realtek_cr_ids,
 	.soft_unbind = 1,
 	.supports_autosuspend = 1,
+	.no_dynamic_id = 1,
 };
 
 module_usb_driver(realtek_cr_driver);
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 13b8bcd..a324a5d 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -78,8 +78,6 @@
 
 static int slave_alloc (struct scsi_device *sdev)
 {
-	struct us_data *us = host_to_us(sdev->host);
-
 	/*
 	 * Set the INQUIRY transfer length to 36.  We don't use any of
 	 * the extra data and many devices choke if asked for more or
@@ -104,18 +102,6 @@
 	 */
 	blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
 
-	/*
-	 * The UFI spec treates the Peripheral Qualifier bits in an
-	 * INQUIRY result as reserved and requires devices to set them
-	 * to 0.  However the SCSI spec requires these bits to be set
-	 * to 3 to indicate when a LUN is not present.
-	 *
-	 * Let the scanning code know if this target merely sets
-	 * Peripheral Device Type to 0x1f to indicate no LUN.
-	 */
-	if (us->subclass == USB_SC_UFI)
-		sdev->sdev_target->pdt_1f_for_no_lun = 1;
-
 	return 0;
 }
 
@@ -197,6 +183,9 @@
 		 * page x08, so we will skip it. */
 		sdev->skip_ms_page_8 = 1;
 
+		/* Some devices don't handle VPD pages correctly */
+		sdev->skip_vpd_pages = 1;
+
 		/* Some disks return the total number of blocks in response
 		 * to READ CAPACITY rather than the highest block number.
 		 * If this device makes that mistake, tell the sd driver. */
@@ -217,16 +206,6 @@
 		if (sdev->scsi_level > SCSI_SPC_2)
 			us->fflags |= US_FL_SANE_SENSE;
 
-		/* Some devices report a SCSI revision level above 2 but are
-		 * unable to handle the REPORT LUNS command (for which
-		 * support is mandatory at level 3).  Since we already have
-		 * a Get-Max-LUN request, we won't lose much by setting the
-		 * revision level down to 2.  The only devices that would be
-		 * affected are those with sparse LUNs. */
-		if (sdev->scsi_level > SCSI_2)
-			sdev->sdev_target->scsi_level =
-					sdev->scsi_level = SCSI_2;
-
 		/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
 		 * Hardware Error) when any low-level error occurs,
 		 * recoverable or not.  Setting this flag tells the SCSI
@@ -283,6 +262,33 @@
 	return 0;
 }
 
+static int target_alloc(struct scsi_target *starget)
+{
+	struct us_data *us = host_to_us(dev_to_shost(starget->dev.parent));
+
+	/*
+	 * Some USB drives don't support REPORT LUNS, even though they
+	 * report a SCSI revision level above 2.  Tell the SCSI layer
+	 * not to issue that command; it will perform a normal sequential
+	 * scan instead.
+	 */
+	starget->no_report_luns = 1;
+
+	/*
+	 * The UFI spec treats the Peripheral Qualifier bits in an
+	 * INQUIRY result as reserved and requires devices to set them
+	 * to 0.  However the SCSI spec requires these bits to be set
+	 * to 3 to indicate when a LUN is not present.
+	 *
+	 * Let the scanning code know if this target merely sets
+	 * Peripheral Device Type to 0x1f to indicate no LUN.
+	 */
+	if (us->subclass == USB_SC_UFI)
+		starget->pdt_1f_for_no_lun = 1;
+
+	return 0;
+}
+
 /* queue a command */
 /* This is always called with scsi_lock(host) held */
 static int queuecommand_lck(struct scsi_cmnd *srb,
@@ -546,6 +552,7 @@
 
 	.slave_alloc =			slave_alloc,
 	.slave_configure =		slave_configure,
+	.target_alloc =			target_alloc,
 
 	/* lots of sg segments can be handled */
 	.sg_tablesize =			SCSI_MAX_SG_CHAIN_SEGMENTS,
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index 425df7d..3252a62 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -1787,6 +1787,7 @@
 	.post_reset =	usb_stor_post_reset,
 	.id_table =	sddr09_usb_ids,
 	.soft_unbind =	1,
+	.no_dynamic_id = 1,
 };
 
 module_usb_driver(sddr09_driver);
diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c
index e4ca5fc..c144078 100644
--- a/drivers/usb/storage/sddr55.c
+++ b/drivers/usb/storage/sddr55.c
@@ -1006,6 +1006,7 @@
 	.post_reset =	usb_stor_post_reset,
 	.id_table =	sddr55_usb_ids,
 	.soft_unbind =	1,
+	.no_dynamic_id = 1,
 };
 
 module_usb_driver(sddr55_driver);
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index 1369d25..fa1ceeb 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -1863,6 +1863,7 @@
 	.post_reset =	usb_stor_post_reset,
 	.id_table =	usbat_usb_ids,
 	.soft_unbind =	1,
+	.no_dynamic_id = 1,
 };
 
 module_usb_driver(usbat_driver);
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 0e5c91c..c70109e 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -1071,7 +1071,8 @@
 	/* set up the command wrapper */
 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 	bcb->DataTransferLength = cpu_to_le32(transfer_length);
-	bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0;
+	bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ?
+		US_BULK_FLAG_IN : 0;
 	bcb->Tag = ++us->tag;
 	bcb->Lun = srb->device->lun;
 	if (us->fflags & US_FL_SCM_MULT_TARG)
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
index 242ff5e..9369d75 100644
--- a/drivers/usb/storage/transport.h
+++ b/drivers/usb/storage/transport.h
@@ -42,45 +42,6 @@
 #include <linux/blkdev.h>
 
 /*
- * Bulk only data structures
- */
-
-/* command block wrapper */
-struct bulk_cb_wrap {
-	__le32	Signature;		/* contains 'USBC' */
-	__u32	Tag;			/* unique per command id */
-	__le32	DataTransferLength;	/* size of data */
-	__u8	Flags;			/* direction in bit 0 */
-	__u8	Lun;			/* LUN normally 0 */
-	__u8	Length;			/* of of the CDB */
-	__u8	CDB[16];		/* max command */
-};
-
-#define US_BULK_CB_WRAP_LEN	31
-#define US_BULK_CB_SIGN		0x43425355	/*spells out USBC */
-#define US_BULK_FLAG_IN		1
-#define US_BULK_FLAG_OUT	0
-
-/* command status wrapper */
-struct bulk_cs_wrap {
-	__le32	Signature;		/* should = 'USBS' */
-	__u32	Tag;			/* same as original command */
-	__le32	Residue;		/* amount not transferred */
-	__u8	Status;			/* see below */
-	__u8	Filler[18];
-};
-
-#define US_BULK_CS_WRAP_LEN	13
-#define US_BULK_CS_SIGN		0x53425355	/* spells out 'USBS' */
-#define US_BULK_STAT_OK		0
-#define US_BULK_STAT_FAIL	1
-#define US_BULK_STAT_PHASE	2
-
-/* bulk-only class specific requests */
-#define US_BULK_RESET_REQUEST	0xff
-#define US_BULK_GET_MAX_LUN	0xfe
-
-/*
  * usb_stor_bulk_transfer_xxx() return codes, in order of severity
  */
 
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index a33ead5..8ec8a6e 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -13,7 +13,9 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 #include <linux/usb/storage.h>
+#include <linux/usb/uas.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_dbg.h>
@@ -22,49 +24,6 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
 
-/* Common header for all IUs */
-struct iu {
-	__u8 iu_id;
-	__u8 rsvd1;
-	__be16 tag;
-};
-
-enum {
-	IU_ID_COMMAND		= 0x01,
-	IU_ID_STATUS		= 0x03,
-	IU_ID_RESPONSE		= 0x04,
-	IU_ID_TASK_MGMT		= 0x05,
-	IU_ID_READ_READY	= 0x06,
-	IU_ID_WRITE_READY	= 0x07,
-};
-
-struct command_iu {
-	__u8 iu_id;
-	__u8 rsvd1;
-	__be16 tag;
-	__u8 prio_attr;
-	__u8 rsvd5;
-	__u8 len;
-	__u8 rsvd7;
-	struct scsi_lun lun;
-	__u8 cdb[16];	/* XXX: Overflow-checking tools may misunderstand */
-};
-
-/*
- * Also used for the Read Ready and Write Ready IUs since they have the
- * same first four bytes
- */
-struct sense_iu {
-	__u8 iu_id;
-	__u8 rsvd1;
-	__be16 tag;
-	__be16 status_qual;
-	__u8 status;
-	__u8 rsvd7[7];
-	__be16 len;
-	__u8 sense[SCSI_SENSE_BUFFERSIZE];
-};
-
 /*
  * The r00-r01c specs define this version of the SENSE IU data structure.
  * It's still in use by several different firmware releases.
@@ -79,18 +38,6 @@
 	__u8 sense[SCSI_SENSE_BUFFERSIZE];
 };
 
-enum {
-	CMD_PIPE_ID		= 1,
-	STATUS_PIPE_ID		= 2,
-	DATA_IN_PIPE_ID		= 3,
-	DATA_OUT_PIPE_ID	= 4,
-
-	UAS_SIMPLE_TAG		= 0,
-	UAS_HEAD_TAG		= 1,
-	UAS_ORDERED_TAG		= 2,
-	UAS_ACA			= 4,
-};
-
 struct uas_dev_info {
 	struct usb_interface *intf;
 	struct usb_device *udev;
@@ -98,6 +45,8 @@
 	unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
 	unsigned use_streams:1;
 	unsigned uas_sense_old:1;
+	struct scsi_cmnd *cmnd;
+	struct urb *status_urb; /* used only if stream support is available */
 };
 
 enum {
@@ -109,6 +58,9 @@
 	SUBMIT_DATA_OUT_URB	= (1 << 5),
 	ALLOC_CMD_URB		= (1 << 6),
 	SUBMIT_CMD_URB		= (1 << 7),
+	COMPLETED_DATA_IN	= (1 << 8),
+	COMPLETED_DATA_OUT	= (1 << 9),
+	DATA_COMPLETES_CMD	= (1 << 10),
 };
 
 /* Overrides scsi_pointer */
@@ -116,6 +68,7 @@
 	unsigned int state;
 	unsigned int stream;
 	struct urb *cmd_urb;
+	/* status_urb is used only if stream support isn't available */
 	struct urb *status_urb;
 	struct urb *data_in_urb;
 	struct urb *data_out_urb;
@@ -125,33 +78,43 @@
 /* I hate forward declarations, but I actually have a loop */
 static int uas_submit_urbs(struct scsi_cmnd *cmnd,
 				struct uas_dev_info *devinfo, gfp_t gfp);
+static void uas_do_work(struct work_struct *work);
 
+static DECLARE_WORK(uas_work, uas_do_work);
 static DEFINE_SPINLOCK(uas_work_lock);
 static LIST_HEAD(uas_work_list);
 
 static void uas_do_work(struct work_struct *work)
 {
 	struct uas_cmd_info *cmdinfo;
+	struct uas_cmd_info *temp;
 	struct list_head list;
+	int err;
 
 	spin_lock_irq(&uas_work_lock);
 	list_replace_init(&uas_work_list, &list);
 	spin_unlock_irq(&uas_work_lock);
 
-	list_for_each_entry(cmdinfo, &list, list) {
+	list_for_each_entry_safe(cmdinfo, temp, &list, list) {
 		struct scsi_pointer *scp = (void *)cmdinfo;
 		struct scsi_cmnd *cmnd = container_of(scp,
 							struct scsi_cmnd, SCp);
-		uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
+		err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
+		if (err) {
+			list_del(&cmdinfo->list);
+			spin_lock_irq(&uas_work_lock);
+			list_add_tail(&cmdinfo->list, &uas_work_list);
+			spin_unlock_irq(&uas_work_lock);
+			schedule_work(&uas_work);
+		}
 	}
 }
 
-static DECLARE_WORK(uas_work, uas_do_work);
-
 static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
 {
 	struct sense_iu *sense_iu = urb->transfer_buffer;
 	struct scsi_device *sdev = cmnd->device;
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
 
 	if (urb->actual_length > 16) {
 		unsigned len = be16_to_cpup(&sense_iu->len);
@@ -169,16 +132,15 @@
 	}
 
 	cmnd->result = sense_iu->status;
-	if (sdev->current_cmnd)
-		sdev->current_cmnd = NULL;
-	cmnd->scsi_done(cmnd);
-	usb_free_urb(urb);
+	if (!(cmdinfo->state & DATA_COMPLETES_CMD))
+		cmnd->scsi_done(cmnd);
 }
 
 static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
 {
 	struct sense_iu_old *sense_iu = urb->transfer_buffer;
 	struct scsi_device *sdev = cmnd->device;
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
 
 	if (urb->actual_length > 8) {
 		unsigned len = be16_to_cpup(&sense_iu->len) - 2;
@@ -196,10 +158,8 @@
 	}
 
 	cmnd->result = sense_iu->status;
-	if (sdev->current_cmnd)
-		sdev->current_cmnd = NULL;
-	cmnd->scsi_done(cmnd);
-	usb_free_urb(urb);
+	if (!(cmdinfo->state & DATA_COMPLETES_CMD))
+		cmnd->scsi_done(cmnd);
 }
 
 static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
@@ -208,7 +168,7 @@
 	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
 	int err;
 
-	cmdinfo->state = direction | SUBMIT_STATUS_URB;
+	cmdinfo->state = direction;
 	err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
 	if (err) {
 		spin_lock(&uas_work_lock);
@@ -221,27 +181,61 @@
 static void uas_stat_cmplt(struct urb *urb)
 {
 	struct iu *iu = urb->transfer_buffer;
-	struct scsi_device *sdev = urb->context;
-	struct uas_dev_info *devinfo = sdev->hostdata;
+	struct Scsi_Host *shost = urb->context;
+	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
 	struct scsi_cmnd *cmnd;
+	struct uas_cmd_info *cmdinfo;
 	u16 tag;
+	int ret;
 
 	if (urb->status) {
 		dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status);
-		usb_free_urb(urb);
+		if (devinfo->use_streams)
+			usb_free_urb(urb);
 		return;
 	}
 
 	tag = be16_to_cpup(&iu->tag) - 1;
-	if (sdev->current_cmnd)
-		cmnd = sdev->current_cmnd;
+	if (tag == 0)
+		cmnd = devinfo->cmnd;
 	else
-		cmnd = scsi_find_tag(sdev, tag);
-	if (!cmnd)
+		cmnd = scsi_host_find_tag(shost, tag - 1);
+	if (!cmnd) {
+		if (devinfo->use_streams) {
+			usb_free_urb(urb);
+			return;
+		}
+		ret = usb_submit_urb(urb, GFP_ATOMIC);
+		if (ret)
+			dev_err(&urb->dev->dev, "failed submit status urb\n");
 		return;
+	}
+	cmdinfo = (void *)&cmnd->SCp;
 
 	switch (iu->iu_id) {
 	case IU_ID_STATUS:
+		if (devinfo->cmnd == cmnd)
+			devinfo->cmnd = NULL;
+
+		if (!(cmdinfo->state & COMPLETED_DATA_IN) &&
+				cmdinfo->data_in_urb) {
+		       if (devinfo->use_streams) {
+			       cmdinfo->state |= DATA_COMPLETES_CMD;
+			       usb_unlink_urb(cmdinfo->data_in_urb);
+		       } else {
+			       usb_free_urb(cmdinfo->data_in_urb);
+		       }
+		}
+		if (!(cmdinfo->state & COMPLETED_DATA_OUT) &&
+				cmdinfo->data_out_urb) {
+			if (devinfo->use_streams) {
+				cmdinfo->state |= DATA_COMPLETES_CMD;
+				usb_unlink_urb(cmdinfo->data_in_urb);
+			} else {
+				usb_free_urb(cmdinfo->data_out_urb);
+			}
+		}
+
 		if (urb->actual_length < 16)
 			devinfo->uas_sense_old = 1;
 		if (devinfo->uas_sense_old)
@@ -259,29 +253,70 @@
 		scmd_printk(KERN_ERR, cmnd,
 			"Bogus IU (%d) received on status pipe\n", iu->iu_id);
 	}
+
+	if (devinfo->use_streams) {
+		usb_free_urb(urb);
+		return;
+	}
+
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	if (ret)
+		dev_err(&urb->dev->dev, "failed submit status urb\n");
 }
 
-static void uas_data_cmplt(struct urb *urb)
+static void uas_data_out_cmplt(struct urb *urb)
 {
-	struct scsi_data_buffer *sdb = urb->context;
+	struct scsi_cmnd *cmnd = urb->context;
+	struct scsi_data_buffer *sdb = scsi_out(cmnd);
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+
+	cmdinfo->state |= COMPLETED_DATA_OUT;
+
 	sdb->resid = sdb->length - urb->actual_length;
 	usb_free_urb(urb);
+
+	if (cmdinfo->state & DATA_COMPLETES_CMD)
+		cmnd->scsi_done(cmnd);
+}
+
+static void uas_data_in_cmplt(struct urb *urb)
+{
+	struct scsi_cmnd *cmnd = urb->context;
+	struct scsi_data_buffer *sdb = scsi_in(cmnd);
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+
+	cmdinfo->state |= COMPLETED_DATA_IN;
+
+	sdb->resid = sdb->length - urb->actual_length;
+	usb_free_urb(urb);
+
+	if (cmdinfo->state & DATA_COMPLETES_CMD)
+		cmnd->scsi_done(cmnd);
 }
 
 static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
-				unsigned int pipe, u16 stream_id,
-				struct scsi_data_buffer *sdb,
-				enum dma_data_direction dir)
+		unsigned int pipe, struct scsi_cmnd *cmnd,
+		enum dma_data_direction dir)
 {
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
 	struct usb_device *udev = devinfo->udev;
 	struct urb *urb = usb_alloc_urb(0, gfp);
+	struct scsi_data_buffer *sdb;
+	usb_complete_t complete_fn;
+	u16 stream_id = cmdinfo->stream;
 
 	if (!urb)
 		goto out;
-	usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, uas_data_cmplt,
-									sdb);
-	if (devinfo->use_streams)
-		urb->stream_id = stream_id;
+	if (dir == DMA_FROM_DEVICE) {
+		sdb = scsi_in(cmnd);
+		complete_fn = uas_data_in_cmplt;
+	} else {
+		sdb = scsi_out(cmnd);
+		complete_fn = uas_data_out_cmplt;
+	}
+	usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
+			complete_fn, cmnd);
+	urb->stream_id = stream_id;
 	urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
 	urb->sg = sdb->table.sgl;
  out:
@@ -289,7 +324,7 @@
 }
 
 static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
-					struct scsi_cmnd *cmnd, u16 stream_id)
+		struct Scsi_Host *shost, u16 stream_id)
 {
 	struct usb_device *udev = devinfo->udev;
 	struct urb *urb = usb_alloc_urb(0, gfp);
@@ -303,7 +338,7 @@
 		goto free;
 
 	usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
-						uas_stat_cmplt, cmnd->device);
+						uas_stat_cmplt, shost);
 	urb->stream_id = stream_id;
 	urb->transfer_flags |= URB_FREE_BUFFER;
  out:
@@ -334,7 +369,10 @@
 		goto free;
 
 	iu->iu_id = IU_ID_COMMAND;
-	iu->tag = cpu_to_be16(stream_id);
+	if (blk_rq_tagged(cmnd->request))
+		iu->tag = cpu_to_be16(cmnd->request->tag + 2);
+	else
+		iu->tag = cpu_to_be16(1);
 	iu->prio_attr = UAS_SIMPLE_TAG;
 	iu->len = len;
 	int_to_scsilun(sdev->lun, &iu->lun);
@@ -362,8 +400,8 @@
 	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
 
 	if (cmdinfo->state & ALLOC_STATUS_URB) {
-		cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd,
-							  cmdinfo->stream);
+		cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp,
+				cmnd->device->host, cmdinfo->stream);
 		if (!cmdinfo->status_urb)
 			return SCSI_MLQUEUE_DEVICE_BUSY;
 		cmdinfo->state &= ~ALLOC_STATUS_URB;
@@ -380,8 +418,8 @@
 
 	if (cmdinfo->state & ALLOC_DATA_IN_URB) {
 		cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp,
-					devinfo->data_in_pipe, cmdinfo->stream,
-					scsi_in(cmnd), DMA_FROM_DEVICE);
+					devinfo->data_in_pipe, cmnd,
+					DMA_FROM_DEVICE);
 		if (!cmdinfo->data_in_urb)
 			return SCSI_MLQUEUE_DEVICE_BUSY;
 		cmdinfo->state &= ~ALLOC_DATA_IN_URB;
@@ -398,8 +436,8 @@
 
 	if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
 		cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp,
-					devinfo->data_out_pipe, cmdinfo->stream,
-					scsi_out(cmnd), DMA_TO_DEVICE);
+					devinfo->data_out_pipe, cmnd,
+					DMA_TO_DEVICE);
 		if (!cmdinfo->data_out_urb)
 			return SCSI_MLQUEUE_DEVICE_BUSY;
 		cmdinfo->state &= ~ALLOC_DATA_OUT_URB;
@@ -444,13 +482,13 @@
 
 	BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
 
-	if (!cmdinfo->status_urb && sdev->current_cmnd)
+	if (devinfo->cmnd)
 		return SCSI_MLQUEUE_DEVICE_BUSY;
 
 	if (blk_rq_tagged(cmnd->request)) {
-		cmdinfo->stream = cmnd->request->tag + 1;
+		cmdinfo->stream = cmnd->request->tag + 2;
 	} else {
-		sdev->current_cmnd = cmnd;
+		devinfo->cmnd = cmnd;
 		cmdinfo->stream = 1;
 	}
 
@@ -472,7 +510,8 @@
 	}
 
 	if (!devinfo->use_streams) {
-		cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
+		cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB |
+				ALLOC_STATUS_URB | SUBMIT_STATUS_URB);
 		cmdinfo->stream = 0;
 	}
 
@@ -551,7 +590,7 @@
 {
 	struct uas_dev_info *devinfo = sdev->hostdata;
 	scsi_set_tag_type(sdev, MSG_ORDERED_TAG);
-	scsi_activate_tcq(sdev, devinfo->qdepth - 1);
+	scsi_activate_tcq(sdev, devinfo->qdepth - 2);
 	return 0;
 }
 
@@ -589,22 +628,34 @@
 		intf->desc.bInterfaceProtocol == USB_PR_UAS);
 }
 
+static int uas_isnt_supported(struct usb_device *udev)
+{
+	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+	dev_warn(&udev->dev, "The driver for the USB controller %s does not "
+			"support scatter-gather which is\n",
+			hcd->driver->description);
+	dev_warn(&udev->dev, "required by the UAS driver. Please try an"
+			"alternative USB controller if you wish to use UAS.\n");
+	return -ENODEV;
+}
+
 static int uas_switch_interface(struct usb_device *udev,
 						struct usb_interface *intf)
 {
 	int i;
-
-	if (uas_is_interface(intf->cur_altsetting))
-		return 0;
+	int sg_supported = udev->bus->sg_tablesize != 0;
 
 	for (i = 0; i < intf->num_altsetting; i++) {
 		struct usb_host_interface *alt = &intf->altsetting[i];
-		if (alt == intf->cur_altsetting)
-			continue;
-		if (uas_is_interface(alt))
+
+		if (uas_is_interface(alt)) {
+			if (!sg_supported)
+				return uas_isnt_supported(udev);
 			return usb_set_interface(udev,
 						alt->desc.bInterfaceNumber,
 						alt->desc.bAlternateSetting);
+		}
 	}
 
 	return -ENODEV;
@@ -619,6 +670,7 @@
 	unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints;
 
 	devinfo->uas_sense_old = 0;
+	devinfo->cmnd = NULL;
 
 	for (i = 0; i < n_endpoints; i++) {
 		unsigned char *extra = endpoint[i].extra;
@@ -670,6 +722,40 @@
 	}
 }
 
+static int uas_alloc_status_urb(struct uas_dev_info *devinfo,
+		struct Scsi_Host *shost)
+{
+	if (devinfo->use_streams) {
+		devinfo->status_urb = NULL;
+		return 0;
+	}
+
+	devinfo->status_urb = uas_alloc_sense_urb(devinfo, GFP_KERNEL,
+			shost, 0);
+	if (!devinfo->status_urb)
+		goto err_s_urb;
+
+	if (usb_submit_urb(devinfo->status_urb, GFP_KERNEL))
+		goto err_submit_urb;
+
+	return 0;
+err_submit_urb:
+	usb_free_urb(devinfo->status_urb);
+err_s_urb:
+	return -ENOMEM;
+}
+
+static void uas_free_streams(struct uas_dev_info *devinfo)
+{
+	struct usb_device *udev = devinfo->udev;
+	struct usb_host_endpoint *eps[3];
+
+	eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);
+	eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
+	eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
+	usb_free_streams(devinfo->intf, eps, 3, GFP_KERNEL);
+}
+
 /*
  * XXX: What I'd like to do here is register a SCSI host for each USB host in
  * the system.  Follow usb-storage's design of registering a SCSI host for
@@ -699,18 +785,33 @@
 	shost->max_id = 1;
 	shost->sg_tablesize = udev->bus->sg_tablesize;
 
-	result = scsi_add_host(shost, &intf->dev);
-	if (result)
-		goto free;
-	shost->hostdata[0] = (unsigned long)devinfo;
-
 	devinfo->intf = intf;
 	devinfo->udev = udev;
 	uas_configure_endpoints(devinfo);
 
+	result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2);
+	if (result)
+		goto free;
+
+	result = scsi_add_host(shost, &intf->dev);
+	if (result)
+		goto deconfig_eps;
+
+	shost->hostdata[0] = (unsigned long)devinfo;
+
+	result = uas_alloc_status_urb(devinfo, shost);
+	if (result)
+		goto err_alloc_status;
+
 	scsi_scan_host(shost);
 	usb_set_intfdata(intf, shost);
 	return result;
+
+err_alloc_status:
+	scsi_remove_host(shost);
+	shost = NULL;
+deconfig_eps:
+	uas_free_streams(devinfo);
  free:
 	kfree(devinfo);
 	if (shost)
@@ -732,18 +833,13 @@
 
 static void uas_disconnect(struct usb_interface *intf)
 {
-	struct usb_device *udev = interface_to_usbdev(intf);
-	struct usb_host_endpoint *eps[3];
 	struct Scsi_Host *shost = usb_get_intfdata(intf);
 	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
 
 	scsi_remove_host(shost);
-
-	eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);
-	eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
-	eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
-	usb_free_streams(intf, eps, 3, GFP_KERNEL);
-
+	usb_kill_urb(devinfo->status_urb);
+	usb_free_urb(devinfo->status_urb);
+	uas_free_streams(devinfo);
 	kfree(devinfo);
 }
 
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index db51ba1..c18538e 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -125,6 +125,9 @@
 	{ }		/* Terminating entry */
 };
 
+static struct us_unusual_dev for_dynamic_ids =
+		USUAL_DEV(USB_SC_SCSI, USB_PR_BULK, 0);
+
 #undef UNUSUAL_DEV
 #undef COMPLIANT_DEV
 #undef USUAL_DEV
@@ -999,8 +1002,10 @@
 static int storage_probe(struct usb_interface *intf,
 			 const struct usb_device_id *id)
 {
+	struct us_unusual_dev *unusual_dev;
 	struct us_data *us;
 	int result;
+	int size;
 
 	/*
 	 * If libusual is configured, let it decide whether a standard
@@ -1019,8 +1024,19 @@
 	 * table, so we use the index of the id entry to find the
 	 * corresponding unusual_devs entry.
 	 */
-	result = usb_stor_probe1(&us, intf, id,
-			(id - usb_storage_usb_ids) + us_unusual_dev_list);
+
+	size = ARRAY_SIZE(us_unusual_dev_list);
+	if (id >= usb_storage_usb_ids && id < usb_storage_usb_ids + size) {
+		unusual_dev = (id - usb_storage_usb_ids) + us_unusual_dev_list;
+	} else {
+		unusual_dev = &for_dynamic_ids;
+
+		US_DEBUGP("%s %s 0x%04x 0x%04x\n", "Use Bulk-Only transport",
+			"with the Transparent SCSI protocol for dynamic id:",
+			id->idVendor, id->idProduct);
+	}
+
+	result = usb_stor_probe1(&us, intf, id, unusual_dev);
 	if (result)
 		return result;
 
@@ -1046,7 +1062,6 @@
 	.id_table =	usb_storage_usb_ids,
 	.supports_autosuspend = 1,
 	.soft_unbind =	1,
-	.no_dynamic_id = 1,
 };
 
 static int __init usb_stor_init(void)
diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c
index e132157..516db70 100644
--- a/drivers/video/backlight/s6e63m0.c
+++ b/drivers/video/backlight/s6e63m0.c
@@ -690,7 +690,7 @@
 	struct backlight_device *bd = NULL;
 	int brightness, rc;
 
-	rc = strict_strtoul(buf, 0, (unsigned long *)&lcd->gamma_mode);
+	rc = kstrtouint(buf, 0, &lcd->gamma_mode);
 	if (rc < 0)
 		return rc;
 
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
index fcbe742..df600d1 100644
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -13,12 +13,11 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/w1-gpio.h>
+#include <linux/gpio.h>
 
 #include "../w1.h"
 #include "../w1_int.h"
 
-#include <asm/gpio.h>
-
 static void w1_gpio_write_bit_dir(void *data, u8 bit)
 {
 	struct w1_gpio_platform_data *pdata = data;
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index d0cb01b..eb9e376 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -81,6 +81,19 @@
 
 	  If you are unsure, say N.
 
+config W1_SLAVE_DS2781
+	tristate "Dallas 2781 battery monitor chip"
+	depends on W1
+	help
+	  If you enable this you will have the DS2781 battery monitor
+	  chip support.
+
+	  The battery monitor chip is used in many batteries/devices
+	  as the one who is responsible for charging/discharging/monitoring
+	  Li+ batteries.
+
+	  If you are unsure, say N.
+
 config W1_SLAVE_BQ27000
 	tristate "BQ27000 slave support"
 	depends on W1
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile
index 1f31e9f..c4f1859 100644
--- a/drivers/w1/slaves/Makefile
+++ b/drivers/w1/slaves/Makefile
@@ -10,4 +10,5 @@
 obj-$(CONFIG_W1_SLAVE_DS2433)	+= w1_ds2433.o
 obj-$(CONFIG_W1_SLAVE_DS2760)	+= w1_ds2760.o
 obj-$(CONFIG_W1_SLAVE_DS2780)	+= w1_ds2780.o
+obj-$(CONFIG_W1_SLAVE_DS2781)	+= w1_ds2781.o
 obj-$(CONFIG_W1_SLAVE_BQ27000)	+= w1_bq27000.o
diff --git a/drivers/w1/slaves/w1_bq27000.c b/drivers/w1/slaves/w1_bq27000.c
index 8f4c91f..52ad812 100644
--- a/drivers/w1/slaves/w1_bq27000.c
+++ b/drivers/w1/slaves/w1_bq27000.c
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
+#include <linux/power/bq27x00_battery.h>
 
 #include "../w1.h"
 #include "../w1_int.h"
@@ -25,46 +26,37 @@
 
 static int F_ID;
 
-void w1_bq27000_write(struct device *dev, u8 buf, u8 reg)
-{
-	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
-
-	if (!dev) {
-		pr_info("Could not obtain slave dev ptr\n");
-		return;
-	}
-
-	w1_write_8(sl->master, HDQ_CMD_WRITE | reg);
-	w1_write_8(sl->master, buf);
-}
-EXPORT_SYMBOL(w1_bq27000_write);
-
-int w1_bq27000_read(struct device *dev, u8 reg)
+static int w1_bq27000_read(struct device *dev, unsigned int reg)
 {
 	u8 val;
-	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+	struct w1_slave *sl = container_of(dev->parent, struct w1_slave, dev);
 
-	if (!dev)
-		return 0;
-
+	mutex_lock(&sl->master->mutex);
 	w1_write_8(sl->master, HDQ_CMD_READ | reg);
 	val = w1_read_8(sl->master);
+	mutex_unlock(&sl->master->mutex);
 
 	return val;
 }
-EXPORT_SYMBOL(w1_bq27000_read);
+
+static struct bq27000_platform_data bq27000_battery_info = {
+	.read   = w1_bq27000_read,
+	.name   = "bq27000-battery",
+};
 
 static int w1_bq27000_add_slave(struct w1_slave *sl)
 {
 	int ret;
-	int id = 1;
 	struct platform_device *pdev;
 
-	pdev = platform_device_alloc("bq27000-battery", id);
+	pdev = platform_device_alloc("bq27000-battery", -1);
 	if (!pdev) {
 		ret = -ENOMEM;
 		return ret;
 	}
+	ret = platform_device_add_data(pdev,
+				       &bq27000_battery_info,
+				       sizeof(bq27000_battery_info));
 	pdev->dev.parent = &sl->dev;
 
 	ret = platform_device_add(pdev);
diff --git a/drivers/w1/slaves/w1_ds2781.c b/drivers/w1/slaves/w1_ds2781.c
new file mode 100644
index 0000000..0d0c798
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2781.c
@@ -0,0 +1,201 @@
+/*
+ * 1-Wire implementation for the ds2781 chip
+ *
+ * Author: Renata Sayakhova <renata@oktetlabs.ru>
+ *
+ * Based on w1-ds2780 driver
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/idr.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+#include "w1_ds2781.h"
+
+static int w1_ds2781_do_io(struct device *dev, char *buf, int addr,
+			size_t count, int io)
+{
+	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+
+	if (addr > DS2781_DATA_SIZE || addr < 0)
+		return 0;
+
+	count = min_t(int, count, DS2781_DATA_SIZE - addr);
+
+	if (w1_reset_select_slave(sl) == 0) {
+		if (io) {
+			w1_write_8(sl->master, W1_DS2781_WRITE_DATA);
+			w1_write_8(sl->master, addr);
+			w1_write_block(sl->master, buf, count);
+		} else {
+			w1_write_8(sl->master, W1_DS2781_READ_DATA);
+			w1_write_8(sl->master, addr);
+			count = w1_read_block(sl->master, buf, count);
+		}
+	}
+
+	return count;
+}
+
+int w1_ds2781_io(struct device *dev, char *buf, int addr, size_t count,
+			int io)
+{
+	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+	int ret;
+
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&sl->master->mutex);
+
+	ret = w1_ds2781_do_io(dev, buf, addr, count, io);
+
+	mutex_unlock(&sl->master->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(w1_ds2781_io);
+
+int w1_ds2781_io_nolock(struct device *dev, char *buf, int addr, size_t count,
+			int io)
+{
+	int ret;
+
+	if (!dev)
+		return -ENODEV;
+
+	ret = w1_ds2781_do_io(dev, buf, addr, count, io);
+
+	return ret;
+}
+EXPORT_SYMBOL(w1_ds2781_io_nolock);
+
+int w1_ds2781_eeprom_cmd(struct device *dev, int addr, int cmd)
+{
+	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+
+	if (!dev)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->mutex);
+
+	if (w1_reset_select_slave(sl) == 0) {
+		w1_write_8(sl->master, cmd);
+		w1_write_8(sl->master, addr);
+	}
+
+	mutex_unlock(&sl->master->mutex);
+	return 0;
+}
+EXPORT_SYMBOL(w1_ds2781_eeprom_cmd);
+
+static ssize_t w1_ds2781_read_bin(struct file *filp,
+				  struct kobject *kobj,
+				  struct bin_attribute *bin_attr,
+				  char *buf, loff_t off, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	return w1_ds2781_io(dev, buf, off, count, 0);
+}
+
+static struct bin_attribute w1_ds2781_bin_attr = {
+	.attr = {
+		.name = "w1_slave",
+		.mode = S_IRUGO,
+	},
+	.size = DS2781_DATA_SIZE,
+	.read = w1_ds2781_read_bin,
+};
+
+static DEFINE_IDA(bat_ida);
+
+static int w1_ds2781_add_slave(struct w1_slave *sl)
+{
+	int ret;
+	int id;
+	struct platform_device *pdev;
+
+	id = ida_simple_get(&bat_ida, 0, 0, GFP_KERNEL);
+	if (id < 0) {
+		ret = id;
+		goto noid;
+	}
+
+	pdev = platform_device_alloc("ds2781-battery", id);
+	if (!pdev) {
+		ret = -ENOMEM;
+		goto pdev_alloc_failed;
+	}
+	pdev->dev.parent = &sl->dev;
+
+	ret = platform_device_add(pdev);
+	if (ret)
+		goto pdev_add_failed;
+
+	ret = sysfs_create_bin_file(&sl->dev.kobj, &w1_ds2781_bin_attr);
+	if (ret)
+		goto bin_attr_failed;
+
+	dev_set_drvdata(&sl->dev, pdev);
+
+	return 0;
+
+bin_attr_failed:
+pdev_add_failed:
+	platform_device_unregister(pdev);
+pdev_alloc_failed:
+	ida_simple_remove(&bat_ida, id);
+noid:
+	return ret;
+}
+
+static void w1_ds2781_remove_slave(struct w1_slave *sl)
+{
+	struct platform_device *pdev = dev_get_drvdata(&sl->dev);
+	int id = pdev->id;
+
+	platform_device_unregister(pdev);
+	ida_simple_remove(&bat_ida, id);
+	sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2781_bin_attr);
+}
+
+static struct w1_family_ops w1_ds2781_fops = {
+	.add_slave    = w1_ds2781_add_slave,
+	.remove_slave = w1_ds2781_remove_slave,
+};
+
+static struct w1_family w1_ds2781_family = {
+	.fid = W1_FAMILY_DS2781,
+	.fops = &w1_ds2781_fops,
+};
+
+static int __init w1_ds2781_init(void)
+{
+	ida_init(&bat_ida);
+	return w1_register_family(&w1_ds2781_family);
+}
+
+static void __exit w1_ds2781_exit(void)
+{
+	w1_unregister_family(&w1_ds2781_family);
+	ida_destroy(&bat_ida);
+}
+
+module_init(w1_ds2781_init);
+module_exit(w1_ds2781_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Renata Sayakhova <renata@oktetlabs.ru>");
+MODULE_DESCRIPTION("1-wire Driver for Maxim/Dallas DS2781 Stand-Alone Fuel Gauge IC");
diff --git a/drivers/w1/slaves/w1_ds2781.h b/drivers/w1/slaves/w1_ds2781.h
new file mode 100644
index 0000000..82bc664
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2781.h
@@ -0,0 +1,136 @@
+/*
+ * 1-Wire implementation for the ds2780 chip
+ *
+ * Author: Renata Sayakhova <renata@oktetlabs.ru>
+ *
+ * Based on w1-ds2760 driver
+ *
+ * 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 _W1_DS2781_H
+#define _W1_DS2781_H
+
+/* Function commands */
+#define W1_DS2781_READ_DATA		0x69
+#define W1_DS2781_WRITE_DATA		0x6C
+#define W1_DS2781_COPY_DATA		0x48
+#define W1_DS2781_RECALL_DATA		0xB8
+#define W1_DS2781_LOCK			0x6A
+
+/* Register map */
+/* Register 0x00 Reserved */
+#define DS2781_STATUS			0x01
+#define DS2781_RAAC_MSB			0x02
+#define DS2781_RAAC_LSB			0x03
+#define DS2781_RSAC_MSB			0x04
+#define DS2781_RSAC_LSB			0x05
+#define DS2781_RARC			0x06
+#define DS2781_RSRC			0x07
+#define DS2781_IAVG_MSB			0x08
+#define DS2781_IAVG_LSB			0x09
+#define DS2781_TEMP_MSB			0x0A
+#define DS2781_TEMP_LSB			0x0B
+#define DS2781_VOLT_MSB			0x0C
+#define DS2781_VOLT_LSB			0x0D
+#define DS2781_CURRENT_MSB		0x0E
+#define DS2781_CURRENT_LSB		0x0F
+#define DS2781_ACR_MSB			0x10
+#define DS2781_ACR_LSB			0x11
+#define DS2781_ACRL_MSB			0x12
+#define DS2781_ACRL_LSB			0x13
+#define DS2781_AS			0x14
+#define DS2781_SFR			0x15
+#define DS2781_FULL_MSB			0x16
+#define DS2781_FULL_LSB			0x17
+#define DS2781_AE_MSB			0x18
+#define DS2781_AE_LSB			0x19
+#define DS2781_SE_MSB			0x1A
+#define DS2781_SE_LSB			0x1B
+/* Register 0x1C - 0x1E Reserved */
+#define DS2781_EEPROM		0x1F
+#define DS2781_EEPROM_BLOCK0_START	0x20
+/* Register 0x20 - 0x2F User EEPROM */
+#define DS2781_EEPROM_BLOCK0_END	0x2F
+/* Register 0x30 - 0x5F Reserved */
+#define DS2781_EEPROM_BLOCK1_START	0x60
+#define DS2781_CONTROL			0x60
+#define DS2781_AB			0x61
+#define DS2781_AC_MSB			0x62
+#define DS2781_AC_LSB			0x63
+#define DS2781_VCHG			0x64
+#define DS2781_IMIN			0x65
+#define DS2781_VAE			0x66
+#define DS2781_IAE			0x67
+#define DS2781_AE_40			0x68
+#define DS2781_RSNSP			0x69
+#define DS2781_FULL_40_MSB		0x6A
+#define DS2781_FULL_40_LSB		0x6B
+#define DS2781_FULL_4_SLOPE		0x6C
+#define DS2781_FULL_3_SLOPE		0x6D
+#define DS2781_FULL_2_SLOPE		0x6E
+#define DS2781_FULL_1_SLOPE		0x6F
+#define DS2781_AE_4_SLOPE		0x70
+#define DS2781_AE_3_SLOPE		0x71
+#define DS2781_AE_2_SLOPE		0x72
+#define DS2781_AE_1_SLOPE		0x73
+#define DS2781_SE_4_SLOPE		0x74
+#define DS2781_SE_3_SLOPE		0x75
+#define DS2781_SE_2_SLOPE		0x76
+#define DS2781_SE_1_SLOPE		0x77
+#define DS2781_RSGAIN_MSB		0x78
+#define DS2781_RSGAIN_LSB		0x79
+#define DS2781_RSTC			0x7A
+#define DS2781_COB			0x7B
+#define DS2781_TBP34			0x7C
+#define DS2781_TBP23			0x7D
+#define DS2781_TBP12			0x7E
+#define DS2781_EEPROM_BLOCK1_END	0x7F
+/* Register 0x7D - 0xFF Reserved */
+
+#define DS2781_FSGAIN_MSB		0xB0
+#define DS2781_FSGAIN_LSB		0xB1
+
+/* Number of valid register addresses */
+#define DS2781_DATA_SIZE		0xB2
+
+/* Status register bits */
+#define DS2781_STATUS_CHGTF		(1 << 7)
+#define DS2781_STATUS_AEF		(1 << 6)
+#define DS2781_STATUS_SEF		(1 << 5)
+#define DS2781_STATUS_LEARNF		(1 << 4)
+/* Bit 3 Reserved */
+#define DS2781_STATUS_UVF		(1 << 2)
+#define DS2781_STATUS_PORF		(1 << 1)
+/* Bit 0 Reserved */
+
+/* Control register bits */
+/* Bit 7 Reserved */
+#define DS2781_CONTROL_NBEN		(1 << 7)
+#define DS2781_CONTROL_UVEN		(1 << 6)
+#define DS2781_CONTROL_PMOD		(1 << 5)
+#define DS2781_CONTROL_RNAOP		(1 << 4)
+#define DS1781_CONTROL_UVTH		(1 << 3)
+/* Bit 0 - 2 Reserved */
+
+/* Special feature register bits */
+/* Bit 1 - 7 Reserved */
+#define DS2781_SFR_PIOSC		(1 << 0)
+
+/* EEPROM register bits */
+#define DS2781_EEPROM_EEC		(1 << 7)
+#define DS2781_EEPROM_LOCK		(1 << 6)
+/* Bit 2 - 6 Reserved */
+#define DS2781_EEPROM_BL1		(1 << 1)
+#define DS2781_EEPROM_BL0		(1 << 0)
+
+extern int w1_ds2781_io(struct device *dev, char *buf, int addr, size_t count,
+			int io);
+extern int w1_ds2781_io_nolock(struct device *dev, char *buf, int addr,
+			size_t count, int io);
+extern int w1_ds2781_eeprom_cmd(struct device *dev, int addr, int cmd);
+
+#endif /* !_W1_DS2781_H */
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index 490cda2..874aeb0 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -38,6 +38,7 @@
 #define W1_EEPROM_DS2431	0x2D
 #define W1_FAMILY_DS2760	0x30
 #define W1_FAMILY_DS2780	0x32
+#define W1_FAMILY_DS2781	0x3D
 #define W1_THERM_DS28EA00	0x42
 
 #define MAXNAMELEN		32
diff --git a/fs/Kconfig b/fs/Kconfig
index d621f02..aa19526 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -4,6 +4,10 @@
 
 menu "File systems"
 
+# Use unaligned word dcache accesses
+config DCACHE_WORD_ACCESS
+       bool
+
 if BLOCK
 
 source "fs/ext2/Kconfig"
diff --git a/fs/afs/file.c b/fs/afs/file.c
index 14d89fa..8f6e923 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -251,7 +251,7 @@
 	ASSERT(key != NULL);
 
 	vnode = AFS_FS_I(mapping->host);
-	if (vnode->flags & AFS_VNODE_DELETED) {
+	if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
 		_leave(" = -ESTALE");
 		return -ESTALE;
 	}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index d2b0888..a306bb6 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -109,7 +109,7 @@
 	unsigned		reply_size;	/* current size of reply */
 	unsigned		first_offset;	/* offset into mapping[first] */
 	unsigned		last_to;	/* amount of mapping[last] */
-	unsigned short		offset;		/* offset into received data store */
+	unsigned		offset;		/* offset into received data store */
 	unsigned char		unmarshall;	/* unmarshalling phase */
 	bool			incoming;	/* T if incoming call */
 	bool			send_pages;	/* T if data from mapping should be sent */
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index e45a323..8ad8c2a 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -314,6 +314,7 @@
 	struct msghdr msg;
 	struct kvec iov[1];
 	int ret;
+	struct sk_buff *skb;
 
 	_enter("%x,{%d},", addr->s_addr, ntohs(call->port));
 
@@ -380,6 +381,8 @@
 
 error_do_abort:
 	rxrpc_kernel_abort_call(rxcall, RX_USER_ABORT);
+	while ((skb = skb_dequeue(&call->rx_queue)))
+		afs_free_skb(skb);
 	rxrpc_kernel_end_call(rxcall);
 	call->rxcall = NULL;
 error_kill_call:
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 0e575d1..5e9f198 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1183,8 +1183,12 @@
 			 * The latter is necessary to prevent ghost
 			 * partitions on a removed medium.
 			 */
-			if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM))
-				rescan_partitions(disk, bdev);
+			if (bdev->bd_invalidated) {
+				if (!ret)
+					rescan_partitions(disk, bdev);
+				else if (ret == -ENOMEDIUM)
+					invalidate_partitions(disk, bdev);
+			}
 			if (ret)
 				goto out_clear;
 		} else {
@@ -1214,8 +1218,12 @@
 			if (bdev->bd_disk->fops->open)
 				ret = bdev->bd_disk->fops->open(bdev, mode);
 			/* the same as first opener case, read comment there */
-			if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM))
-				rescan_partitions(bdev->bd_disk, bdev);
+			if (bdev->bd_invalidated) {
+				if (!ret)
+					rescan_partitions(bdev->bd_disk, bdev);
+				else if (ret == -ENOMEDIUM)
+					invalidate_partitions(bdev->bd_disk, bdev);
+			}
 			if (ret)
 				goto out_unlock_bdev;
 		}
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 4dd9283..5e64748 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -920,16 +920,26 @@
 	for (lockp = &inode->i_flock; *lockp != NULL; \
 	     lockp = &(*lockp)->fl_next)
 
+struct lock_to_push {
+	struct list_head llist;
+	__u64 offset;
+	__u64 length;
+	__u32 pid;
+	__u16 netfid;
+	__u8 type;
+};
+
 static int
 cifs_push_posix_locks(struct cifsFileInfo *cfile)
 {
 	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 	struct file_lock *flock, **before;
-	struct cifsLockInfo *lck, *tmp;
+	unsigned int count = 0, i = 0;
 	int rc = 0, xid, type;
+	struct list_head locks_to_send, *el;
+	struct lock_to_push *lck, *tmp;
 	__u64 length;
-	struct list_head locks_to_send;
 
 	xid = GetXid();
 
@@ -940,29 +950,55 @@
 		return rc;
 	}
 
-	INIT_LIST_HEAD(&locks_to_send);
-
 	lock_flocks();
 	cifs_for_each_lock(cfile->dentry->d_inode, before) {
+		if ((*before)->fl_flags & FL_POSIX)
+			count++;
+	}
+	unlock_flocks();
+
+	INIT_LIST_HEAD(&locks_to_send);
+
+	/*
+	 * Allocating count locks is enough because no locks can be added to
+	 * the list while we are holding cinode->lock_mutex that protects
+	 * locking operations of this inode.
+	 */
+	for (; i < count; i++) {
+		lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL);
+		if (!lck) {
+			rc = -ENOMEM;
+			goto err_out;
+		}
+		list_add_tail(&lck->llist, &locks_to_send);
+	}
+
+	i = 0;
+	el = locks_to_send.next;
+	lock_flocks();
+	cifs_for_each_lock(cfile->dentry->d_inode, before) {
+		if (el == &locks_to_send) {
+			/* something is really wrong */
+			cERROR(1, "Can't push all brlocks!");
+			break;
+		}
 		flock = *before;
+		if ((flock->fl_flags & FL_POSIX) == 0)
+			continue;
 		length = 1 + flock->fl_end - flock->fl_start;
 		if (flock->fl_type == F_RDLCK || flock->fl_type == F_SHLCK)
 			type = CIFS_RDLCK;
 		else
 			type = CIFS_WRLCK;
-
-		lck = cifs_lock_init(flock->fl_start, length, type,
-				     cfile->netfid);
-		if (!lck) {
-			rc = -ENOMEM;
-			goto send_locks;
-		}
+		lck = list_entry(el, struct lock_to_push, llist);
 		lck->pid = flock->fl_pid;
-
-		list_add_tail(&lck->llist, &locks_to_send);
+		lck->netfid = cfile->netfid;
+		lck->length = length;
+		lck->type = type;
+		lck->offset = flock->fl_start;
+		i++;
+		el = el->next;
 	}
-
-send_locks:
 	unlock_flocks();
 
 	list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) {
@@ -979,11 +1015,18 @@
 		kfree(lck);
 	}
 
+out:
 	cinode->can_cache_brlcks = false;
 	mutex_unlock(&cinode->lock_mutex);
 
 	FreeXid(xid);
 	return rc;
+err_out:
+	list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) {
+		list_del(&lck->llist);
+		kfree(lck);
+	}
+	goto out;
 }
 
 static int
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 45f07c4..10d92cf 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -105,7 +105,6 @@
 	struct cifs_tcon *pTcon;
 	struct super_block *sb;
 	char *full_path;
-	struct cifs_ntsd *pacl;
 
 	if (direntry == NULL)
 		return -EIO;
@@ -164,23 +163,24 @@
 			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	} else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
 			strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
+#ifdef CONFIG_CIFS_ACL
+		struct cifs_ntsd *pacl;
 		pacl = kmalloc(value_size, GFP_KERNEL);
 		if (!pacl) {
 			cFYI(1, "%s: Can't allocate memory for ACL",
 					__func__);
 			rc = -ENOMEM;
 		} else {
-#ifdef CONFIG_CIFS_ACL
 			memcpy(pacl, ea_value, value_size);
 			rc = set_cifs_acl(pacl, value_size,
 				direntry->d_inode, full_path, CIFS_ACL_DACL);
 			if (rc == 0) /* force revalidate of the inode */
 				CIFS_I(direntry->d_inode)->time = 0;
 			kfree(pacl);
+		}
 #else
 			cFYI(1, "Set CIFS ACL not supported yet");
 #endif /* CONFIG_CIFS_ACL */
-		}
 	} else {
 		int temp;
 		temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
diff --git a/fs/dcache.c b/fs/dcache.c
index bcbdb33..11828de 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -105,10 +105,10 @@
 static struct hlist_bl_head *dentry_hashtable __read_mostly;
 
 static inline struct hlist_bl_head *d_hash(const struct dentry *parent,
-					unsigned long hash)
+					unsigned int hash)
 {
-	hash += ((unsigned long) parent ^ GOLDEN_RATIO_PRIME) / L1_CACHE_BYTES;
-	hash = hash ^ ((hash ^ GOLDEN_RATIO_PRIME) >> D_HASHBITS);
+	hash += (unsigned long) parent / L1_CACHE_BYTES;
+	hash = hash + (hash >> D_HASHBITS);
 	return dentry_hashtable + (hash & D_HASHMASK);
 }
 
@@ -144,6 +144,28 @@
 static inline int dentry_cmp(const unsigned char *cs, size_t scount,
 				const unsigned char *ct, size_t tcount)
 {
+#ifdef CONFIG_DCACHE_WORD_ACCESS
+	unsigned long a,b,mask;
+
+	if (unlikely(scount != tcount))
+		return 1;
+
+	for (;;) {
+		a = *(unsigned long *)cs;
+		b = *(unsigned long *)ct;
+		if (tcount < sizeof(unsigned long))
+			break;
+		if (unlikely(a != b))
+			return 1;
+		cs += sizeof(unsigned long);
+		ct += sizeof(unsigned long);
+		tcount -= sizeof(unsigned long);
+		if (!tcount)
+			return 0;
+	}
+	mask = ~(~0ul << tcount*8);
+	return unlikely(!!((a ^ b) & mask));
+#else
 	if (scount != tcount)
 		return 1;
 
@@ -155,6 +177,7 @@
 		tcount--;
 	} while (tcount);
 	return 0;
+#endif
 }
 
 static void __d_free(struct rcu_head *head)
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 956d5dd..b80bc84 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -23,9 +23,13 @@
 #include <linux/debugfs.h>
 #include <linux/fsnotify.h>
 #include <linux/string.h>
+#include <linux/seq_file.h>
+#include <linux/parser.h>
 #include <linux/magic.h>
 #include <linux/slab.h>
 
+#define DEBUGFS_DEFAULT_MODE	0755
+
 static struct vfsmount *debugfs_mount;
 static int debugfs_mount_count;
 static bool debugfs_registered;
@@ -125,11 +129,154 @@
 	return dentry->d_inode && !d_unhashed(dentry);
 }
 
+struct debugfs_mount_opts {
+	uid_t uid;
+	gid_t gid;
+	umode_t mode;
+};
+
+enum {
+	Opt_uid,
+	Opt_gid,
+	Opt_mode,
+	Opt_err
+};
+
+static const match_table_t tokens = {
+	{Opt_uid, "uid=%u"},
+	{Opt_gid, "gid=%u"},
+	{Opt_mode, "mode=%o"},
+	{Opt_err, NULL}
+};
+
+struct debugfs_fs_info {
+	struct debugfs_mount_opts mount_opts;
+};
+
+static int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts)
+{
+	substring_t args[MAX_OPT_ARGS];
+	int option;
+	int token;
+	char *p;
+
+	opts->mode = DEBUGFS_DEFAULT_MODE;
+
+	while ((p = strsep(&data, ",")) != NULL) {
+		if (!*p)
+			continue;
+
+		token = match_token(p, tokens, args);
+		switch (token) {
+		case Opt_uid:
+			if (match_int(&args[0], &option))
+				return -EINVAL;
+			opts->uid = option;
+			break;
+		case Opt_gid:
+			if (match_octal(&args[0], &option))
+				return -EINVAL;
+			opts->gid = option;
+			break;
+		case Opt_mode:
+			if (match_octal(&args[0], &option))
+				return -EINVAL;
+			opts->mode = option & S_IALLUGO;
+			break;
+		/*
+		 * We might like to report bad mount options here;
+		 * but traditionally debugfs has ignored all mount options
+		 */
+		}
+	}
+
+	return 0;
+}
+
+static int debugfs_apply_options(struct super_block *sb)
+{
+	struct debugfs_fs_info *fsi = sb->s_fs_info;
+	struct inode *inode = sb->s_root->d_inode;
+	struct debugfs_mount_opts *opts = &fsi->mount_opts;
+
+	inode->i_mode &= ~S_IALLUGO;
+	inode->i_mode |= opts->mode;
+
+	inode->i_uid = opts->uid;
+	inode->i_gid = opts->gid;
+
+	return 0;
+}
+
+static int debugfs_remount(struct super_block *sb, int *flags, char *data)
+{
+	int err;
+	struct debugfs_fs_info *fsi = sb->s_fs_info;
+
+	err = debugfs_parse_options(data, &fsi->mount_opts);
+	if (err)
+		goto fail;
+
+	debugfs_apply_options(sb);
+
+fail:
+	return err;
+}
+
+static int debugfs_show_options(struct seq_file *m, struct dentry *root)
+{
+	struct debugfs_fs_info *fsi = root->d_sb->s_fs_info;
+	struct debugfs_mount_opts *opts = &fsi->mount_opts;
+
+	if (opts->uid != 0)
+		seq_printf(m, ",uid=%u", opts->uid);
+	if (opts->gid != 0)
+		seq_printf(m, ",gid=%u", opts->gid);
+	if (opts->mode != DEBUGFS_DEFAULT_MODE)
+		seq_printf(m, ",mode=%o", opts->mode);
+
+	return 0;
+}
+
+static const struct super_operations debugfs_super_operations = {
+	.statfs		= simple_statfs,
+	.remount_fs	= debugfs_remount,
+	.show_options	= debugfs_show_options,
+};
+
 static int debug_fill_super(struct super_block *sb, void *data, int silent)
 {
 	static struct tree_descr debug_files[] = {{""}};
+	struct debugfs_fs_info *fsi;
+	int err;
 
-	return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files);
+	save_mount_options(sb, data);
+
+	fsi = kzalloc(sizeof(struct debugfs_fs_info), GFP_KERNEL);
+	sb->s_fs_info = fsi;
+	if (!fsi) {
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	err = debugfs_parse_options(data, &fsi->mount_opts);
+	if (err)
+		goto fail;
+
+	err  =  simple_fill_super(sb, DEBUGFS_MAGIC, debug_files);
+	if (err)
+		goto fail;
+
+	sb->s_op = &debugfs_super_operations;
+
+	debugfs_apply_options(sb);
+
+	return 0;
+
+fail:
+	kfree(fsi);
+	sb->s_fs_info = NULL;
+	return err;
 }
 
 static struct dentry *debug_mount(struct file_system_type *fs_type,
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index c4e2a58..1c6f908 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -36,7 +36,61 @@
 #define DEVPTS_DEFAULT_PTMX_MODE 0000
 #define PTMX_MINOR	2
 
-extern int pty_limit;			/* Config limit on Unix98 ptys */
+/*
+ * sysctl support for setting limits on the number of Unix98 ptys allocated.
+ * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
+ */
+static int pty_limit = NR_UNIX98_PTY_DEFAULT;
+static int pty_reserve = NR_UNIX98_PTY_RESERVE;
+static int pty_limit_min;
+static int pty_limit_max = INT_MAX;
+static int pty_count;
+
+static struct ctl_table pty_table[] = {
+	{
+		.procname	= "max",
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.data		= &pty_limit,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &pty_limit_min,
+		.extra2		= &pty_limit_max,
+	}, {
+		.procname	= "reserve",
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.data		= &pty_reserve,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &pty_limit_min,
+		.extra2		= &pty_limit_max,
+	}, {
+		.procname	= "nr",
+		.maxlen		= sizeof(int),
+		.mode		= 0444,
+		.data		= &pty_count,
+		.proc_handler	= proc_dointvec,
+	},
+	{}
+};
+
+static struct ctl_table pty_kern_table[] = {
+	{
+		.procname	= "pty",
+		.mode		= 0555,
+		.child		= pty_table,
+	},
+	{}
+};
+
+static struct ctl_table pty_root_table[] = {
+	{
+		.procname	= "kernel",
+		.mode		= 0555,
+		.child		= pty_kern_table,
+	},
+	{}
+};
+
 static DEFINE_MUTEX(allocated_ptys_lock);
 
 static struct vfsmount *devpts_mnt;
@@ -49,10 +103,11 @@
 	umode_t mode;
 	umode_t ptmxmode;
 	int newinstance;
+	int max;
 };
 
 enum {
-	Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance,
+	Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance,  Opt_max,
 	Opt_err
 };
 
@@ -63,6 +118,7 @@
 #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
 	{Opt_ptmxmode, "ptmxmode=%o"},
 	{Opt_newinstance, "newinstance"},
+	{Opt_max, "max=%d"},
 #endif
 	{Opt_err, NULL}
 };
@@ -109,6 +165,7 @@
 	opts->gid     = 0;
 	opts->mode    = DEVPTS_DEFAULT_MODE;
 	opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
+	opts->max     = NR_UNIX98_PTY_MAX;
 
 	/* newinstance makes sense only on initial mount */
 	if (op == PARSE_MOUNT)
@@ -152,6 +209,12 @@
 			if (op == PARSE_MOUNT)
 				opts->newinstance = 1;
 			break;
+		case Opt_max:
+			if (match_int(&args[0], &option) ||
+			    option < 0 || option > NR_UNIX98_PTY_MAX)
+				return -EINVAL;
+			opts->max = option;
+			break;
 #endif
 		default:
 			printk(KERN_ERR "devpts: called with bogus options\n");
@@ -258,6 +321,8 @@
 	seq_printf(seq, ",mode=%03o", opts->mode);
 #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
 	seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode);
+	if (opts->max < NR_UNIX98_PTY_MAX)
+		seq_printf(seq, ",max=%d", opts->max);
 #endif
 
 	return 0;
@@ -438,6 +503,12 @@
 		return -ENOMEM;
 
 	mutex_lock(&allocated_ptys_lock);
+	if (pty_count >= pty_limit -
+			(fsi->mount_opts.newinstance ? pty_reserve : 0)) {
+		mutex_unlock(&allocated_ptys_lock);
+		return -ENOSPC;
+	}
+
 	ida_ret = ida_get_new(&fsi->allocated_ptys, &index);
 	if (ida_ret < 0) {
 		mutex_unlock(&allocated_ptys_lock);
@@ -446,11 +517,12 @@
 		return -EIO;
 	}
 
-	if (index >= pty_limit) {
+	if (index >= fsi->mount_opts.max) {
 		ida_remove(&fsi->allocated_ptys, index);
 		mutex_unlock(&allocated_ptys_lock);
-		return -EIO;
+		return -ENOSPC;
 	}
+	pty_count++;
 	mutex_unlock(&allocated_ptys_lock);
 	return index;
 }
@@ -462,6 +534,7 @@
 
 	mutex_lock(&allocated_ptys_lock);
 	ida_remove(&fsi->allocated_ptys, idx);
+	pty_count--;
 	mutex_unlock(&allocated_ptys_lock);
 }
 
@@ -558,11 +631,15 @@
 static int __init init_devpts_fs(void)
 {
 	int err = register_filesystem(&devpts_fs_type);
+	struct ctl_table_header *table;
+
 	if (!err) {
+		table = register_sysctl_table(pty_root_table);
 		devpts_mnt = kern_mount(&devpts_fs_type);
 		if (IS_ERR(devpts_mnt)) {
 			err = PTR_ERR(devpts_mnt);
 			unregister_filesystem(&devpts_fs_type);
+			unregister_sysctl_table(table);
 		}
 	}
 	return err;
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index ea54cde..4d9d3a4 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -988,6 +988,10 @@
 
 static int path_count_inc(int nests)
 {
+	/* Allow an arbitrary number of depth 1 paths */
+	if (nests == 0)
+		return 0;
+
 	if (++path_count[nests] > path_limits[nests])
 		return -1;
 	return 0;
diff --git a/fs/exec.c b/fs/exec.c
index 153dee1..95551c6 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -63,6 +63,8 @@
 #include <trace/events/task.h>
 #include "internal.h"
 
+#include <trace/events/sched.h>
+
 int core_uses_pid;
 char core_pattern[CORENAME_MAX_SIZE] = "core";
 unsigned int core_pipe_limit;
@@ -848,6 +850,7 @@
 	if (old_mm) {
 		up_read(&old_mm->mmap_sem);
 		BUG_ON(active_mm != old_mm);
+		setmax_mm_hiwater_rss(&tsk->signal->maxrss, old_mm);
 		mm_update_next_owner(old_mm);
 		mmput(old_mm);
 		return 0;
@@ -975,8 +978,8 @@
 	sig->notify_count = 0;
 
 no_thread_group:
-	if (current->mm)
-		setmax_mm_hiwater_rss(&sig->maxrss, current->mm);
+	/* we have changed execution domain */
+	tsk->exit_signal = SIGCHLD;
 
 	exit_itimers(sig);
 	flush_itimer_signals();
@@ -1402,9 +1405,10 @@
 			 */
 			bprm->recursion_depth = depth;
 			if (retval >= 0) {
-				if (depth == 0)
-					ptrace_event(PTRACE_EVENT_EXEC,
-							old_pid);
+				if (depth == 0) {
+					trace_sched_process_exec(current, old_pid, bprm);
+					ptrace_event(PTRACE_EVENT_EXEC, old_pid);
+				}
 				put_binfmt(fmt);
 				allow_write_access(bprm->file);
 				if (bprm->file)
diff --git a/fs/inode.c b/fs/inode.c
index d3ebdbe..83ab215 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -938,8 +938,7 @@
 		struct file_system_type *type = inode->i_sb->s_type;
 
 		/* Set new key only if filesystem hasn't already changed it */
-		if (!lockdep_match_class(&inode->i_mutex,
-		    &type->i_mutex_key)) {
+		if (lockdep_match_class(&inode->i_mutex, &type->i_mutex_key)) {
 			/*
 			 * ensure nobody is actually holding i_mutex
 			 */
@@ -966,6 +965,7 @@
 	spin_lock(&inode->i_lock);
 	WARN_ON(!(inode->i_state & I_NEW));
 	inode->i_state &= ~I_NEW;
+	smp_mb();
 	wake_up_bit(&inode->i_state, __I_NEW);
 	spin_unlock(&inode->i_lock);
 }
diff --git a/fs/namei.c b/fs/namei.c
index e2ba628..fa96a26 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1374,6 +1374,126 @@
 	return 1;
 }
 
+/*
+ * We can do the critical dentry name comparison and hashing
+ * operations one word at a time, but we are limited to:
+ *
+ * - Architectures with fast unaligned word accesses. We could
+ *   do a "get_unaligned()" if this helps and is sufficiently
+ *   fast.
+ *
+ * - Little-endian machines (so that we can generate the mask
+ *   of low bytes efficiently). Again, we *could* do a byte
+ *   swapping load on big-endian architectures if that is not
+ *   expensive enough to make the optimization worthless.
+ *
+ * - non-CONFIG_DEBUG_PAGEALLOC configurations (so that we
+ *   do not trap on the (extremely unlikely) case of a page
+ *   crossing operation.
+ *
+ * - Furthermore, we need an efficient 64-bit compile for the
+ *   64-bit case in order to generate the "number of bytes in
+ *   the final mask". Again, that could be replaced with a
+ *   efficient population count instruction or similar.
+ */
+#ifdef CONFIG_DCACHE_WORD_ACCESS
+
+#ifdef CONFIG_64BIT
+
+/*
+ * Jan Achrenius on G+: microoptimized version of
+ * the simpler "(mask & ONEBYTES) * ONEBYTES >> 56"
+ * that works for the bytemasks without having to
+ * mask them first.
+ */
+static inline long count_masked_bytes(unsigned long mask)
+{
+	return mask*0x0001020304050608 >> 56;
+}
+
+static inline unsigned int fold_hash(unsigned long hash)
+{
+	hash += hash >> (8*sizeof(int));
+	return hash;
+}
+
+#else	/* 32-bit case */
+
+/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */
+static inline long count_masked_bytes(long mask)
+{
+	/* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
+	long a = (0x0ff0001+mask) >> 23;
+	/* Fix the 1 for 00 case */
+	return a & mask;
+}
+
+#define fold_hash(x) (x)
+
+#endif
+
+unsigned int full_name_hash(const unsigned char *name, unsigned int len)
+{
+	unsigned long a, mask;
+	unsigned long hash = 0;
+
+	for (;;) {
+		a = *(unsigned long *)name;
+		hash *= 9;
+		if (len < sizeof(unsigned long))
+			break;
+		hash += a;
+		name += sizeof(unsigned long);
+		len -= sizeof(unsigned long);
+		if (!len)
+			goto done;
+	}
+	mask = ~(~0ul << len*8);
+	hash += mask & a;
+done:
+	return fold_hash(hash);
+}
+EXPORT_SYMBOL(full_name_hash);
+
+#define ONEBYTES	0x0101010101010101ul
+#define SLASHBYTES	0x2f2f2f2f2f2f2f2ful
+#define HIGHBITS	0x8080808080808080ul
+
+/* Return the high bit set in the first byte that is a zero */
+static inline unsigned long has_zero(unsigned long a)
+{
+	return ((a - ONEBYTES) & ~a) & HIGHBITS;
+}
+
+/*
+ * Calculate the length and hash of the path component, and
+ * return the length of the component;
+ */
+static inline unsigned long hash_name(const char *name, unsigned int *hashp)
+{
+	unsigned long a, mask, hash, len;
+
+	hash = a = 0;
+	len = -sizeof(unsigned long);
+	do {
+		hash = (hash + a) * 9;
+		len += sizeof(unsigned long);
+		a = *(unsigned long *)(name+len);
+		/* Do we have any NUL or '/' bytes in this word? */
+		mask = has_zero(a) | has_zero(a ^ SLASHBYTES);
+	} while (!mask);
+
+	/* The mask *below* the first high bit set */
+	mask = (mask - 1) & ~mask;
+	mask >>= 7;
+	hash += a & mask;
+	*hashp = fold_hash(hash);
+
+	return len + count_masked_bytes(mask);
+}
+
+#else
+
 unsigned int full_name_hash(const unsigned char *name, unsigned int len)
 {
 	unsigned long hash = init_name_hash();
@@ -1402,6 +1522,8 @@
 	return len;
 }
 
+#endif
+
 /*
  * Name resolution.
  * This is the basic name resolution function, turning a pathname into
@@ -2162,7 +2284,7 @@
 		/* sayonara */
 		error = complete_walk(nd);
 		if (error)
-			return ERR_PTR(-ECHILD);
+			return ERR_PTR(error);
 
 		error = -ENOTDIR;
 		if (nd->flags & LOOKUP_DIRECTORY) {
@@ -2261,7 +2383,7 @@
 	/* Why this, you ask?  _Now_ we might have grown LOOKUP_JUMPED... */
 	error = complete_walk(nd);
 	if (error)
-		goto exit;
+		return ERR_PTR(error);
 	error = -EISDIR;
 	if (S_ISDIR(nd->inode->i_mode))
 		goto exit;
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
index d327140..501b7f8 100644
--- a/fs/nilfs2/the_nilfs.c
+++ b/fs/nilfs2/the_nilfs.c
@@ -409,6 +409,12 @@
 	nilfs->ns_first_data_block = le64_to_cpu(sbp->s_first_data_block);
 	nilfs->ns_r_segments_percentage =
 		le32_to_cpu(sbp->s_r_segments_percentage);
+	if (nilfs->ns_r_segments_percentage < 1 ||
+	    nilfs->ns_r_segments_percentage > 99) {
+		printk(KERN_ERR "NILFS: invalid reserved segments percentage.\n");
+		return -EINVAL;
+	}
+
 	nilfs_set_nsegments(nilfs, le64_to_cpu(sbp->s_nsegments));
 	nilfs->ns_crc_seed = le32_to_cpu(sbp->s_crc_seed);
 	return 0;
@@ -515,6 +521,7 @@
 		brelse(sbh[1]);
 		sbh[1] = NULL;
 		sbp[1] = NULL;
+		valid[1] = 0;
 		swp = 0;
 	}
 	if (!valid[swp]) {
diff --git a/fs/proc/base.c b/fs/proc/base.c
index d4548dd..965d4bd 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1310,8 +1310,7 @@
 	if (!p)
 		return -ESRCH;
 
-	err = nice;
-	err = proc_sched_autogroup_set_nice(p, &err);
+	err = proc_sched_autogroup_set_nice(p, nice);
 	if (err)
 		count = err;
 
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 7fdf6a7..2a7a3f5 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -22,76 +22,103 @@
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/security.h>
+#include <linux/hash.h>
 #include "sysfs.h"
 
 DEFINE_MUTEX(sysfs_mutex);
 DEFINE_SPINLOCK(sysfs_assoc_lock);
 
+#define to_sysfs_dirent(X) rb_entry((X), struct sysfs_dirent, s_rb);
+
 static DEFINE_SPINLOCK(sysfs_ino_lock);
 static DEFINE_IDA(sysfs_ino_ida);
 
 /**
- *	sysfs_link_sibling - link sysfs_dirent into sibling list
+ *	sysfs_name_hash
+ *	@ns:   Namespace tag to hash
+ *	@name: Null terminated string to hash
+ *
+ *	Returns 31 bit hash of ns + name (so it fits in an off_t )
+ */
+static unsigned int sysfs_name_hash(const void *ns, const char *name)
+{
+	unsigned long hash = init_name_hash();
+	unsigned int len = strlen(name);
+	while (len--)
+		hash = partial_name_hash(*name++, hash);
+	hash = ( end_name_hash(hash) ^ hash_ptr( (void *)ns, 31 ) );
+	hash &= 0x7fffffffU;
+	/* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */
+	if (hash < 1)
+		hash += 2;
+	if (hash >= INT_MAX)
+		hash = INT_MAX - 1;
+	return hash;
+}
+
+static int sysfs_name_compare(unsigned int hash, const void *ns,
+	const char *name, const struct sysfs_dirent *sd)
+{
+	if (hash != sd->s_hash)
+		return hash - sd->s_hash;
+	if (ns != sd->s_ns)
+		return ns - sd->s_ns;
+	return strcmp(name, sd->s_name);
+}
+
+static int sysfs_sd_compare(const struct sysfs_dirent *left,
+			    const struct sysfs_dirent *right)
+{
+	return sysfs_name_compare(left->s_hash, left->s_ns, left->s_name,
+				  right);
+}
+
+/**
+ *	sysfs_link_subling - link sysfs_dirent into sibling rbtree
  *	@sd: sysfs_dirent of interest
  *
- *	Link @sd into its sibling list which starts from
+ *	Link @sd into its sibling rbtree which starts from
  *	sd->s_parent->s_dir.children.
  *
  *	Locking:
  *	mutex_lock(sysfs_mutex)
+ *
+ *	RETURNS:
+ *	0 on susccess -EEXIST on failure.
  */
-static void sysfs_link_sibling(struct sysfs_dirent *sd)
+static int sysfs_link_sibling(struct sysfs_dirent *sd)
 {
-	struct sysfs_dirent *parent_sd = sd->s_parent;
-
-	struct rb_node **p;
-	struct rb_node *parent;
+	struct rb_node **node = &sd->s_parent->s_dir.children.rb_node;
+	struct rb_node *parent = NULL;
 
 	if (sysfs_type(sd) == SYSFS_DIR)
-		parent_sd->s_dir.subdirs++;
+		sd->s_parent->s_dir.subdirs++;
 
-	p = &parent_sd->s_dir.inode_tree.rb_node;
-	parent = NULL;
-	while (*p) {
-		parent = *p;
-#define node	rb_entry(parent, struct sysfs_dirent, inode_node)
-		if (sd->s_ino < node->s_ino) {
-			p = &node->inode_node.rb_left;
-		} else if (sd->s_ino > node->s_ino) {
-			p = &node->inode_node.rb_right;
-		} else {
-			printk(KERN_CRIT "sysfs: inserting duplicate inode '%lx'\n",
-			       (unsigned long) sd->s_ino);
-			BUG();
-		}
-#undef node
-	}
-	rb_link_node(&sd->inode_node, parent, p);
-	rb_insert_color(&sd->inode_node, &parent_sd->s_dir.inode_tree);
+	while (*node) {
+		struct sysfs_dirent *pos;
+		int result;
 
-	p = &parent_sd->s_dir.name_tree.rb_node;
-	parent = NULL;
-	while (*p) {
-		int c;
-		parent = *p;
-#define node	rb_entry(parent, struct sysfs_dirent, name_node)
-		c = strcmp(sd->s_name, node->s_name);
-		if (c < 0) {
-			p = &node->name_node.rb_left;
-		} else {
-			p = &node->name_node.rb_right;
-		}
-#undef node
+		pos = to_sysfs_dirent(*node);
+		parent = *node;
+		result = sysfs_sd_compare(sd, pos);
+		if (result < 0)
+			node = &pos->s_rb.rb_left;
+		else if (result > 0)
+			node = &pos->s_rb.rb_right;
+		else
+			return -EEXIST;
 	}
-	rb_link_node(&sd->name_node, parent, p);
-	rb_insert_color(&sd->name_node, &parent_sd->s_dir.name_tree);
+	/* add new node and rebalance the tree */
+	rb_link_node(&sd->s_rb, parent, node);
+	rb_insert_color(&sd->s_rb, &sd->s_parent->s_dir.children);
+	return 0;
 }
 
 /**
- *	sysfs_unlink_sibling - unlink sysfs_dirent from sibling list
+ *	sysfs_unlink_sibling - unlink sysfs_dirent from sibling rbtree
  *	@sd: sysfs_dirent of interest
  *
- *	Unlink @sd from its sibling list which starts from
+ *	Unlink @sd from its sibling rbtree which starts from
  *	sd->s_parent->s_dir.children.
  *
  *	Locking:
@@ -102,8 +129,7 @@
 	if (sysfs_type(sd) == SYSFS_DIR)
 		sd->s_parent->s_dir.subdirs--;
 
-	rb_erase(&sd->inode_node, &sd->s_parent->s_dir.inode_tree);
-	rb_erase(&sd->name_node, &sd->s_parent->s_dir.name_tree);
+	rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children);
 }
 
 /**
@@ -198,7 +224,7 @@
 	rwsem_release(&sd->dep_map, 1, _RET_IP_);
 }
 
-static int sysfs_alloc_ino(ino_t *pino)
+static int sysfs_alloc_ino(unsigned int *pino)
 {
 	int ino, rc;
 
@@ -217,7 +243,7 @@
 	return rc;
 }
 
-static void sysfs_free_ino(ino_t ino)
+static void sysfs_free_ino(unsigned int ino)
 {
 	spin_lock(&sysfs_ino_lock);
 	ida_remove(&sysfs_ino_ida, ino);
@@ -402,6 +428,7 @@
 int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
 {
 	struct sysfs_inode_attrs *ps_iattr;
+	int ret;
 
 	if (!!sysfs_ns_type(acxt->parent_sd) != !!sd->s_ns) {
 		WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n",
@@ -410,12 +437,12 @@
 		return -EINVAL;
 	}
 
-	if (sysfs_find_dirent(acxt->parent_sd, sd->s_ns, sd->s_name))
-		return -EEXIST;
-
+	sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name);
 	sd->s_parent = sysfs_get(acxt->parent_sd);
 
-	sysfs_link_sibling(sd);
+	ret = sysfs_link_sibling(sd);
+	if (ret)
+		return ret;
 
 	/* Update timestamps on the parent */
 	ps_iattr = acxt->parent_sd->s_iattr;
@@ -565,8 +592,8 @@
 				       const void *ns,
 				       const unsigned char *name)
 {
-	struct rb_node *p = parent_sd->s_dir.name_tree.rb_node;
-	struct sysfs_dirent *found = NULL;
+	struct rb_node *node = parent_sd->s_dir.children.rb_node;
+	unsigned int hash;
 
 	if (!!sysfs_ns_type(parent_sd) != !!ns) {
 		WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n",
@@ -575,33 +602,21 @@
 		return NULL;
 	}
 
-	while (p) {
-		int c;
-#define node	rb_entry(p, struct sysfs_dirent, name_node)
-		c = strcmp(name, node->s_name);
-		if (c < 0) {
-			p = node->name_node.rb_left;
-		} else if (c > 0) {
-			p = node->name_node.rb_right;
-		} else {
-			found = node;
-			p = node->name_node.rb_left;
-		}
-#undef node
-	}
+	hash = sysfs_name_hash(ns, name);
+	while (node) {
+		struct sysfs_dirent *sd;
+		int result;
 
-	if (found) {
-		while (found->s_ns != ns) {
-			p = rb_next(&found->name_node);
-			if (!p)
-				return NULL;
-			found = rb_entry(p, struct sysfs_dirent, name_node);
-			if (strcmp(name, found->s_name))
-				return NULL;
-		}
+		sd = to_sysfs_dirent(node);
+		result = sysfs_name_compare(hash, ns, name, sd);
+		if (result < 0)
+			node = node->rb_left;
+		else if (result > 0)
+			node = node->rb_right;
+		else
+			return sd;
 	}
-
-	return found;
+	return NULL;
 }
 
 /**
@@ -804,9 +819,9 @@
 
 	pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
 	sysfs_addrm_start(&acxt, dir_sd);
-	pos = rb_first(&dir_sd->s_dir.inode_tree);
+	pos = rb_first(&dir_sd->s_dir.children);
 	while (pos) {
-		struct sysfs_dirent *sd = rb_entry(pos, struct sysfs_dirent, inode_node);
+		struct sysfs_dirent *sd = to_sysfs_dirent(pos);
 		pos = rb_next(pos);
 		if (sysfs_type(sd) != SYSFS_DIR)
 			sysfs_remove_one(&acxt, sd);
@@ -863,6 +878,7 @@
 
 		dup_name = sd->s_name;
 		sd->s_name = new_name;
+		sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name);
 	}
 
 	/* Move to the appropriate place in the appropriate directories rbtree. */
@@ -919,38 +935,36 @@
 }
 
 static struct sysfs_dirent *sysfs_dir_pos(const void *ns,
-	struct sysfs_dirent *parent_sd,	ino_t ino, struct sysfs_dirent *pos)
+	struct sysfs_dirent *parent_sd,	loff_t hash, struct sysfs_dirent *pos)
 {
 	if (pos) {
 		int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) &&
 			pos->s_parent == parent_sd &&
-			ino == pos->s_ino;
+			hash == pos->s_hash;
 		sysfs_put(pos);
 		if (!valid)
 			pos = NULL;
 	}
-	if (!pos && (ino > 1) && (ino < INT_MAX)) {
-		struct rb_node *p = parent_sd->s_dir.inode_tree.rb_node;
-		while (p) {
-#define node	rb_entry(p, struct sysfs_dirent, inode_node)
-			if (ino < node->s_ino) {
-				pos = node;
-				p = node->inode_node.rb_left;
-			} else if (ino > node->s_ino) {
-				p = node->inode_node.rb_right;
-			} else {
-				pos = node;
+	if (!pos && (hash > 1) && (hash < INT_MAX)) {
+		struct rb_node *node = parent_sd->s_dir.children.rb_node;
+		while (node) {
+			pos = to_sysfs_dirent(node);
+
+			if (hash < pos->s_hash)
+				node = node->rb_left;
+			else if (hash > pos->s_hash)
+				node = node->rb_right;
+			else
 				break;
-			}
-#undef node
 		}
 	}
+	/* Skip over entries in the wrong namespace */
 	while (pos && pos->s_ns != ns) {
-		struct rb_node *p = rb_next(&pos->inode_node);
-		if (!p)
+		struct rb_node *node = rb_next(&pos->s_rb);
+		if (!node)
 			pos = NULL;
 		else
-			pos = rb_entry(p, struct sysfs_dirent, inode_node);
+			pos = to_sysfs_dirent(node);
 	}
 	return pos;
 }
@@ -960,11 +974,11 @@
 {
 	pos = sysfs_dir_pos(ns, parent_sd, ino, pos);
 	if (pos) do {
-		struct rb_node *p = rb_next(&pos->inode_node);
-		if (!p)
+		struct rb_node *node = rb_next(&pos->s_rb);
+		if (!node)
 			pos = NULL;
 		else
-			pos = rb_entry(p, struct sysfs_dirent, inode_node);
+			pos = to_sysfs_dirent(node);
 	} while (pos && pos->s_ns != ns);
 	return pos;
 }
@@ -1006,7 +1020,7 @@
 		len = strlen(name);
 		ino = pos->s_ino;
 		type = dt_type(pos);
-		filp->f_pos = ino;
+		filp->f_pos = pos->s_hash;
 		filp->private_data = sysfs_get(pos);
 
 		mutex_unlock(&sysfs_mutex);
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 85eb816..feb2d69 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -136,12 +136,13 @@
 	void *old_secdata;
 	size_t old_secdata_len;
 
-	iattrs = sd->s_iattr;
-	if (!iattrs)
-		iattrs = sysfs_init_inode_attrs(sd);
-	if (!iattrs)
-		return -ENOMEM;
+	if (!sd->s_iattr) {
+		sd->s_iattr = sysfs_init_inode_attrs(sd);
+		if (!sd->s_iattr)
+			return -ENOMEM;
+	}
 
+	iattrs = sd->s_iattr;
 	old_secdata = iattrs->ia_secdata;
 	old_secdata_len = iattrs->ia_secdata_len;
 
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index e34f0d9..140f26a 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -36,7 +36,7 @@
 	.s_name		= "",
 	.s_count	= ATOMIC_INIT(1),
 	.s_flags	= SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT),
-	.s_mode		= S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
+	.s_mode		= S_IFDIR | S_IRUGO | S_IXUGO,
 	.s_ino		= 1,
 };
 
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 7484a36..661a963 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -20,9 +20,8 @@
 	struct kobject		*kobj;
 
 	unsigned long		subdirs;
-
-	struct rb_root		inode_tree;
-	struct rb_root		name_tree;
+	/* children rbtree starts here and goes through sd->s_rb */
+	struct rb_root		children;
 };
 
 struct sysfs_elem_symlink {
@@ -62,8 +61,7 @@
 	struct sysfs_dirent	*s_parent;
 	const char		*s_name;
 
-	struct rb_node		inode_node;
-	struct rb_node		name_node;
+	struct rb_node		s_rb;
 
 	union {
 		struct completion	*completion;
@@ -71,6 +69,7 @@
 	} u;
 
 	const void		*s_ns; /* namespace tag */
+	unsigned int		s_hash; /* ns + name hash */
 	union {
 		struct sysfs_elem_dir		s_dir;
 		struct sysfs_elem_symlink	s_symlink;
@@ -78,9 +77,9 @@
 		struct sysfs_elem_bin_attr	s_bin_attr;
 	};
 
-	unsigned int		s_flags;
+	unsigned short		s_flags;
 	umode_t 		s_mode;
-	ino_t			s_ino;
+	unsigned int		s_ino;
 	struct sysfs_inode_attrs *s_iattr;
 };
 
@@ -95,11 +94,11 @@
 #define SYSFS_ACTIVE_REF		(SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR)
 
 /* identify any namespace tag on sysfs_dirents */
-#define SYSFS_NS_TYPE_MASK		0xff00
+#define SYSFS_NS_TYPE_MASK		0xf00
 #define SYSFS_NS_TYPE_SHIFT		8
 
 #define SYSFS_FLAG_MASK			~(SYSFS_NS_TYPE_MASK|SYSFS_TYPE_MASK)
-#define SYSFS_FLAG_REMOVED		0x020000
+#define SYSFS_FLAG_REMOVED		0x02000
 
 static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
 {
diff --git a/fs/udf/file.c b/fs/udf/file.c
index dca0c38..d567b84 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -201,12 +201,10 @@
 static int udf_release_file(struct inode *inode, struct file *filp)
 {
 	if (filp->f_mode & FMODE_WRITE) {
-		mutex_lock(&inode->i_mutex);
 		down_write(&UDF_I(inode)->i_data_sem);
 		udf_discard_prealloc(inode);
 		udf_truncate_tail_extent(inode);
 		up_write(&UDF_I(inode)->i_data_sem);
-		mutex_unlock(&inode->i_mutex);
 	}
 	return 0;
 }
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 8cf7e98..9d65047 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -225,6 +225,7 @@
 	} piix4;
 };
 
+extern void acpi_processor_load_module(struct acpi_processor *pr);
 extern int acpi_processor_preregister_performance(struct
 						  acpi_processor_performance
 						  __percpu *performance);
diff --git a/include/linux/altera_uart.h b/include/linux/altera_uart.h
index a10a907..c022c82 100644
--- a/include/linux/altera_uart.h
+++ b/include/linux/altera_uart.h
@@ -5,8 +5,6 @@
 #ifndef	__ALTUART_H
 #define	__ALTUART_H
 
-#include <linux/init.h>
-
 struct altera_uart_platform_uart {
 	unsigned long mapbase;	/* Physical address base */
 	unsigned int irq;	/* Interrupt vector */
@@ -14,6 +12,4 @@
 	unsigned int bus_shift;	/* Bus shift (address stride) */
 };
 
-int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp);
-
 #endif /* __ALTUART_H */
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index e9b6021..501adb1 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -160,38 +160,6 @@
 	CGRP_CLONE_CHILDREN,
 };
 
-/* which pidlist file are we talking about? */
-enum cgroup_filetype {
-	CGROUP_FILE_PROCS,
-	CGROUP_FILE_TASKS,
-};
-
-/*
- * A pidlist is a list of pids that virtually represents the contents of one
- * of the cgroup files ("procs" or "tasks"). We keep a list of such pidlists,
- * a pair (one each for procs, tasks) for each pid namespace that's relevant
- * to the cgroup.
- */
-struct cgroup_pidlist {
-	/*
-	 * used to find which pidlist is wanted. doesn't change as long as
-	 * this particular list stays in the list.
-	 */
-	struct { enum cgroup_filetype type; struct pid_namespace *ns; } key;
-	/* array of xids */
-	pid_t *list;
-	/* how many elements the above list has */
-	int length;
-	/* how many files are using the current array */
-	int use_count;
-	/* each of these stored in a list by its cgroup */
-	struct list_head links;
-	/* pointer to the cgroup we belong to, for list removal purposes */
-	struct cgroup *owner;
-	/* protects the other fields */
-	struct rw_semaphore mutex;
-};
-
 struct cgroup {
 	unsigned long flags;		/* "unsigned long" so bitops work */
 
@@ -484,23 +452,18 @@
  */
 
 struct cgroup_subsys {
-	struct cgroup_subsys_state *(*create)(struct cgroup_subsys *ss,
-						  struct cgroup *cgrp);
-	int (*pre_destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
-	void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
-	int (*can_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
-			  struct cgroup_taskset *tset);
-	void (*cancel_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
-			      struct cgroup_taskset *tset);
-	void (*attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
-		       struct cgroup_taskset *tset);
-	void (*fork)(struct cgroup_subsys *ss, struct task_struct *task);
-	void (*exit)(struct cgroup_subsys *ss, struct cgroup *cgrp,
-			struct cgroup *old_cgrp, struct task_struct *task);
-	int (*populate)(struct cgroup_subsys *ss,
-			struct cgroup *cgrp);
-	void (*post_clone)(struct cgroup_subsys *ss, struct cgroup *cgrp);
-	void (*bind)(struct cgroup_subsys *ss, struct cgroup *root);
+	struct cgroup_subsys_state *(*create)(struct cgroup *cgrp);
+	int (*pre_destroy)(struct cgroup *cgrp);
+	void (*destroy)(struct cgroup *cgrp);
+	int (*can_attach)(struct cgroup *cgrp, struct cgroup_taskset *tset);
+	void (*cancel_attach)(struct cgroup *cgrp, struct cgroup_taskset *tset);
+	void (*attach)(struct cgroup *cgrp, struct cgroup_taskset *tset);
+	void (*fork)(struct task_struct *task);
+	void (*exit)(struct cgroup *cgrp, struct cgroup *old_cgrp,
+		     struct task_struct *task);
+	int (*populate)(struct cgroup_subsys *ss, struct cgroup *cgrp);
+	void (*post_clone)(struct cgroup *cgrp);
+	void (*bind)(struct cgroup *root);
 
 	int subsys_id;
 	int active;
@@ -602,11 +565,6 @@
 int cgroup_attach_task(struct cgroup *, struct task_struct *);
 int cgroup_attach_task_all(struct task_struct *from, struct task_struct *);
 
-static inline int cgroup_attach_task_current_cg(struct task_struct *tsk)
-{
-	return cgroup_attach_task_all(current, tsk);
-}
-
 /*
  * CSS ID is ID for cgroup_subsys_state structs under subsys. This only works
  * if cgroup_subsys.use_id == true. It can be used for looking up and scanning.
@@ -669,10 +627,6 @@
 {
 	return 0;
 }
-static inline int cgroup_attach_task_current_cg(struct task_struct *t)
-{
-	return 0;
-}
 
 #endif /* !CONFIG_CGROUPS */
 
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 081147d..fbe89e1 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -319,13 +319,6 @@
 	__clocksource_updatefreq_scale(cs, 1000, khz);
 }
 
-static inline void
-clocksource_calc_mult_shift(struct clocksource *cs, u32 freq, u32 minsec)
-{
-	return clocks_calc_mult_shift(&cs->mult, &cs->shift, freq,
-				      NSEC_PER_SEC, minsec);
-}
-
 #ifdef CONFIG_GENERIC_TIME_VSYSCALL
 extern void
 update_vsyscall(struct timespec *ts, struct timespec *wtm,
diff --git a/include/linux/connector.h b/include/linux/connector.h
index 3c9c54f..7638407 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -43,6 +43,7 @@
 #define CN_IDX_DRBD			0x8
 #define CN_VAL_DRBD			0x1
 #define CN_KVP_IDX			0x9	/* HyperV KVP */
+#define CN_KVP_VAL			0x1	/* queries from the kernel */
 
 #define CN_NETLINK_USERS		10	/* Highest index + 1 */
 
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 1f65875..6e53b48 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -44,6 +44,13 @@
 #endif
 struct notifier_block;
 
+#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
+extern int arch_cpu_uevent(struct device *dev, struct kobj_uevent_env *env);
+extern ssize_t arch_print_cpu_modalias(struct device *dev,
+				       struct device_attribute *attr,
+				       char *bufptr);
+#endif
+
 /*
  * CPU notifier priorities.
  */
diff --git a/include/linux/device.h b/include/linux/device.h
index b63fb39..7c46bc3 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -238,8 +238,6 @@
 extern int __must_check driver_register(struct device_driver *drv);
 extern void driver_unregister(struct device_driver *drv);
 
-extern struct device_driver *get_driver(struct device_driver *drv);
-extern void put_driver(struct device_driver *drv);
 extern struct device_driver *driver_find(const char *name,
 					 struct bus_type *bus);
 extern int driver_probe_done(void);
@@ -946,14 +944,14 @@
 
 #define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg)
 
-#if defined(DEBUG)
-#define dev_dbg(dev, format, arg...)		\
-	dev_printk(KERN_DEBUG, dev, format, ##arg)
-#elif defined(CONFIG_DYNAMIC_DEBUG)
+#if defined(CONFIG_DYNAMIC_DEBUG)
 #define dev_dbg(dev, format, ...)		     \
 do {						     \
 	dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
 } while (0)
+#elif defined(DEBUG)
+#define dev_dbg(dev, format, arg...)		\
+	dev_printk(KERN_DEBUG, dev, format, ##arg)
 #else
 #define dev_dbg(dev, format, arg...)				\
 ({								\
@@ -1007,19 +1005,20 @@
  * @__driver: driver name
  * @__register: register function for this driver type
  * @__unregister: unregister function for this driver type
+ * @...: Additional arguments to be passed to __register and __unregister.
  *
  * Use this macro to construct bus specific macros for registering
  * drivers, and do not use it on its own.
  */
-#define module_driver(__driver, __register, __unregister) \
+#define module_driver(__driver, __register, __unregister, ...) \
 static int __init __driver##_init(void) \
 { \
-	return __register(&(__driver)); \
+	return __register(&(__driver) , ##__VA_ARGS__); \
 } \
 module_init(__driver##_init); \
 static void __exit __driver##_exit(void) \
 { \
-	__unregister(&(__driver)); \
+	__unregister(&(__driver) , ##__VA_ARGS__); \
 } \
 module_exit(__driver##_exit);
 
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 0564e3c..7e3c53a 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -15,20 +15,24 @@
 	const char *function;
 	const char *filename;
 	const char *format;
-	unsigned int lineno:24;
+	unsigned int lineno:18;
 	/*
  	 * The flags field controls the behaviour at the callsite.
  	 * The bits here are changed dynamically when the user
 	 * writes commands to <debugfs>/dynamic_debug/control
 	 */
-#define _DPRINTK_FLAGS_PRINT   (1<<0)  /* printk() a message using the format */
+#define _DPRINTK_FLAGS_NONE	0
+#define _DPRINTK_FLAGS_PRINT	(1<<0) /* printk() a message using the format */
 #define _DPRINTK_FLAGS_INCL_MODNAME	(1<<1)
 #define _DPRINTK_FLAGS_INCL_FUNCNAME	(1<<2)
 #define _DPRINTK_FLAGS_INCL_LINENO	(1<<3)
 #define _DPRINTK_FLAGS_INCL_TID		(1<<4)
+#if defined DEBUG
+#define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT
+#else
 #define _DPRINTK_FLAGS_DEFAULT 0
+#endif
 	unsigned int flags:8;
-	char enabled;
 } __attribute__((aligned(8)));
 
 
@@ -62,21 +66,20 @@
 		.format = (fmt),				\
 		.lineno = __LINE__,				\
 		.flags =  _DPRINTK_FLAGS_DEFAULT,		\
-		.enabled = false,				\
 	}
 
 #define dynamic_pr_debug(fmt, ...)				\
 do {								\
 	DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt);		\
-	if (unlikely(descriptor.enabled))			\
+	if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT))	\
 		__dynamic_pr_debug(&descriptor, pr_fmt(fmt),	\
 				   ##__VA_ARGS__);		\
 } while (0)
 
 #define dynamic_dev_dbg(dev, fmt, ...)				\
 do {								\
-	DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt);	\
-	if (unlikely(descriptor.enabled))			\
+	DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt);		\
+	if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT))	\
 		__dynamic_dev_dbg(&descriptor, dev, fmt,	\
 				  ##__VA_ARGS__);		\
 } while (0)
@@ -84,7 +87,7 @@
 #define dynamic_netdev_dbg(dev, fmt, ...)			\
 do {								\
 	DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt);		\
-	if (unlikely(descriptor.enabled))			\
+	if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT))	\
 		__dynamic_netdev_dbg(&descriptor, dev, fmt,	\
 				     ##__VA_ARGS__);		\
 } while (0)
diff --git a/include/linux/errno.h b/include/linux/errno.h
index 4668583..2d09bfa 100644
--- a/include/linux/errno.h
+++ b/include/linux/errno.h
@@ -16,6 +16,7 @@
 #define ERESTARTNOHAND	514	/* restart if no handler.. */
 #define ENOIOCTLCMD	515	/* No ioctl command */
 #define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
+#define EPROBE_DEFER	517	/* Driver requests probe retry */
 
 /* Defined for the NFSv3 protocol */
 #define EBADHANDLE	521	/* Illegal NFS file handle */
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 028e26f..72a6cab 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -31,16 +31,33 @@
 
 typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip);
 
+/*
+ * FTRACE_OPS_FL_* bits denote the state of ftrace_ops struct and are
+ * set in the flags member.
+ *
+ * ENABLED - set/unset when ftrace_ops is registered/unregistered
+ * GLOBAL  - set manualy by ftrace_ops user to denote the ftrace_ops
+ *           is part of the global tracers sharing the same filter
+ *           via set_ftrace_* debugfs files.
+ * DYNAMIC - set when ftrace_ops is registered to denote dynamically
+ *           allocated ftrace_ops which need special care
+ * CONTROL - set manualy by ftrace_ops user to denote the ftrace_ops
+ *           could be controled by following calls:
+ *             ftrace_function_local_enable
+ *             ftrace_function_local_disable
+ */
 enum {
 	FTRACE_OPS_FL_ENABLED		= 1 << 0,
 	FTRACE_OPS_FL_GLOBAL		= 1 << 1,
 	FTRACE_OPS_FL_DYNAMIC		= 1 << 2,
+	FTRACE_OPS_FL_CONTROL		= 1 << 3,
 };
 
 struct ftrace_ops {
 	ftrace_func_t			func;
 	struct ftrace_ops		*next;
 	unsigned long			flags;
+	int __percpu			*disabled;
 #ifdef CONFIG_DYNAMIC_FTRACE
 	struct ftrace_hash		*notrace_hash;
 	struct ftrace_hash		*filter_hash;
@@ -97,6 +114,55 @@
 int unregister_ftrace_function(struct ftrace_ops *ops);
 void clear_ftrace_function(void);
 
+/**
+ * ftrace_function_local_enable - enable controlled ftrace_ops on current cpu
+ *
+ * This function enables tracing on current cpu by decreasing
+ * the per cpu control variable.
+ * It must be called with preemption disabled and only on ftrace_ops
+ * registered with FTRACE_OPS_FL_CONTROL. If called without preemption
+ * disabled, this_cpu_ptr will complain when CONFIG_DEBUG_PREEMPT is enabled.
+ */
+static inline void ftrace_function_local_enable(struct ftrace_ops *ops)
+{
+	if (WARN_ON_ONCE(!(ops->flags & FTRACE_OPS_FL_CONTROL)))
+		return;
+
+	(*this_cpu_ptr(ops->disabled))--;
+}
+
+/**
+ * ftrace_function_local_disable - enable controlled ftrace_ops on current cpu
+ *
+ * This function enables tracing on current cpu by decreasing
+ * the per cpu control variable.
+ * It must be called with preemption disabled and only on ftrace_ops
+ * registered with FTRACE_OPS_FL_CONTROL. If called without preemption
+ * disabled, this_cpu_ptr will complain when CONFIG_DEBUG_PREEMPT is enabled.
+ */
+static inline void ftrace_function_local_disable(struct ftrace_ops *ops)
+{
+	if (WARN_ON_ONCE(!(ops->flags & FTRACE_OPS_FL_CONTROL)))
+		return;
+
+	(*this_cpu_ptr(ops->disabled))++;
+}
+
+/**
+ * ftrace_function_local_disabled - returns ftrace_ops disabled value
+ *                                  on current cpu
+ *
+ * This function returns value of ftrace_ops::disabled on current cpu.
+ * It must be called with preemption disabled and only on ftrace_ops
+ * registered with FTRACE_OPS_FL_CONTROL. If called without preemption
+ * disabled, this_cpu_ptr will complain when CONFIG_DEBUG_PREEMPT is enabled.
+ */
+static inline int ftrace_function_local_disabled(struct ftrace_ops *ops)
+{
+	WARN_ON_ONCE(!(ops->flags & FTRACE_OPS_FL_CONTROL));
+	return *this_cpu_ptr(ops->disabled);
+}
+
 extern void ftrace_stub(unsigned long a0, unsigned long a1);
 
 #else /* !CONFIG_FUNCTION_TRACER */
@@ -178,12 +244,13 @@
 };
 
 int ftrace_force_update(void);
-void ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf,
+int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf,
 		       int len, int reset);
-void ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,
+int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,
 			int len, int reset);
 void ftrace_set_global_filter(unsigned char *buf, int len, int reset);
 void ftrace_set_global_notrace(unsigned char *buf, int len, int reset);
+void ftrace_free_filter(struct ftrace_ops *ops);
 
 int register_ftrace_command(struct ftrace_func_command *cmd);
 int unregister_ftrace_command(struct ftrace_func_command *cmd);
@@ -314,9 +381,6 @@
 #else
 static inline int skip_trace(unsigned long ip) { return 0; }
 static inline int ftrace_force_update(void) { return 0; }
-static inline void ftrace_set_filter(unsigned char *buf, int len, int reset)
-{
-}
 static inline void ftrace_disable_daemon(void) { }
 static inline void ftrace_enable_daemon(void) { }
 static inline void ftrace_release_mod(struct module *mod) {}
@@ -340,6 +404,9 @@
  */
 #define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; })
 #define ftrace_set_early_filter(ops, buf, enable) do { } while (0)
+#define ftrace_set_filter(ops, buf, len, reset) ({ -ENODEV; })
+#define ftrace_set_notrace(ops, buf, len, reset) ({ -ENODEV; })
+#define ftrace_free_filter(ops) do { } while (0)
 
 static inline ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf,
 			    size_t cnt, loff_t *ppos) { return -ENODEV; }
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index c3da42d..dd478fc 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -146,6 +146,10 @@
 	TRACE_REG_UNREGISTER,
 	TRACE_REG_PERF_REGISTER,
 	TRACE_REG_PERF_UNREGISTER,
+	TRACE_REG_PERF_OPEN,
+	TRACE_REG_PERF_CLOSE,
+	TRACE_REG_PERF_ADD,
+	TRACE_REG_PERF_DEL,
 };
 
 struct ftrace_event_call;
@@ -157,7 +161,7 @@
 	void			*perf_probe;
 #endif
 	int			(*reg)(struct ftrace_event_call *event,
-				       enum trace_reg type);
+				       enum trace_reg type, void *data);
 	int			(*define_fields)(struct ftrace_event_call *);
 	struct list_head	*(*get_fields)(struct ftrace_event_call *);
 	struct list_head	fields;
@@ -165,7 +169,7 @@
 };
 
 extern int ftrace_event_reg(struct ftrace_event_call *event,
-			    enum trace_reg type);
+			    enum trace_reg type, void *data);
 
 enum {
 	TRACE_EVENT_FL_ENABLED_BIT,
@@ -241,6 +245,7 @@
 	FILTER_STATIC_STRING,
 	FILTER_DYN_STRING,
 	FILTER_PTR_STRING,
+	FILTER_TRACE_FN,
 };
 
 #define EVENT_STORAGE_SIZE 128
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index fe23ee7..e61d319 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -596,6 +596,7 @@
 
 extern int disk_expand_part_tbl(struct gendisk *disk, int target);
 extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
+extern int invalidate_partitions(struct gendisk *disk, struct block_device *bdev);
 extern struct hd_struct * __must_check add_partition(struct gendisk *disk,
 						     int partno, sector_t start,
 						     sector_t len, int flags,
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 0ae065a..5852545 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -25,6 +25,173 @@
 #ifndef _HYPERV_H
 #define _HYPERV_H
 
+#include <linux/types.h>
+
+/*
+ * An implementation of HyperV key value pair (KVP) functionality for Linux.
+ *
+ *
+ * Copyright (C) 2010, Novell, Inc.
+ * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
+ *
+ */
+
+/*
+ * Maximum value size - used for both key names and value data, and includes
+ * any applicable NULL terminators.
+ *
+ * Note:  This limit is somewhat arbitrary, but falls easily within what is
+ * supported for all native guests (back to Win 2000) and what is reasonable
+ * for the IC KVP exchange functionality.  Note that Windows Me/98/95 are
+ * limited to 255 character key names.
+ *
+ * MSDN recommends not storing data values larger than 2048 bytes in the
+ * registry.
+ *
+ * Note:  This value is used in defining the KVP exchange message - this value
+ * cannot be modified without affecting the message size and compatibility.
+ */
+
+/*
+ * bytes, including any null terminators
+ */
+#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE          (2048)
+
+
+/*
+ * Maximum key size - the registry limit for the length of an entry name
+ * is 256 characters, including the null terminator
+ */
+
+#define HV_KVP_EXCHANGE_MAX_KEY_SIZE            (512)
+
+/*
+ * In Linux, we implement the KVP functionality in two components:
+ * 1) The kernel component which is packaged as part of the hv_utils driver
+ * is responsible for communicating with the host and responsible for
+ * implementing the host/guest protocol. 2) A user level daemon that is
+ * responsible for data gathering.
+ *
+ * Host/Guest Protocol: The host iterates over an index and expects the guest
+ * to assign a key name to the index and also return the value corresponding to
+ * the key. The host will have atmost one KVP transaction outstanding at any
+ * given point in time. The host side iteration stops when the guest returns
+ * an error. Microsoft has specified the following mapping of key names to
+ * host specified index:
+ *
+ *	Index		Key Name
+ *	0		FullyQualifiedDomainName
+ *	1		IntegrationServicesVersion
+ *	2		NetworkAddressIPv4
+ *	3		NetworkAddressIPv6
+ *	4		OSBuildNumber
+ *	5		OSName
+ *	6		OSMajorVersion
+ *	7		OSMinorVersion
+ *	8		OSVersion
+ *	9		ProcessorArchitecture
+ *
+ * The Windows host expects the Key Name and Key Value to be encoded in utf16.
+ *
+ * Guest Kernel/KVP Daemon Protocol: As noted earlier, we implement all of the
+ * data gathering functionality in a user mode daemon. The user level daemon
+ * is also responsible for binding the key name to the index as well. The
+ * kernel and user-level daemon communicate using a connector channel.
+ *
+ * The user mode component first registers with the
+ * the kernel component. Subsequently, the kernel component requests, data
+ * for the specified keys. In response to this message the user mode component
+ * fills in the value corresponding to the specified key. We overload the
+ * sequence field in the cn_msg header to define our KVP message types.
+ *
+ *
+ * The kernel component simply acts as a conduit for communication between the
+ * Windows host and the user-level daemon. The kernel component passes up the
+ * index received from the Host to the user-level daemon. If the index is
+ * valid (supported), the corresponding key as well as its
+ * value (both are strings) is returned. If the index is invalid
+ * (not supported), a NULL key string is returned.
+ */
+
+
+/*
+ * Registry value types.
+ */
+
+#define REG_SZ 1
+#define REG_U32 4
+#define REG_U64 8
+
+enum hv_kvp_exchg_op {
+	KVP_OP_GET = 0,
+	KVP_OP_SET,
+	KVP_OP_DELETE,
+	KVP_OP_ENUMERATE,
+	KVP_OP_REGISTER,
+	KVP_OP_COUNT /* Number of operations, must be last. */
+};
+
+enum hv_kvp_exchg_pool {
+	KVP_POOL_EXTERNAL = 0,
+	KVP_POOL_GUEST,
+	KVP_POOL_AUTO,
+	KVP_POOL_AUTO_EXTERNAL,
+	KVP_POOL_AUTO_INTERNAL,
+	KVP_POOL_COUNT /* Number of pools, must be last. */
+};
+
+struct hv_kvp_hdr {
+	__u8 operation;
+	__u8 pool;
+	__u16 pad;
+} __attribute__((packed));
+
+struct hv_kvp_exchg_msg_value {
+	__u32 value_type;
+	__u32 key_size;
+	__u32 value_size;
+	__u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+	union {
+		__u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
+		__u32 value_u32;
+		__u64 value_u64;
+	};
+} __attribute__((packed));
+
+struct hv_kvp_msg_enumerate {
+	__u32 index;
+	struct hv_kvp_exchg_msg_value data;
+} __attribute__((packed));
+
+struct hv_kvp_msg_get {
+	struct hv_kvp_exchg_msg_value data;
+};
+
+struct hv_kvp_msg_set {
+	struct hv_kvp_exchg_msg_value data;
+};
+
+struct hv_kvp_msg_delete {
+	__u32 key_size;
+	__u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+};
+
+struct hv_kvp_register {
+	__u8 version[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+};
+
+struct hv_kvp_msg {
+	struct hv_kvp_hdr	kvp_hdr;
+	union {
+		struct hv_kvp_msg_get		kvp_get;
+		struct hv_kvp_msg_set		kvp_set;
+		struct hv_kvp_msg_delete	kvp_delete;
+		struct hv_kvp_msg_enumerate	kvp_enum_data;
+		struct hv_kvp_register		kvp_register;
+	} body;
+} __attribute__((packed));
+
+#ifdef __KERNEL__
 #include <linux/scatterlist.h>
 #include <linux/list.h>
 #include <linux/uuid.h>
@@ -785,6 +952,7 @@
 
 #define HV_S_OK				0x00000000
 #define HV_E_FAIL			0x80004005
+#define HV_S_CONT			0x80070103
 #define HV_ERROR_NOT_SUPPORTED		0x80070032
 #define HV_ERROR_MACHINE_LOCKED		0x800704F7
 
@@ -870,4 +1038,9 @@
 extern void vmbus_prep_negotiate_resp(struct icmsg_hdr *,
 				      struct icmsg_negotiate *, u8 *);
 
+int hv_kvp_init(struct hv_util_service *);
+void hv_kvp_deinit(void);
+void hv_kvp_onchannelcallback(void *);
+
+#endif /* __KERNEL__ */
 #endif /* _HYPERV_H */
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 9c66b1a..f994d51 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -149,7 +149,7 @@
 	},								\
 	.rt		= {						\
 		.run_list	= LIST_HEAD_INIT(tsk.rt.run_list),	\
-		.time_slice	= HZ, 					\
+		.time_slice	= RR_TIMESLICE,				\
 		.nr_cpus_allowed = NR_CPUS,				\
 	},								\
 	.tasks		= LIST_HEAD_INIT(tsk.tasks),			\
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index a64b00e..3f830e0 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -20,7 +20,6 @@
 #include <linux/atomic.h>
 #include <asm/ptrace.h>
 #include <asm/system.h>
-#include <trace/events/irq.h>
 
 /*
  * These correspond to the IORESOURCE_IRQ_* defines in
@@ -456,11 +455,7 @@
 asmlinkage void __do_softirq(void);
 extern void open_softirq(int nr, void (*action)(struct softirq_action *));
 extern void softirq_init(void);
-static inline void __raise_softirq_irqoff(unsigned int nr)
-{
-	trace_softirq_raise(nr);
-	or_softirq_pending(1UL << nr);
-}
+extern void __raise_softirq_irqoff(unsigned int nr);
 
 extern void raise_softirq_irqoff(unsigned int nr);
 extern void raise_softirq(unsigned int nr);
diff --git a/include/linux/iocontext.h b/include/linux/iocontext.h
index 119773e..1a30180 100644
--- a/include/linux/iocontext.h
+++ b/include/linux/iocontext.h
@@ -6,8 +6,11 @@
 #include <linux/workqueue.h>
 
 enum {
-	ICQ_IOPRIO_CHANGED,
-	ICQ_CGROUP_CHANGED,
+	ICQ_IOPRIO_CHANGED	= 1 << 0,
+	ICQ_CGROUP_CHANGED	= 1 << 1,
+	ICQ_EXITED		= 1 << 2,
+
+	ICQ_CHANGED_MASK	= ICQ_IOPRIO_CHANGED | ICQ_CGROUP_CHANGED,
 };
 
 /*
@@ -88,7 +91,7 @@
 		struct rcu_head		__rcu_head;
 	};
 
-	unsigned long		changed;
+	unsigned int		flags;
 };
 
 /*
@@ -139,6 +142,7 @@
 				       gfp_t gfp_flags, int node);
 void ioc_ioprio_changed(struct io_context *ioc, int ioprio);
 void ioc_cgroup_changed(struct io_context *ioc);
+unsigned int icq_get_changed(struct io_cq *icq);
 #else
 struct io_context;
 static inline void put_io_context(struct io_context *ioc) { }
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h
index 5ce8b14..c513a40 100644
--- a/include/linux/jump_label.h
+++ b/include/linux/jump_label.h
@@ -1,22 +1,69 @@
 #ifndef _LINUX_JUMP_LABEL_H
 #define _LINUX_JUMP_LABEL_H
 
+/*
+ * Jump label support
+ *
+ * Copyright (C) 2009-2012 Jason Baron <jbaron@redhat.com>
+ * Copyright (C) 2011-2012 Peter Zijlstra <pzijlstr@redhat.com>
+ *
+ * Jump labels provide an interface to generate dynamic branches using
+ * self-modifying code. Assuming toolchain and architecture support the result
+ * of a "if (static_key_false(&key))" statement is a unconditional branch (which
+ * defaults to false - and the true block is placed out of line).
+ *
+ * However at runtime we can change the branch target using
+ * static_key_slow_{inc,dec}(). These function as a 'reference' count on the key
+ * object and for as long as there are references all branches referring to
+ * that particular key will point to the (out of line) true block.
+ *
+ * Since this relies on modifying code the static_key_slow_{inc,dec}() functions
+ * must be considered absolute slow paths (machine wide synchronization etc.).
+ * OTOH, since the affected branches are unconditional their runtime overhead
+ * will be absolutely minimal, esp. in the default (off) case where the total
+ * effect is a single NOP of appropriate size. The on case will patch in a jump
+ * to the out-of-line block.
+ *
+ * When the control is directly exposed to userspace it is prudent to delay the
+ * decrement to avoid high frequency code modifications which can (and do)
+ * cause significant performance degradation. Struct static_key_deferred and
+ * static_key_slow_dec_deferred() provide for this.
+ *
+ * Lacking toolchain and or architecture support, it falls back to a simple
+ * conditional branch.
+ *
+ * struct static_key my_key = STATIC_KEY_INIT_TRUE;
+ *
+ *   if (static_key_true(&my_key)) {
+ *   }
+ *
+ * will result in the true case being in-line and starts the key with a single
+ * reference. Mixing static_key_true() and static_key_false() on the same key is not
+ * allowed.
+ *
+ * Not initializing the key (static data is initialized to 0s anyway) is the
+ * same as using STATIC_KEY_INIT_FALSE and static_key_false() is
+ * equivalent with static_branch().
+ *
+*/
+
 #include <linux/types.h>
 #include <linux/compiler.h>
 #include <linux/workqueue.h>
 
 #if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL)
 
-struct jump_label_key {
+struct static_key {
 	atomic_t enabled;
+/* Set lsb bit to 1 if branch is default true, 0 ot */
 	struct jump_entry *entries;
 #ifdef CONFIG_MODULES
-	struct jump_label_mod *next;
+	struct static_key_mod *next;
 #endif
 };
 
-struct jump_label_key_deferred {
-	struct jump_label_key key;
+struct static_key_deferred {
+	struct static_key key;
 	unsigned long timeout;
 	struct delayed_work work;
 };
@@ -34,13 +81,34 @@
 
 #ifdef HAVE_JUMP_LABEL
 
-#ifdef CONFIG_MODULES
-#define JUMP_LABEL_INIT {ATOMIC_INIT(0), NULL, NULL}
-#else
-#define JUMP_LABEL_INIT {ATOMIC_INIT(0), NULL}
-#endif
+#define JUMP_LABEL_TRUE_BRANCH 1UL
 
-static __always_inline bool static_branch(struct jump_label_key *key)
+static
+inline struct jump_entry *jump_label_get_entries(struct static_key *key)
+{
+	return (struct jump_entry *)((unsigned long)key->entries
+						& ~JUMP_LABEL_TRUE_BRANCH);
+}
+
+static inline bool jump_label_get_branch_default(struct static_key *key)
+{
+	if ((unsigned long)key->entries & JUMP_LABEL_TRUE_BRANCH)
+		return true;
+	return false;
+}
+
+static __always_inline bool static_key_false(struct static_key *key)
+{
+	return arch_static_branch(key);
+}
+
+static __always_inline bool static_key_true(struct static_key *key)
+{
+	return !static_key_false(key);
+}
+
+/* Deprecated. Please use 'static_key_false() instead. */
+static __always_inline bool static_branch(struct static_key *key)
 {
 	return arch_static_branch(key);
 }
@@ -56,21 +124,23 @@
 extern void arch_jump_label_transform_static(struct jump_entry *entry,
 					     enum jump_label_type type);
 extern int jump_label_text_reserved(void *start, void *end);
-extern void jump_label_inc(struct jump_label_key *key);
-extern void jump_label_dec(struct jump_label_key *key);
-extern void jump_label_dec_deferred(struct jump_label_key_deferred *key);
-extern bool jump_label_enabled(struct jump_label_key *key);
+extern void static_key_slow_inc(struct static_key *key);
+extern void static_key_slow_dec(struct static_key *key);
+extern void static_key_slow_dec_deferred(struct static_key_deferred *key);
 extern void jump_label_apply_nops(struct module *mod);
-extern void jump_label_rate_limit(struct jump_label_key_deferred *key,
-		unsigned long rl);
+extern void
+jump_label_rate_limit(struct static_key_deferred *key, unsigned long rl);
+
+#define STATIC_KEY_INIT_TRUE ((struct static_key) \
+	{ .enabled = ATOMIC_INIT(1), .entries = (void *)1 })
+#define STATIC_KEY_INIT_FALSE ((struct static_key) \
+	{ .enabled = ATOMIC_INIT(0), .entries = (void *)0 })
 
 #else  /* !HAVE_JUMP_LABEL */
 
 #include <linux/atomic.h>
 
-#define JUMP_LABEL_INIT {ATOMIC_INIT(0)}
-
-struct jump_label_key {
+struct static_key {
 	atomic_t enabled;
 };
 
@@ -78,30 +148,45 @@
 {
 }
 
-struct jump_label_key_deferred {
-	struct jump_label_key  key;
+struct static_key_deferred {
+	struct static_key  key;
 };
 
-static __always_inline bool static_branch(struct jump_label_key *key)
+static __always_inline bool static_key_false(struct static_key *key)
 {
-	if (unlikely(atomic_read(&key->enabled)))
+	if (unlikely(atomic_read(&key->enabled)) > 0)
 		return true;
 	return false;
 }
 
-static inline void jump_label_inc(struct jump_label_key *key)
+static __always_inline bool static_key_true(struct static_key *key)
+{
+	if (likely(atomic_read(&key->enabled)) > 0)
+		return true;
+	return false;
+}
+
+/* Deprecated. Please use 'static_key_false() instead. */
+static __always_inline bool static_branch(struct static_key *key)
+{
+	if (unlikely(atomic_read(&key->enabled)) > 0)
+		return true;
+	return false;
+}
+
+static inline void static_key_slow_inc(struct static_key *key)
 {
 	atomic_inc(&key->enabled);
 }
 
-static inline void jump_label_dec(struct jump_label_key *key)
+static inline void static_key_slow_dec(struct static_key *key)
 {
 	atomic_dec(&key->enabled);
 }
 
-static inline void jump_label_dec_deferred(struct jump_label_key_deferred *key)
+static inline void static_key_slow_dec_deferred(struct static_key_deferred *key)
 {
-	jump_label_dec(&key->key);
+	static_key_slow_dec(&key->key);
 }
 
 static inline int jump_label_text_reserved(void *start, void *end)
@@ -112,23 +197,30 @@
 static inline void jump_label_lock(void) {}
 static inline void jump_label_unlock(void) {}
 
-static inline bool jump_label_enabled(struct jump_label_key *key)
-{
-	return !!atomic_read(&key->enabled);
-}
-
 static inline int jump_label_apply_nops(struct module *mod)
 {
 	return 0;
 }
 
-static inline void jump_label_rate_limit(struct jump_label_key_deferred *key,
+static inline void
+jump_label_rate_limit(struct static_key_deferred *key,
 		unsigned long rl)
 {
 }
+
+#define STATIC_KEY_INIT_TRUE ((struct static_key) \
+		{ .enabled = ATOMIC_INIT(1) })
+#define STATIC_KEY_INIT_FALSE ((struct static_key) \
+		{ .enabled = ATOMIC_INIT(0) })
+
 #endif	/* HAVE_JUMP_LABEL */
 
-#define jump_label_key_enabled	((struct jump_label_key){ .enabled = ATOMIC_INIT(1), })
-#define jump_label_key_disabled	((struct jump_label_key){ .enabled = ATOMIC_INIT(0), })
+#define STATIC_KEY_INIT STATIC_KEY_INIT_FALSE
+#define jump_label_enabled static_key_enabled
+
+static inline bool static_key_enabled(struct static_key *key)
+{
+	return (atomic_read(&key->enabled) > 0);
+}
 
 #endif	/* _LINUX_JUMP_LABEL_H */
diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h
index ec2d17b..daf4a3a 100644
--- a/include/linux/kbd_kern.h
+++ b/include/linux/kbd_kern.h
@@ -7,8 +7,6 @@
 
 extern struct tasklet_struct keyboard_tasklet;
 
-extern int shift_state;
-
 extern char *func_table[MAX_NR_FUNC];
 extern char func_buf[];
 extern char *funcbufptr;
@@ -65,8 +63,6 @@
 #define VC_META		4	/* 0 - meta, 1 - meta=prefix with ESC */
 };
 
-extern struct kbd_struct kbd_table[];
-
 extern int kbd_init(void);
 
 extern unsigned char getledstate(void);
@@ -79,6 +75,7 @@
 extern int set_console(int nr);
 extern void schedule_console_callback(void);
 
+/* FIXME: review locking for vt.c callers */
 static inline void set_leds(void)
 {
 	tasklet_schedule(&keyboard_tasklet);
@@ -142,8 +139,6 @@
 
 struct console;
 
-int getkeycode(unsigned int scancode);
-int setkeycode(unsigned int scancode, unsigned int keycode);
 void compute_shiftstate(void);
 
 /* defkeymap.c */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index e834342..d801acb 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -85,6 +85,19 @@
 }							\
 )
 
+/*
+ * Multiplies an integer by a fraction, while avoiding unnecessary
+ * overflow or loss of precision.
+ */
+#define mult_frac(x, numer, denom)(			\
+{							\
+	typeof(x) quot = (x) / (denom);			\
+	typeof(x) rem  = (x) % (denom);			\
+	(quot * (numer)) + ((rem * (numer)) / (denom));	\
+}							\
+)
+
+
 #define _RET_IP_		(unsigned long)__builtin_return_address(0)
 #define _THIS_IP_  ({ __label__ __here; __here: (unsigned long)&&__here; })
 
diff --git a/include/linux/keyboard.h b/include/linux/keyboard.h
index 33a63f6..86e5214 100644
--- a/include/linux/keyboard.h
+++ b/include/linux/keyboard.h
@@ -24,8 +24,6 @@
 
 #ifdef __KERNEL__
 struct notifier_block;
-extern const int NR_TYPES;
-extern const int max_vals[];
 extern unsigned short *key_maps[MAX_NR_KEYMAPS];
 extern unsigned short plain_map[NR_KEYS];
 
diff --git a/include/linux/math64.h b/include/linux/math64.h
index 23fcdfc..b8ba855 100644
--- a/include/linux/math64.h
+++ b/include/linux/math64.h
@@ -6,6 +6,8 @@
 
 #if BITS_PER_LONG == 64
 
+#define div64_long(x,y) div64_s64((x),(y))
+
 /**
  * div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder
  *
@@ -45,6 +47,8 @@
 
 #elif BITS_PER_LONG == 32
 
+#define div64_long(x,y) div_s64((x),(y))
+
 #ifndef div_u64_rem
 static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
 {
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 83ac071..fb69ad1 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -560,4 +560,25 @@
 #endif
 };
 
+/*
+ * Match x86 CPUs for CPU specific drivers.
+ * See documentation of "x86_match_cpu" for details.
+ */
+
+struct x86_cpu_id {
+	__u16 vendor;
+	__u16 family;
+	__u16 model;
+	__u16 feature;	/* bit index */
+	kernel_ulong_t driver_data;
+};
+
+#define X86_FEATURE_MATCH(x) \
+	{ X86_VENDOR_ANY, X86_FAMILY_ANY, X86_MODEL_ANY, x }
+
+#define X86_VENDOR_ANY 0xffff
+#define X86_FAMILY_ANY 0
+#define X86_MODEL_ANY  0
+#define X86_FEATURE_ANY 0	/* Same as FPU, you can't test for that */
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 0eac07c..3e5cb25 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -214,8 +214,8 @@
 #include <linux/skbuff.h>
 
 #ifdef CONFIG_RPS
-#include <linux/jump_label.h>
-extern struct jump_label_key rps_needed;
+#include <linux/static_key.h>
+extern struct static_key rps_needed;
 #endif
 
 struct neighbour;
@@ -2687,14 +2687,14 @@
 #define MODULE_ALIAS_NETDEV(device) \
 	MODULE_ALIAS("netdev-" device)
 
-#if defined(DEBUG)
-#define netdev_dbg(__dev, format, args...)			\
-	netdev_printk(KERN_DEBUG, __dev, format, ##args)
-#elif defined(CONFIG_DYNAMIC_DEBUG)
+#if defined(CONFIG_DYNAMIC_DEBUG)
 #define netdev_dbg(__dev, format, args...)			\
 do {								\
 	dynamic_netdev_dbg(__dev, format, ##args);		\
 } while (0)
+#elif defined(DEBUG)
+#define netdev_dbg(__dev, format, args...)			\
+	netdev_printk(KERN_DEBUG, __dev, format, ##args)
 #else
 #define netdev_dbg(__dev, format, args...)			\
 ({								\
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index b809265..29734be 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -163,13 +163,13 @@
 extern struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
 
 #if defined(CONFIG_JUMP_LABEL)
-#include <linux/jump_label.h>
-extern struct jump_label_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
+#include <linux/static_key.h>
+extern struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
 static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook)
 {
 	if (__builtin_constant_p(pf) &&
 	    __builtin_constant_p(hook))
-		return static_branch(&nf_hooks_needed[pf][hook]);
+		return static_key_false(&nf_hooks_needed[pf][hook]);
 
 	return !list_empty(&nf_hooks[pf][hook]);
 }
diff --git a/include/linux/pci.h b/include/linux/pci.h
index a16b1df..d4afd70 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -946,6 +946,19 @@
 	__pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
 
 void pci_unregister_driver(struct pci_driver *dev);
+
+/**
+ * module_pci_driver() - Helper macro for registering a PCI driver
+ * @__pci_driver: pci_driver struct
+ *
+ * Helper macro for PCI drivers which do not do anything special in module
+ * init/exit. This eliminates a lot of boilerplate. Each module may only
+ * use this macro once, and calling it replaces module_init() and module_exit()
+ */
+#define module_pci_driver(__pci_driver) \
+	module_driver(__pci_driver, pci_register_driver, \
+		       pci_unregister_driver)
+
 void pci_remove_behind_bridge(struct pci_dev *dev);
 struct pci_driver *pci_dev_driver(const struct pci_dev *dev);
 int pci_add_dynid(struct pci_driver *drv,
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index abb2776..bd9f55a 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -129,11 +129,40 @@
 	PERF_SAMPLE_PERIOD			= 1U << 8,
 	PERF_SAMPLE_STREAM_ID			= 1U << 9,
 	PERF_SAMPLE_RAW				= 1U << 10,
+	PERF_SAMPLE_BRANCH_STACK		= 1U << 11,
 
-	PERF_SAMPLE_MAX = 1U << 11,		/* non-ABI */
+	PERF_SAMPLE_MAX = 1U << 12,		/* non-ABI */
 };
 
 /*
+ * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set
+ *
+ * If the user does not pass priv level information via branch_sample_type,
+ * the kernel uses the event's priv level. Branch and event priv levels do
+ * not have to match. Branch priv level is checked for permissions.
+ *
+ * The branch types can be combined, however BRANCH_ANY covers all types
+ * of branches and therefore it supersedes all the other types.
+ */
+enum perf_branch_sample_type {
+	PERF_SAMPLE_BRANCH_USER		= 1U << 0, /* user branches */
+	PERF_SAMPLE_BRANCH_KERNEL	= 1U << 1, /* kernel branches */
+	PERF_SAMPLE_BRANCH_HV		= 1U << 2, /* hypervisor branches */
+
+	PERF_SAMPLE_BRANCH_ANY		= 1U << 3, /* any branch types */
+	PERF_SAMPLE_BRANCH_ANY_CALL	= 1U << 4, /* any call branch */
+	PERF_SAMPLE_BRANCH_ANY_RETURN	= 1U << 5, /* any return branch */
+	PERF_SAMPLE_BRANCH_IND_CALL	= 1U << 6, /* indirect calls */
+
+	PERF_SAMPLE_BRANCH_MAX		= 1U << 7, /* non-ABI */
+};
+
+#define PERF_SAMPLE_BRANCH_PLM_ALL \
+	(PERF_SAMPLE_BRANCH_USER|\
+	 PERF_SAMPLE_BRANCH_KERNEL|\
+	 PERF_SAMPLE_BRANCH_HV)
+
+/*
  * The format of the data returned by read() on a perf event fd,
  * as specified by attr.read_format:
  *
@@ -163,6 +192,8 @@
 };
 
 #define PERF_ATTR_SIZE_VER0	64	/* sizeof first published struct */
+#define PERF_ATTR_SIZE_VER1	72	/* add: config2 */
+#define PERF_ATTR_SIZE_VER2	80	/* add: branch_sample_type */
 
 /*
  * Hardware event_id to monitor via a performance monitoring event:
@@ -240,6 +271,7 @@
 		__u64		bp_len;
 		__u64		config2; /* extension of config1 */
 	};
+	__u64	branch_sample_type; /* enum branch_sample_type */
 };
 
 /*
@@ -291,12 +323,14 @@
 	__s64	offset;			/* add to hardware event value */
 	__u64	time_enabled;		/* time event active */
 	__u64	time_running;		/* time event on cpu */
+	__u32	time_mult, time_shift;
+	__u64	time_offset;
 
 		/*
 		 * Hole for extension of the self monitor capabilities
 		 */
 
-	__u64	__reserved[123];	/* align to 1k */
+	__u64	__reserved[121];	/* align to 1k */
 
 	/*
 	 * Control data for the mmap() data buffer.
@@ -456,6 +490,8 @@
 	 *
 	 *	{ u32			size;
 	 *	  char                  data[size];}&& PERF_SAMPLE_RAW
+	 *
+	 *	{ u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
 	 * };
 	 */
 	PERF_RECORD_SAMPLE			= 9,
@@ -512,7 +548,7 @@
 #include <linux/ftrace.h>
 #include <linux/cpu.h>
 #include <linux/irq_work.h>
-#include <linux/jump_label.h>
+#include <linux/static_key.h>
 #include <linux/atomic.h>
 #include <asm/local.h>
 
@@ -528,12 +564,34 @@
 	void				*data;
 };
 
+/*
+ * single taken branch record layout:
+ *
+ *      from: source instruction (may not always be a branch insn)
+ *        to: branch target
+ *   mispred: branch target was mispredicted
+ * predicted: branch target was predicted
+ *
+ * support for mispred, predicted is optional. In case it
+ * is not supported mispred = predicted = 0.
+ */
 struct perf_branch_entry {
-	__u64				from;
-	__u64				to;
-	__u64				flags;
+	__u64	from;
+	__u64	to;
+	__u64	mispred:1,  /* target mispredicted */
+		predicted:1,/* target predicted */
+		reserved:62;
 };
 
+/*
+ * branch stack layout:
+ *  nr: number of taken branches stored in entries[]
+ *
+ * Note that nr can vary from sample to sample
+ * branches (to, from) are stored from most recent
+ * to least recent, i.e., entries[0] contains the most
+ * recent branch.
+ */
 struct perf_branch_stack {
 	__u64				nr;
 	struct perf_branch_entry	entries[0];
@@ -564,7 +622,9 @@
 			unsigned long	event_base;
 			int		idx;
 			int		last_cpu;
+
 			struct hw_perf_event_extra extra_reg;
+			struct hw_perf_event_extra branch_reg;
 		};
 		struct { /* software */
 			struct hrtimer	hrtimer;
@@ -616,6 +676,7 @@
 	struct list_head		entry;
 
 	struct device			*dev;
+	const struct attribute_group	**attr_groups;
 	char				*name;
 	int				type;
 
@@ -681,6 +742,17 @@
 	 * for each successful ->add() during the transaction.
 	 */
 	void (*cancel_txn)		(struct pmu *pmu); /* optional */
+
+	/*
+	 * Will return the value for perf_event_mmap_page::index for this event,
+	 * if no implementation is provided it will default to: event->hw.idx + 1.
+	 */
+	int (*event_idx)		(struct perf_event *event); /*optional */
+
+	/*
+	 * flush branch stack on context-switches (needed in cpu-wide mode)
+	 */
+	void (*flush_branch_stack)	(void);
 };
 
 /**
@@ -850,6 +922,9 @@
 #ifdef CONFIG_EVENT_TRACING
 	struct ftrace_event_call	*tp_event;
 	struct event_filter		*filter;
+#ifdef CONFIG_FUNCTION_TRACER
+	struct ftrace_ops               ftrace_ops;
+#endif
 #endif
 
 #ifdef CONFIG_CGROUP_PERF
@@ -911,7 +986,8 @@
 	u64				parent_gen;
 	u64				generation;
 	int				pin_count;
-	int				nr_cgroups; /* cgroup events present */
+	int				nr_cgroups;	 /* cgroup evts */
+	int				nr_branch_stack; /* branch_stack evt */
 	struct rcu_head			rcu_head;
 };
 
@@ -976,6 +1052,7 @@
 extern u64 perf_event_read_value(struct perf_event *event,
 				 u64 *enabled, u64 *running);
 
+
 struct perf_sample_data {
 	u64				type;
 
@@ -995,12 +1072,14 @@
 	u64				period;
 	struct perf_callchain_entry	*callchain;
 	struct perf_raw_record		*raw;
+	struct perf_branch_stack	*br_stack;
 };
 
 static inline void perf_sample_data_init(struct perf_sample_data *data, u64 addr)
 {
 	data->addr = addr;
 	data->raw  = NULL;
+	data->br_stack = NULL;
 }
 
 extern void perf_output_sample(struct perf_output_handle *handle,
@@ -1029,7 +1108,7 @@
 	return event->pmu->task_ctx_nr == perf_sw_context;
 }
 
-extern struct jump_label_key perf_swevent_enabled[PERF_COUNT_SW_MAX];
+extern struct static_key perf_swevent_enabled[PERF_COUNT_SW_MAX];
 
 extern void __perf_sw_event(u32, u64, struct pt_regs *, u64);
 
@@ -1057,7 +1136,7 @@
 {
 	struct pt_regs hot_regs;
 
-	if (static_branch(&perf_swevent_enabled[event_id])) {
+	if (static_key_false(&perf_swevent_enabled[event_id])) {
 		if (!regs) {
 			perf_fetch_caller_regs(&hot_regs);
 			regs = &hot_regs;
@@ -1066,12 +1145,12 @@
 	}
 }
 
-extern struct jump_label_key_deferred perf_sched_events;
+extern struct static_key_deferred perf_sched_events;
 
 static inline void perf_event_task_sched_in(struct task_struct *prev,
 					    struct task_struct *task)
 {
-	if (static_branch(&perf_sched_events.key))
+	if (static_key_false(&perf_sched_events.key))
 		__perf_event_task_sched_in(prev, task);
 }
 
@@ -1080,7 +1159,7 @@
 {
 	perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, NULL, 0);
 
-	if (static_branch(&perf_sched_events.key))
+	if (static_key_false(&perf_sched_events.key))
 		__perf_event_task_sched_out(prev, next);
 }
 
@@ -1139,6 +1218,11 @@
 # define perf_instruction_pointer(regs)	instruction_pointer(regs)
 #endif
 
+static inline bool has_branch_stack(struct perf_event *event)
+{
+	return event->attr.sample_type & PERF_SAMPLE_BRANCH_STACK;
+}
+
 extern int perf_output_begin(struct perf_output_handle *handle,
 			     struct perf_event *event, unsigned int size);
 extern void perf_output_end(struct perf_output_handle *handle);
diff --git a/include/linux/platform_data/dwc3-exynos.h b/include/linux/platform_data/dwc3-exynos.h
new file mode 100644
index 0000000..5eb7da9
--- /dev/null
+++ b/include/linux/platform_data/dwc3-exynos.h
@@ -0,0 +1,24 @@
+/**
+ * dwc3-exynos.h - Samsung EXYNOS DWC3 Specific Glue layer, header.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Author: Anton Tikhomirov <av.tikhomirov@samsung.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.
+ */
+
+#ifndef _DWC3_EXYNOS_H_
+#define _DWC3_EXYNOS_H_
+
+struct dwc3_exynos_data {
+	int phy_type;
+	int (*phy_init)(struct platform_device *pdev, int type);
+	int (*phy_exit)(struct platform_device *pdev, int type);
+};
+
+#endif /* _DWC3_EXYNOS_H_ */
diff --git a/include/linux/platform_data/efm32-uart.h b/include/linux/platform_data/efm32-uart.h
new file mode 100644
index 0000000..ed0e975
--- /dev/null
+++ b/include/linux/platform_data/efm32-uart.h
@@ -0,0 +1,18 @@
+/*
+ *
+ *
+ */
+#ifndef __LINUX_PLATFORM_DATA_EFM32_UART_H__
+#define __LINUX_PLATFORM_DATA_EFM32_UART_H__
+
+#include <linux/types.h>
+
+/**
+ * struct efm32_uart_pdata
+ * @location: pinmux location for the I/O pins (to be written to the ROUTE
+ * 	register)
+ */
+struct efm32_uart_pdata {
+	u8 location;
+};
+#endif /* ifndef __LINUX_PLATFORM_DATA_EFM32_UART_H__ */
diff --git a/include/linux/preempt.h b/include/linux/preempt.h
index 58969b2..5a710b9 100644
--- a/include/linux/preempt.h
+++ b/include/linux/preempt.h
@@ -48,12 +48,14 @@
 	barrier(); \
 } while (0)
 
-#define preempt_enable_no_resched() \
+#define sched_preempt_enable_no_resched() \
 do { \
 	barrier(); \
 	dec_preempt_count(); \
 } while (0)
 
+#define preempt_enable_no_resched()	sched_preempt_enable_no_resched()
+
 #define preempt_enable() \
 do { \
 	preempt_enable_no_resched(); \
@@ -92,6 +94,7 @@
 #else /* !CONFIG_PREEMPT_COUNT */
 
 #define preempt_disable()		do { } while (0)
+#define sched_preempt_enable_no_resched()	do { } while (0)
 #define preempt_enable_no_resched()	do { } while (0)
 #define preempt_enable()		do { } while (0)
 
diff --git a/include/linux/printk.h b/include/linux/printk.h
index f0e22f7..0525927 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -101,6 +101,11 @@
 int printk(const char *fmt, ...);
 
 /*
+ * Special printk facility for scheduler use only, _DO_NOT_USE_ !
+ */
+__printf(1, 2) __cold int printk_sched(const char *fmt, ...);
+
+/*
  * Please don't use printk_ratelimit(), because it shares ratelimiting state
  * with all other unrelated printk_ratelimit() callsites.  Instead use
  * printk_ratelimited() or plain old __ratelimit().
@@ -127,6 +132,11 @@
 {
 	return 0;
 }
+static inline __printf(1, 2) __cold
+int printk_sched(const char *s, ...)
+{
+	return 0;
+}
 static inline int printk_ratelimit(void)
 {
 	return 0;
@@ -180,13 +190,13 @@
 #endif
 
 /* If you are writing a driver, please use dev_dbg instead */
-#if defined(DEBUG)
-#define pr_debug(fmt, ...) \
-	printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
-#elif defined(CONFIG_DYNAMIC_DEBUG)
+#if defined(CONFIG_DYNAMIC_DEBUG)
 /* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */
 #define pr_debug(fmt, ...) \
 	dynamic_pr_debug(fmt, ##__VA_ARGS__)
+#elif defined(DEBUG)
+#define pr_debug(fmt, ...) \
+	printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
 #else
 #define pr_debug(fmt, ...) \
 	no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 81c04f4..9372174 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -190,6 +190,33 @@
 extern void rcu_irq_enter(void);
 extern void rcu_irq_exit(void);
 
+/**
+ * RCU_NONIDLE - Indicate idle-loop code that needs RCU readers
+ * @a: Code that RCU needs to pay attention to.
+ *
+ * RCU, RCU-bh, and RCU-sched read-side critical sections are forbidden
+ * in the inner idle loop, that is, between the rcu_idle_enter() and
+ * the rcu_idle_exit() -- RCU will happily ignore any such read-side
+ * critical sections.  However, things like powertop need tracepoints
+ * in the inner idle loop.
+ *
+ * This macro provides the way out:  RCU_NONIDLE(do_something_with_RCU())
+ * will tell RCU that it needs to pay attending, invoke its argument
+ * (in this example, a call to the do_something_with_RCU() function),
+ * and then tell RCU to go back to ignoring this CPU.  It is permissible
+ * to nest RCU_NONIDLE() wrappers, but the nesting level is currently
+ * quite limited.  If deeper nesting is required, it will be necessary
+ * to adjust DYNTICK_TASK_NESTING_VALUE accordingly.
+ *
+ * This macro may be used from process-level code only.
+ */
+#define RCU_NONIDLE(a) \
+	do { \
+		rcu_idle_exit(); \
+		do { a; } while (0); \
+		rcu_idle_enter(); \
+	} while (0)
+
 /*
  * Infrastructure to implement the synchronize_() primitives in
  * TREE_RCU and rcu_barrier_() primitives in TINY_RCU.
@@ -226,6 +253,15 @@
 }
 #endif	/* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
 
+#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU)
+bool rcu_lockdep_current_cpu_online(void);
+#else /* #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */
+static inline bool rcu_lockdep_current_cpu_online(void)
+{
+	return 1;
+}
+#endif /* #else #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */
+
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 
 #ifdef CONFIG_PROVE_RCU
@@ -239,13 +275,11 @@
 
 static inline void rcu_lock_acquire(struct lockdep_map *map)
 {
-	WARN_ON_ONCE(rcu_is_cpu_idle());
 	lock_acquire(map, 0, 0, 2, 1, NULL, _THIS_IP_);
 }
 
 static inline void rcu_lock_release(struct lockdep_map *map)
 {
-	WARN_ON_ONCE(rcu_is_cpu_idle());
 	lock_release(map, 1, _THIS_IP_);
 }
 
@@ -270,6 +304,9 @@
  * occur in the same context, for example, it is illegal to invoke
  * rcu_read_unlock() in process context if the matching rcu_read_lock()
  * was invoked from within an irq handler.
+ *
+ * Note that rcu_read_lock() is disallowed if the CPU is either idle or
+ * offline from an RCU perspective, so check for those as well.
  */
 static inline int rcu_read_lock_held(void)
 {
@@ -277,6 +314,8 @@
 		return 1;
 	if (rcu_is_cpu_idle())
 		return 0;
+	if (!rcu_lockdep_current_cpu_online())
+		return 0;
 	return lock_is_held(&rcu_lock_map);
 }
 
@@ -313,6 +352,9 @@
  * notice an extended quiescent state to other CPUs that started a grace
  * period. Otherwise we would delay any grace period as long as we run in
  * the idle task.
+ *
+ * Similarly, we avoid claiming an SRCU read lock held if the current
+ * CPU is offline.
  */
 #ifdef CONFIG_PREEMPT_COUNT
 static inline int rcu_read_lock_sched_held(void)
@@ -323,6 +365,8 @@
 		return 1;
 	if (rcu_is_cpu_idle())
 		return 0;
+	if (!rcu_lockdep_current_cpu_online())
+		return 0;
 	if (debug_locks)
 		lockdep_opinion = lock_is_held(&rcu_sched_lock_map);
 	return lockdep_opinion || preempt_count() != 0 || irqs_disabled();
@@ -381,8 +425,22 @@
 		}							\
 	} while (0)
 
+#if defined(CONFIG_PROVE_RCU) && !defined(CONFIG_PREEMPT_RCU)
+static inline void rcu_preempt_sleep_check(void)
+{
+	rcu_lockdep_assert(!lock_is_held(&rcu_lock_map),
+			   "Illegal context switch in RCU read-side "
+			   "critical section");
+}
+#else /* #ifdef CONFIG_PROVE_RCU */
+static inline void rcu_preempt_sleep_check(void)
+{
+}
+#endif /* #else #ifdef CONFIG_PROVE_RCU */
+
 #define rcu_sleep_check()						\
 	do {								\
+		rcu_preempt_sleep_check();				\
 		rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map),	\
 				   "Illegal context switch in RCU-bh"	\
 				   " read-side critical section");	\
@@ -470,6 +528,13 @@
  * NULL.  Although rcu_access_pointer() may also be used in cases where
  * update-side locks prevent the value of the pointer from changing, you
  * should instead use rcu_dereference_protected() for this use case.
+ *
+ * It is also permissible to use rcu_access_pointer() when read-side
+ * access to the pointer was removed at least one grace period ago, as
+ * is the case in the context of the RCU callback that is freeing up
+ * the data, or after a synchronize_rcu() returns.  This can be useful
+ * when tearing down multi-linked structures after a grace period
+ * has elapsed.
  */
 #define rcu_access_pointer(p) __rcu_access_pointer((p), __rcu)
 
@@ -659,6 +724,8 @@
 	__rcu_read_lock();
 	__acquire(RCU);
 	rcu_lock_acquire(&rcu_lock_map);
+	rcu_lockdep_assert(!rcu_is_cpu_idle(),
+			   "rcu_read_lock() used illegally while idle");
 }
 
 /*
@@ -678,6 +745,8 @@
  */
 static inline void rcu_read_unlock(void)
 {
+	rcu_lockdep_assert(!rcu_is_cpu_idle(),
+			   "rcu_read_unlock() used illegally while idle");
 	rcu_lock_release(&rcu_lock_map);
 	__release(RCU);
 	__rcu_read_unlock();
@@ -705,6 +774,8 @@
 	local_bh_disable();
 	__acquire(RCU_BH);
 	rcu_lock_acquire(&rcu_bh_lock_map);
+	rcu_lockdep_assert(!rcu_is_cpu_idle(),
+			   "rcu_read_lock_bh() used illegally while idle");
 }
 
 /*
@@ -714,6 +785,8 @@
  */
 static inline void rcu_read_unlock_bh(void)
 {
+	rcu_lockdep_assert(!rcu_is_cpu_idle(),
+			   "rcu_read_unlock_bh() used illegally while idle");
 	rcu_lock_release(&rcu_bh_lock_map);
 	__release(RCU_BH);
 	local_bh_enable();
@@ -737,6 +810,8 @@
 	preempt_disable();
 	__acquire(RCU_SCHED);
 	rcu_lock_acquire(&rcu_sched_lock_map);
+	rcu_lockdep_assert(!rcu_is_cpu_idle(),
+			   "rcu_read_lock_sched() used illegally while idle");
 }
 
 /* Used by lockdep and tracing: cannot be traced, cannot call lockdep. */
@@ -753,6 +828,8 @@
  */
 static inline void rcu_read_unlock_sched(void)
 {
+	rcu_lockdep_assert(!rcu_is_cpu_idle(),
+			   "rcu_read_unlock_sched() used illegally while idle");
 	rcu_lock_release(&rcu_sched_lock_map);
 	__release(RCU_SCHED);
 	preempt_enable();
@@ -841,7 +918,7 @@
 	/* See the kfree_rcu() header comment. */
 	BUILD_BUG_ON(!__is_kfree_rcu_offset(offset));
 
-	call_rcu(head, (rcu_callback)offset);
+	kfree_call_rcu(head, (rcu_callback)offset);
 }
 
 /**
diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h
index 00b7a5e..e93df77 100644
--- a/include/linux/rcutiny.h
+++ b/include/linux/rcutiny.h
@@ -27,13 +27,9 @@
 
 #include <linux/cache.h>
 
-#ifdef CONFIG_RCU_BOOST
 static inline void rcu_init(void)
 {
 }
-#else /* #ifdef CONFIG_RCU_BOOST */
-void rcu_init(void);
-#endif /* #else #ifdef CONFIG_RCU_BOOST */
 
 static inline void rcu_barrier_bh(void)
 {
@@ -83,6 +79,12 @@
 	synchronize_sched();
 }
 
+static inline void kfree_call_rcu(struct rcu_head *head,
+				  void (*func)(struct rcu_head *rcu))
+{
+	call_rcu(head, func);
+}
+
 #ifdef CONFIG_TINY_RCU
 
 static inline void rcu_preempt_note_context_switch(void)
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
index 6745846..e8ee5dd 100644
--- a/include/linux/rcutree.h
+++ b/include/linux/rcutree.h
@@ -61,6 +61,24 @@
 extern void synchronize_sched_expedited(void);
 extern void synchronize_rcu_expedited(void);
 
+void kfree_call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu));
+
+/**
+ * synchronize_rcu_bh_expedited - Brute-force RCU-bh grace period
+ *
+ * Wait for an RCU-bh grace period to elapse, but use a "big hammer"
+ * approach to force the grace period to end quickly.  This consumes
+ * significant time on all CPUs and is unfriendly to real-time workloads,
+ * so is thus not recommended for any sort of common-case code.  In fact,
+ * if you are using synchronize_rcu_bh_expedited() in a loop, please
+ * restructure your code to batch your updates, and then use a single
+ * synchronize_rcu_bh() instead.
+ *
+ * Note that it is illegal to call this function while holding any lock
+ * that is acquired by a CPU-hotplug notifier.  And yes, it is also illegal
+ * to call this function from a CPU-hotplug notifier.  Failing to observe
+ * these restriction will result in deadlock.
+ */
 static inline void synchronize_rcu_bh_expedited(void)
 {
 	synchronize_sched_expedited();
@@ -83,6 +101,7 @@
 /* A context switch is a grace period for RCU-sched and RCU-bh. */
 static inline int rcu_blocking_is_gp(void)
 {
+	might_sleep();  /* Check for RCU read-side critical section. */
 	return num_online_cpus() == 1;
 }
 
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 0657368..e074e1e 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -361,6 +361,7 @@
 extern signed long schedule_timeout_killable(signed long timeout);
 extern signed long schedule_timeout_uninterruptible(signed long timeout);
 asmlinkage void schedule(void);
+extern void schedule_preempt_disabled(void);
 extern int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner);
 
 struct nsproxy;
@@ -905,6 +906,7 @@
 	 * single CPU.
 	 */
 	unsigned int power, power_orig;
+	unsigned long next_update;
 	/*
 	 * Number of busy cpus in this group.
 	 */
@@ -1052,6 +1054,8 @@
 unsigned long default_scale_freq_power(struct sched_domain *sd, int cpu);
 unsigned long default_scale_smt_power(struct sched_domain *sd, int cpu);
 
+bool cpus_share_cache(int this_cpu, int that_cpu);
+
 #else /* CONFIG_SMP */
 
 struct sched_domain_attr;
@@ -1061,6 +1065,12 @@
 			struct sched_domain_attr *dattr_new)
 {
 }
+
+static inline bool cpus_share_cache(int this_cpu, int that_cpu)
+{
+	return true;
+}
+
 #endif	/* !CONFIG_SMP */
 
 
@@ -1225,6 +1235,12 @@
 #endif
 };
 
+/*
+ * default timeslice is 100 msecs (used only for SCHED_RR tasks).
+ * Timeslices get refilled after they expire.
+ */
+#define RR_TIMESLICE		(100 * HZ / 1000)
+
 struct rcu_node;
 
 enum perf_event_task_context {
@@ -1319,6 +1335,11 @@
 	unsigned sched_reset_on_fork:1;
 	unsigned sched_contributes_to_load:1;
 
+#ifdef CONFIG_GENERIC_HARDIRQS
+	/* IRQ handler threads */
+	unsigned irq_thread:1;
+#endif
+
 	pid_t pid;
 	pid_t tgid;
 
@@ -1427,11 +1448,6 @@
  * mempolicy */
 	spinlock_t alloc_lock;
 
-#ifdef CONFIG_GENERIC_HARDIRQS
-	/* IRQ handler threads */
-	struct irqaction *irqaction;
-#endif
-
 	/* Protection of the PI data structures: */
 	raw_spinlock_t pi_lock;
 
@@ -1863,8 +1879,7 @@
 #ifdef CONFIG_PREEMPT_RCU
 
 #define RCU_READ_UNLOCK_BLOCKED (1 << 0) /* blocked while in RCU read-side. */
-#define RCU_READ_UNLOCK_BOOSTED (1 << 1) /* boosted while in RCU read-side. */
-#define RCU_READ_UNLOCK_NEED_QS (1 << 2) /* RCU core needs CPU response. */
+#define RCU_READ_UNLOCK_NEED_QS (1 << 1) /* RCU core needs CPU response. */
 
 static inline void rcu_copy_process(struct task_struct *p)
 {
@@ -2048,7 +2063,7 @@
 extern void sched_autogroup_exit(struct signal_struct *sig);
 #ifdef CONFIG_PROC_FS
 extern void proc_sched_autogroup_show_task(struct task_struct *p, struct seq_file *m);
-extern int proc_sched_autogroup_set_nice(struct task_struct *p, int *nice);
+extern int proc_sched_autogroup_set_nice(struct task_struct *p, int nice);
 #endif
 #else
 static inline void sched_autogroup_create_attach(struct task_struct *p) { }
@@ -2065,12 +2080,20 @@
 extern int rt_mutex_getprio(struct task_struct *p);
 extern void rt_mutex_setprio(struct task_struct *p, int prio);
 extern void rt_mutex_adjust_pi(struct task_struct *p);
+static inline bool tsk_is_pi_blocked(struct task_struct *tsk)
+{
+	return tsk->pi_blocked_on != NULL;
+}
 #else
 static inline int rt_mutex_getprio(struct task_struct *p)
 {
 	return p->normal_prio;
 }
 # define rt_mutex_adjust_pi(p)		do { } while (0)
+static inline bool tsk_is_pi_blocked(struct task_struct *tsk)
+{
+	return false;
+}
 #endif
 
 extern bool yield_to(struct task_struct *p, bool preempt);
@@ -2389,12 +2412,15 @@
 extern struct sighand_struct *__lock_task_sighand(struct task_struct *tsk,
 							unsigned long *flags);
 
-#define lock_task_sighand(tsk, flags)					\
-({	struct sighand_struct *__ss;					\
-	__cond_lock(&(tsk)->sighand->siglock,				\
-		    (__ss = __lock_task_sighand(tsk, flags)));		\
-	__ss;								\
-})									\
+static inline struct sighand_struct *lock_task_sighand(struct task_struct *tsk,
+						       unsigned long *flags)
+{
+	struct sighand_struct *ret;
+
+	ret = __lock_task_sighand(tsk, flags);
+	(void)__cond_lock(&tsk->sighand->siglock, ret);
+	return ret;
+}
 
 static inline void unlock_task_sighand(struct task_struct *tsk,
 						unsigned long *flags)
diff --git a/include/linux/serial.h b/include/linux/serial.h
index 3d86517..441980e 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -152,8 +152,8 @@
 #define ASYNC_AUTOPROBE		(1U << ASYNCB_AUTOPROBE)
 
 #define ASYNC_FLAGS		((1U << (ASYNCB_LAST_USER + 1)) - 1)
-#define ASYNC_USR_MASK		(ASYNC_SPD_HI|ASYNC_SPD_VHI| \
-		ASYNC_CALLOUT_NOHUP|ASYNC_SPD_SHI|ASYNC_LOW_LATENCY)
+#define ASYNC_USR_MASK		(ASYNC_SPD_MASK|ASYNC_CALLOUT_NOHUP| \
+		ASYNC_LOW_LATENCY)
 #define ASYNC_SPD_CUST		(ASYNC_SPD_HI|ASYNC_SPD_VHI)
 #define ASYNC_SPD_WARP		(ASYNC_SPD_HI|ASYNC_SPD_SHI)
 #define ASYNC_SPD_MASK		(ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI)
diff --git a/include/linux/serialP.h b/include/linux/serialP.h
deleted file mode 100644
index e811a61..0000000
--- a/include/linux/serialP.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Private header file for the (dumb) serial driver
- *
- * Copyright (C) 1997 by Theodore Ts'o.
- * 
- * Redistribution of this file is permitted under the terms of the GNU 
- * Public License (GPL)
- */
-
-#ifndef _LINUX_SERIALP_H
-#define _LINUX_SERIALP_H
-
-/*
- * This is our internal structure for each serial port's state.
- * 
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-#include <linux/termios.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-#include <linux/circ_buf.h>
-#include <linux/wait.h>
-
-struct serial_state {
-	int	magic;
-	int	baud_base;
-	unsigned long	port;
-	int	irq;
-	int	flags;
-	int	hub6;
-	int	type;
-	int	line;
-	int	revision;	/* Chip revision (950) */
-	int	xmit_fifo_size;
-	int	custom_divisor;
-	int	count;
-	u8	*iomem_base;
-	u16	iomem_reg_shift;
-	unsigned short	close_delay;
-	unsigned short	closing_wait; /* time to wait before closing */
-	struct async_icount	icount;	
-	int	io_type;
-	struct async_struct *info;
-	struct pci_dev	*dev;
-};
-
-struct async_struct {
-	int			magic;
-	unsigned long		port;
-	int			hub6;
-	int			flags;
-	int			xmit_fifo_size;
-	struct serial_state	*state;
-	struct tty_struct 	*tty;
-	int			read_status_mask;
-	int			ignore_status_mask;
-	int			timeout;
-	int			quot;
-	int			x_char;	/* xon/xoff character */
-	int			close_delay;
-	unsigned short		closing_wait;
-	unsigned short		closing_wait2; /* obsolete */
-	int			IER; 	/* Interrupt Enable Register */
-	int			MCR; 	/* Modem control register */
-	int			LCR; 	/* Line control register */
-	int			ACR;	 /* 16950 Additional Control Reg. */
-	unsigned long		event;
-	unsigned long		last_active;
-	int			line;
-	int			blocked_open; /* # of blocked opens */
- 	struct circ_buf		xmit;
- 	spinlock_t		xmit_lock;
-	u8			*iomem_base;
-	u16			iomem_reg_shift;
-	int			io_type;
-	struct work_struct			work;
-	struct tasklet_struct	tlet;
-#ifdef DECLARE_WAITQUEUE
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
-	wait_queue_head_t	delta_msr_wait;
-#else	
-	struct wait_queue	*open_wait;
-	struct wait_queue	*close_wait;
-	struct wait_queue	*delta_msr_wait;
-#endif	
-	struct async_struct	*next_port; /* For the linked list */
-	struct async_struct	*prev_port;
-};
-
-#define CONFIGURED_SERIAL_PORT(info) ((info)->port || ((info)->iomem_base))
-
-#define SERIAL_MAGIC 0x5301
-#define SSTATE_MAGIC 0x5302
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP	0
-
-/*
- * Multiport serial configuration structure --- internal structure
- */
-struct rs_multiport_struct {
-	int		port1;
-	unsigned char	mask1, match1;
-	int		port2;
-	unsigned char	mask2, match2;
-	int		port3;
-	unsigned char	mask3, match3;
-	int		port4;
-	unsigned char	mask4, match4;
-	int		port_monitor;
-};
-
-#if defined(__alpha__) && !defined(CONFIG_PCI)
-/*
- * Digital did something really horribly wrong with the OUT1 and OUT2
- * lines on at least some ALPHA's.  The failure mode is that if either
- * is cleared, the machine locks up with endless interrupts.
- *
- * This is still used by arch/mips/au1000/common/serial.c for some weird
- * reason (mips != alpha!)
- */
-#define ALPHA_KLUDGE_MCR  (UART_MCR_OUT2 | UART_MCR_OUT1)
-#elif defined(CONFIG_SBC8560)
-/*
- * WindRiver did something similarly broken on their SBC8560 board. The
- * UART tristates its IRQ output while OUT2 is clear, but they pulled
- * the interrupt line _up_ instead of down, so if we register the IRQ
- * while the UART is in that state, we die in an IRQ storm. */
-#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2)
-#else
-#define ALPHA_KLUDGE_MCR 0
-#endif
-
-#endif /* _LINUX_SERIAL_H */
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index c91ace7..f51bf2e 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -210,6 +210,8 @@
 /* Atheros AR933X SoC */
 #define PORT_AR933X	99
 
+/* Energy Micro efm32 SoC */
+#define PORT_EFMUART   100
 
 #ifdef __KERNEL__
 
@@ -381,6 +383,16 @@
 	void			*private_data;		/* generic platform data pointer */
 };
 
+static inline int serial_port_in(struct uart_port *up, int offset)
+{
+	return up->serial_in(up, offset);
+}
+
+static inline void serial_port_out(struct uart_port *up, int offset, int value)
+{
+	up->serial_out(up, offset, value);
+}
+
 /*
  * This is the state information which is persistent across opens.
  */
diff --git a/include/linux/srcu.h b/include/linux/srcu.h
index e1b0059..d3d5fa5 100644
--- a/include/linux/srcu.h
+++ b/include/linux/srcu.h
@@ -99,15 +99,18 @@
  * power mode. This way we can notice an extended quiescent state to
  * other CPUs that started a grace period. Otherwise we would delay any
  * grace period as long as we run in the idle task.
+ *
+ * Similarly, we avoid claiming an SRCU read lock held if the current
+ * CPU is offline.
  */
 static inline int srcu_read_lock_held(struct srcu_struct *sp)
 {
-	if (rcu_is_cpu_idle())
-		return 0;
-
 	if (!debug_lockdep_rcu_enabled())
 		return 1;
-
+	if (rcu_is_cpu_idle())
+		return 0;
+	if (!rcu_lockdep_current_cpu_online())
+		return 0;
 	return lock_is_held(&sp->dep_map);
 }
 
@@ -169,6 +172,8 @@
 	int retval = __srcu_read_lock(sp);
 
 	rcu_lock_acquire(&(sp)->dep_map);
+	rcu_lockdep_assert(!rcu_is_cpu_idle(),
+			   "srcu_read_lock() used illegally while idle");
 	return retval;
 }
 
@@ -182,6 +187,8 @@
 static inline void srcu_read_unlock(struct srcu_struct *sp, int idx)
 	__releases(sp)
 {
+	rcu_lockdep_assert(!rcu_is_cpu_idle(),
+			   "srcu_read_unlock() used illegally while idle");
 	rcu_lock_release(&(sp)->dep_map);
 	__srcu_read_unlock(sp, idx);
 }
diff --git a/include/linux/static_key.h b/include/linux/static_key.h
new file mode 100644
index 0000000..27bd3f8
--- /dev/null
+++ b/include/linux/static_key.h
@@ -0,0 +1 @@
+#include <linux/jump_label.h>
diff --git a/drivers/tty/serial/suncore.h b/include/linux/sunserialcore.h
similarity index 97%
rename from drivers/tty/serial/suncore.h
rename to include/linux/sunserialcore.h
index db20579..68e7430 100644
--- a/drivers/tty/serial/suncore.h
+++ b/include/linux/sunserialcore.h
@@ -1,4 +1,4 @@
-/* suncore.h
+/* sunserialcore.h
  *
  * Generic SUN serial/kbd/ms layer.  Based entirely
  * upon drivers/sbus/char/sunserial.h which is:
diff --git a/include/linux/sys_soc.h b/include/linux/sys_soc.h
new file mode 100644
index 0000000..2739ccb
--- /dev/null
+++ b/include/linux/sys_soc.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ * Author: Lee Jones <lee.jones@linaro.org> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+#ifndef __SOC_BUS_H
+#define __SOC_BUS_H
+
+#include <linux/device.h>
+
+struct soc_device_attribute {
+	const char *machine;
+	const char *family;
+	const char *revision;
+	const char *soc_id;
+};
+
+/**
+ * soc_device_register - register SoC as a device
+ * @soc_plat_dev_attr: Attributes passed from platform to be attributed to a SoC
+ */
+struct soc_device *soc_device_register(
+	struct soc_device_attribute *soc_plat_dev_attr);
+
+/**
+ * soc_device_unregister - unregister SoC device
+ * @dev: SoC device to be unregistered
+ */
+void soc_device_unregister(struct soc_device *soc_dev);
+
+/**
+ * soc_device_to_device - helper function to fetch struct device
+ * @soc: Previously registered SoC device container
+ */
+struct device *soc_device_to_device(struct soc_device *soc);
+
+#endif /* __SOC_BUS_H */
diff --git a/include/linux/timex.h b/include/linux/timex.h
index aa60fe7..b75e186 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -234,23 +234,9 @@
 extern unsigned long tick_usec;		/* USER_HZ period (usec) */
 extern unsigned long tick_nsec;		/* ACTHZ          period (nsec) */
 
-/*
- * phase-lock loop variables
- */
-extern int time_status;		/* clock synchronization status bits */
-
 extern void ntp_init(void);
 extern void ntp_clear(void);
 
-/**
- * ntp_synced - Returns 1 if the NTP status is not UNSYNC
- *
- */
-static inline int ntp_synced(void)
-{
-	return !(time_status & STA_UNSYNC);
-}
-
 /* Required to safely shift negative values */
 #define shift_right(x, s) ({	\
 	__typeof__(x) __x = (x);	\
@@ -264,10 +250,9 @@
 #define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ)
 
 /* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */
-extern u64 tick_length;
+extern u64 ntp_tick_length(void);
 
 extern void second_overflow(void);
-extern void update_ntp_one_tick(void);
 extern int do_adjtimex(struct timex *);
 extern void hardpps(const struct timespec *, const struct timespec *);
 
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index df0a779..bd96ecd 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -17,7 +17,7 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/rcupdate.h>
-#include <linux/jump_label.h>
+#include <linux/static_key.h>
 
 struct module;
 struct tracepoint;
@@ -29,7 +29,7 @@
 
 struct tracepoint {
 	const char *name;		/* Tracepoint name */
-	struct jump_label_key key;
+	struct static_key key;
 	void (*regfunc)(void);
 	void (*unregfunc)(void);
 	struct tracepoint_func __rcu *funcs;
@@ -114,7 +114,7 @@
  * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just
  * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto".
  */
-#define __DO_TRACE(tp, proto, args, cond)				\
+#define __DO_TRACE(tp, proto, args, cond, prercu, postrcu)		\
 	do {								\
 		struct tracepoint_func *it_func_ptr;			\
 		void *it_func;						\
@@ -122,6 +122,7 @@
 									\
 		if (!(cond))						\
 			return;						\
+		prercu;							\
 		rcu_read_lock_sched_notrace();				\
 		it_func_ptr = rcu_dereference_sched((tp)->funcs);	\
 		if (it_func_ptr) {					\
@@ -132,6 +133,7 @@
 			} while ((++it_func_ptr)->func);		\
 		}							\
 		rcu_read_unlock_sched_notrace();			\
+		postrcu;						\
 	} while (0)
 
 /*
@@ -139,15 +141,25 @@
  * not add unwanted padding between the beginning of the section and the
  * structure. Force alignment to the same alignment as the section start.
  */
-#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args)	\
+#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \
 	extern struct tracepoint __tracepoint_##name;			\
 	static inline void trace_##name(proto)				\
 	{								\
+		if (static_key_false(&__tracepoint_##name.key))		\
+			__DO_TRACE(&__tracepoint_##name,		\
+				TP_PROTO(data_proto),			\
+				TP_ARGS(data_args),			\
+				TP_CONDITION(cond),,);			\
+	}								\
+	static inline void trace_##name##_rcuidle(proto)		\
+	{								\
 		if (static_branch(&__tracepoint_##name.key))		\
 			__DO_TRACE(&__tracepoint_##name,		\
 				TP_PROTO(data_proto),			\
 				TP_ARGS(data_args),			\
-				TP_CONDITION(cond));			\
+				TP_CONDITION(cond),			\
+				rcu_idle_exit(),			\
+				rcu_idle_enter());			\
 	}								\
 	static inline int						\
 	register_trace_##name(void (*probe)(data_proto), void *data)	\
@@ -176,7 +188,7 @@
 	__attribute__((section("__tracepoints_strings"))) = #name;	 \
 	struct tracepoint __tracepoint_##name				 \
 	__attribute__((section("__tracepoints"))) =			 \
-		{ __tpstrtab_##name, JUMP_LABEL_INIT, reg, unreg, NULL };\
+		{ __tpstrtab_##name, STATIC_KEY_INIT_FALSE, reg, unreg, NULL };\
 	static struct tracepoint * const __tracepoint_ptr_##name __used	 \
 	__attribute__((section("__tracepoints_ptrs"))) =		 \
 		&__tracepoint_##name;
@@ -190,9 +202,11 @@
 	EXPORT_SYMBOL(__tracepoint_##name)
 
 #else /* !CONFIG_TRACEPOINTS */
-#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args)	\
+#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \
 	static inline void trace_##name(proto)				\
 	{ }								\
+	static inline void trace_##name##_rcuidle(proto)		\
+	{ }								\
 	static inline int						\
 	register_trace_##name(void (*probe)(data_proto),		\
 			      void *data)				\
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 5dbb3cb..a91ff40 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -52,6 +52,7 @@
  * hardcoded at present.)
  */
 #define NR_UNIX98_PTY_DEFAULT	4096      /* Default maximum for Unix98 ptys */
+#define NR_UNIX98_PTY_RESERVE	1024	  /* Default reserve for main devpts */
 #define NR_UNIX98_PTY_MAX	(1 << MINORBITS) /* Absolute limit */
 
 /*
@@ -480,10 +481,11 @@
 extern void initialize_tty_struct(struct tty_struct *tty,
 		struct tty_driver *driver, int idx);
 extern void deinitialize_tty_struct(struct tty_struct *tty);
-extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
-								int first_ok);
+extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx);
 extern int tty_release(struct inode *inode, struct file *filp);
 extern int tty_init_termios(struct tty_struct *tty);
+extern int tty_standard_install(struct tty_driver *driver,
+		struct tty_struct *tty);
 
 extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty);
 extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty);
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 5cf6850..6e6dbb7 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -50,6 +50,8 @@
  *	Note that tty_shutdown() is not called if ops->shutdown is defined.
  *	This means one is responsible to take care of calling ops->remove (e.g.
  *	via tty_driver_remove_tty) and releasing tty->termios.
+ *	Note that this hook may be called from *all* the contexts where one
+ *	uses tty refcounting (e.g. tty_port_tty_get).
  *
  *
  * void (*cleanup)(struct tty_struct * tty);
@@ -234,6 +236,7 @@
  *	if provided (otherwise EINVAL will be returned).
  */
 
+#include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/list.h>
 #include <linux/cdev.h>
@@ -298,7 +301,6 @@
 	int	name_base;	/* offset of printed name */
 	int	major;		/* major device number */
 	int	minor_start;	/* start of minor device number */
-	int	minor_num;	/* number of *possible* devices */
 	int	num;		/* number of devices allocated */
 	short	type;		/* type of tty driver */
 	short	subtype;	/* subtype of tty driver */
@@ -324,7 +326,7 @@
 
 extern struct list_head tty_drivers;
 
-extern struct tty_driver *alloc_tty_driver(int lines);
+extern struct tty_driver *__alloc_tty_driver(int lines, struct module *owner);
 extern void put_tty_driver(struct tty_driver *driver);
 extern void tty_set_operations(struct tty_driver *driver,
 			const struct tty_operations *op);
@@ -332,6 +334,8 @@
 
 extern void tty_driver_kref_put(struct tty_driver *driver);
 
+#define alloc_tty_driver(lines) __alloc_tty_driver(lines, THIS_MODULE)
+
 static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
 {
 	kref_get(&d->kref);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 69d8457..73b68d1 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -376,6 +376,12 @@
 
 struct usb_tt;
 
+enum usb_device_removable {
+	USB_DEVICE_REMOVABLE_UNKNOWN = 0,
+	USB_DEVICE_REMOVABLE,
+	USB_DEVICE_FIXED,
+};
+
 /**
  * struct usb_device - kernel's representation of a USB device
  * @devnum: device number; address on a USB bus
@@ -432,6 +438,7 @@
  * @wusb_dev: if this is a Wireless USB device, link to the WUSB
  *	specific data for the device.
  * @slot_id: Slot ID assigned by xHCI
+ * @removable: Device can be physically removed from this port
  *
  * Notes:
  * Usbcore drivers should not set usbdev->state directly.  Instead use
@@ -494,7 +501,7 @@
 #endif
 
 	int maxchild;
-	struct usb_device *children[USB_MAXCHILDREN];
+	struct usb_device **children;
 
 	u32 quirks;
 	atomic_t urbnum;
@@ -509,6 +516,7 @@
 #endif
 	struct wusb_dev *wusb_dev;
 	int slot_id;
+	enum usb_device_removable removable;
 };
 #define	to_usb_device(d) container_of(d, struct usb_device, dev)
 
diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h
index 964cb60..ed13053 100644
--- a/include/linux/usb/audio-v2.h
+++ b/include/linux/usb/audio-v2.h
@@ -43,6 +43,27 @@
 	return (bmControls >> (control * 2)) & 0x2;
 }
 
+/* 4.7.2 Class-Specific AC Interface Descriptor */
+struct uac2_ac_header_descriptor {
+	__u8  bLength;			/* 9 */
+	__u8  bDescriptorType;		/* USB_DT_CS_INTERFACE */
+	__u8  bDescriptorSubtype;	/* UAC_MS_HEADER */
+	__le16 bcdADC;			/* 0x0200 */
+	__u8  bCategory;
+	__le16 wTotalLength;		/* includes Unit and Terminal desc. */
+	__u8  bmControls;
+} __packed;
+
+/* 2.3.1.6 Type I Format Type Descriptor (Frmts20 final.pdf)*/
+struct uac2_format_type_i_descriptor {
+	__u8  bLength;			/* in bytes: 6 */
+	__u8  bDescriptorType;		/* USB_DT_CS_INTERFACE */
+	__u8  bDescriptorSubtype;	/* FORMAT_TYPE */
+	__u8  bFormatType;		/* FORMAT_TYPE_1 */
+	__u8  bSubslotSize;		/* {1,2,3,4} */
+	__u8  bBitResolution;
+} __packed;
+
 /* 4.7.2.1 Clock Source Descriptor */
 
 struct uac_clock_source_descriptor {
diff --git a/include/linux/usb/cdc-wdm.h b/include/linux/usb/cdc-wdm.h
new file mode 100644
index 0000000..719c332
--- /dev/null
+++ b/include/linux/usb/cdc-wdm.h
@@ -0,0 +1,19 @@
+/*
+ * USB CDC Device Management subdriver
+ *
+ * Copyright (c) 2012  Bjørn Mork <bjorn@mork.no>
+ *
+ * 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_CDC_WDM_H
+#define __LINUX_USB_CDC_WDM_H
+
+extern struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
+					struct usb_endpoint_descriptor *ep,
+					int bufsize,
+					int (*manage_power)(struct usb_interface *, int));
+
+#endif /* __LINUX_USB_CDC_WDM_H */
diff --git a/include/linux/usb/ch11.h b/include/linux/usb/ch11.h
index 0b83acd..f1d26b6 100644
--- a/include/linux/usb/ch11.h
+++ b/include/linux/usb/ch11.h
@@ -76,6 +76,11 @@
 #define USB_PORT_FEAT_C_BH_PORT_RESET		29
 #define USB_PORT_FEAT_FORCE_LINKPM_ACCEPT	30
 
+/* USB 3.0 hub remote wake mask bits, see table 10-14 */
+#define USB_PORT_FEAT_REMOTE_WAKE_CONNECT	(1 << 8)
+#define USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT	(1 << 9)
+#define USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT	(1 << 10)
+
 /*
  * Hub Status and Hub Change results
  * See USB 2.0 spec Table 11-19 and Table 11-20
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 3b6f628..af21f31 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -789,6 +789,11 @@
 	__u8  bDevCapabilityType;
 	__le32 bmAttributes;
 #define USB_LPM_SUPPORT			(1 << 1)	/* supports LPM */
+#define USB_BESL_SUPPORT		(1 << 2)	/* supports BESL */
+#define USB_BESL_BASELINE_VALID		(1 << 3)	/* Baseline BESL valid*/
+#define USB_BESL_DEEP_VALID		(1 << 4)	/* Deep BESL valid */
+#define USB_GET_BESL_BASELINE(p)	(((p) & (0xf << 8)) >> 8)
+#define USB_GET_BESL_DEEP(p)		(((p) & (0xf << 12)) >> 12)
 } __attribute__((packed));
 
 #define USB_DT_USB_EXT_CAP_SIZE	7
diff --git a/include/linux/usb/ehci_pdriver.h b/include/linux/usb/ehci_pdriver.h
new file mode 100644
index 0000000..1894f42
--- /dev/null
+++ b/include/linux/usb/ehci_pdriver.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * 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 __USB_CORE_EHCI_PDRIVER_H
+#define __USB_CORE_EHCI_PDRIVER_H
+
+/**
+ * struct usb_ehci_pdata - platform_data for generic ehci driver
+ *
+ * @caps_offset:	offset of the EHCI Capability Registers to the start of
+ *			the io memory region provided to the driver.
+ * @has_tt:		set to 1 if TT is integrated in root hub.
+ * @port_power_on:	set to 1 if the controller needs a power up after
+ *			initialization.
+ * @port_power_off:	set to 1 if the controller needs to be powered down
+ *			after initialization.
+ *
+ * These are general configuration options for the EHCI controller. All of
+ * these options are activating more or less workarounds for some hardware.
+ */
+struct usb_ehci_pdata {
+	int		caps_offset;
+	unsigned	has_tt:1;
+	unsigned	has_synopsys_hc_bug:1;
+	unsigned	big_endian_desc:1;
+	unsigned	big_endian_mmio:1;
+	unsigned	port_power_on:1;
+	unsigned	port_power_off:1;
+};
+
+#endif /* __USB_CORE_EHCI_PDRIVER_H */
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index da653b5..9517466 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -950,6 +950,16 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* utility to simplify map/unmap of usb_requests to/from DMA */
+
+extern int usb_gadget_map_request(struct usb_gadget *gadget,
+		struct usb_request *req, int is_in);
+
+extern void usb_gadget_unmap_request(struct usb_gadget *gadget,
+		struct usb_request *req, int is_in);
+
+/*-------------------------------------------------------------------------*/
+
 /* utility wrapping a simple endpoint selection policy */
 
 extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *,
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index b2f62f3..5de4157 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -127,7 +127,7 @@
 	unsigned		authorized_default:1;
 	unsigned		has_tt:1;	/* Integrated TT in root hub */
 
-	int			irq;		/* irq allocated */
+	unsigned int		irq;		/* irq allocated */
 	void __iomem		*regs;		/* device memory/io */
 	u64			rsrc_start;	/* memory/io resource start */
 	u64			rsrc_len;	/* memory/io resource length */
@@ -412,6 +412,8 @@
 
 extern void usb_hc_died(struct usb_hcd *hcd);
 extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
+extern void usb_wakeup_notification(struct usb_device *hdev,
+		unsigned int portnum);
 
 /* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */
 #define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
diff --git a/include/linux/usb/intel_mid_otg.h b/include/linux/usb/intel_mid_otg.h
index a0ccf79..756cf55 100644
--- a/include/linux/usb/intel_mid_otg.h
+++ b/include/linux/usb/intel_mid_otg.h
@@ -104,11 +104,11 @@
 /*
  * the Intel MID (Langwell/Penwell) otg transceiver driver needs to interact
  * with device and host drivers to implement the USB OTG related feature. More
- * function members are added based on otg_transceiver data structure for this
+ * function members are added based on usb_phy data structure for this
  * purpose.
  */
 struct intel_mid_otg_xceiv {
-	struct otg_transceiver	otg;
+	struct usb_phy		otg;
 	struct otg_hsm		hsm;
 
 	/* base address */
@@ -147,7 +147,7 @@
 
 };
 static inline
-struct intel_mid_otg_xceiv *otg_to_mid_xceiv(struct otg_transceiver *otg)
+struct intel_mid_otg_xceiv *otg_to_mid_xceiv(struct usb_phy *otg)
 {
 	return container_of(otg, struct intel_mid_otg_xceiv, otg);
 }
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 00311fe..22a396c 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -160,7 +160,7 @@
  *               detection process.
  */
 struct msm_otg {
-	struct otg_transceiver otg;
+	struct usb_phy phy;
 	struct msm_otg_platform_data *pdata;
 	int irq;
 	struct clk *clk;
diff --git a/include/linux/usb/ohci_pdriver.h b/include/linux/usb/ohci_pdriver.h
new file mode 100644
index 0000000..2808f2a
--- /dev/null
+++ b/include/linux/usb/ohci_pdriver.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * 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 __USB_CORE_OHCI_PDRIVER_H
+#define __USB_CORE_OHCI_PDRIVER_H
+
+/**
+ * struct usb_ohci_pdata - platform_data for generic ohci driver
+ *
+ * @big_endian_desc:	BE descriptors
+ * @big_endian_mmio:	BE registers
+ * @no_big_frame_no:	no big endian frame_no shift
+ *
+ * These are general configuration options for the OHCI controller. All of
+ * these options are activating more or less workarounds for some hardware.
+ */
+struct usb_ohci_pdata {
+	unsigned	big_endian_desc:1;
+	unsigned	big_endian_mmio:1;
+	unsigned	no_big_frame_no:1;
+};
+
+#endif /* __USB_CORE_OHCI_PDRIVER_H */
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index d87f44f..f67810f 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -35,7 +35,7 @@
 	OTG_STATE_A_VBUS_ERR,
 };
 
-enum usb_xceiv_events {
+enum usb_phy_events {
 	USB_EVENT_NONE,         /* no events or cable disconnected */
 	USB_EVENT_VBUS,         /* vbus valid event */
 	USB_EVENT_ID,           /* id was grounded */
@@ -43,14 +43,39 @@
 	USB_EVENT_ENUMERATED,   /* gadget driver enumerated */
 };
 
-struct otg_transceiver;
+struct usb_phy;
 
 /* for transceivers connected thru an ULPI interface, the user must
  * provide access ops
  */
-struct otg_io_access_ops {
-	int (*read)(struct otg_transceiver *otg, u32 reg);
-	int (*write)(struct otg_transceiver *otg, u32 val, u32 reg);
+struct usb_phy_io_ops {
+	int (*read)(struct usb_phy *x, u32 reg);
+	int (*write)(struct usb_phy *x, u32 val, u32 reg);
+};
+
+struct usb_otg {
+	u8			default_a;
+
+	struct usb_phy		*phy;
+	struct usb_bus		*host;
+	struct usb_gadget	*gadget;
+
+	/* bind/unbind the host controller */
+	int	(*set_host)(struct usb_otg *otg, struct usb_bus *host);
+
+	/* bind/unbind the peripheral controller */
+	int	(*set_peripheral)(struct usb_otg *otg,
+					struct usb_gadget *gadget);
+
+	/* effective for A-peripheral, ignored for B devices */
+	int	(*set_vbus)(struct usb_otg *otg, bool enabled);
+
+	/* for B devices only:  start session with A-Host */
+	int	(*start_srp)(struct usb_otg *otg);
+
+	/* start or continue HNP role switch */
+	int	(*start_hnp)(struct usb_otg *otg);
+
 };
 
 /*
@@ -59,22 +84,20 @@
  * moment, using the transceiver, ID signal, HNP and sometimes static
  * configuration information (including "board isn't wired for otg").
  */
-struct otg_transceiver {
+struct usb_phy {
 	struct device		*dev;
 	const char		*label;
 	unsigned int		 flags;
 
-	u8			default_a;
 	enum usb_otg_state	state;
-	enum usb_xceiv_events	last_event;
+	enum usb_phy_events	last_event;
 
-	struct usb_bus		*host;
-	struct usb_gadget	*gadget;
+	struct usb_otg		*otg;
 
-	struct otg_io_access_ops	*io_ops;
-	void __iomem			*io_priv;
+	struct usb_phy_io_ops	*io_ops;
+	void __iomem		*io_priv;
 
-	/* for notification of usb_xceiv_events */
+	/* for notification of usb_phy_events */
 	struct atomic_notifier_head	notifier;
 
 	/* to pass extra port status to the root hub */
@@ -82,40 +105,22 @@
 	u16			port_change;
 
 	/* initialize/shutdown the OTG controller */
-	int	(*init)(struct otg_transceiver *otg);
-	void	(*shutdown)(struct otg_transceiver *otg);
-
-	/* bind/unbind the host controller */
-	int	(*set_host)(struct otg_transceiver *otg,
-				struct usb_bus *host);
-
-	/* bind/unbind the peripheral controller */
-	int	(*set_peripheral)(struct otg_transceiver *otg,
-				struct usb_gadget *gadget);
+	int	(*init)(struct usb_phy *x);
+	void	(*shutdown)(struct usb_phy *x);
 
 	/* effective for B devices, ignored for A-peripheral */
-	int	(*set_power)(struct otg_transceiver *otg,
+	int	(*set_power)(struct usb_phy *x,
 				unsigned mA);
 
-	/* effective for A-peripheral, ignored for B devices */
-	int	(*set_vbus)(struct otg_transceiver *otg,
-				bool enabled);
-
 	/* for non-OTG B devices: set transceiver into suspend mode */
-	int	(*set_suspend)(struct otg_transceiver *otg,
+	int	(*set_suspend)(struct usb_phy *x,
 				int suspend);
 
-	/* for B devices only:  start session with A-Host */
-	int	(*start_srp)(struct otg_transceiver *otg);
-
-	/* start or continue HNP role switch */
-	int	(*start_hnp)(struct otg_transceiver *otg);
-
 };
 
 
 /* for board-specific init logic */
-extern int otg_set_transceiver(struct otg_transceiver *);
+extern int usb_set_transceiver(struct usb_phy *);
 
 #if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
 /* sometimes transceivers are accessed only through e.g. ULPI */
@@ -132,50 +137,50 @@
 #endif
 
 /* helpers for direct access thru low-level io interface */
-static inline int otg_io_read(struct otg_transceiver *otg, u32 reg)
+static inline int usb_phy_io_read(struct usb_phy *x, u32 reg)
 {
-	if (otg->io_ops && otg->io_ops->read)
-		return otg->io_ops->read(otg, reg);
+	if (x->io_ops && x->io_ops->read)
+		return x->io_ops->read(x, reg);
 
 	return -EINVAL;
 }
 
-static inline int otg_io_write(struct otg_transceiver *otg, u32 val, u32 reg)
+static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg)
 {
-	if (otg->io_ops && otg->io_ops->write)
-		return otg->io_ops->write(otg, val, reg);
+	if (x->io_ops && x->io_ops->write)
+		return x->io_ops->write(x, val, reg);
 
 	return -EINVAL;
 }
 
 static inline int
-otg_init(struct otg_transceiver *otg)
+usb_phy_init(struct usb_phy *x)
 {
-	if (otg->init)
-		return otg->init(otg);
+	if (x->init)
+		return x->init(x);
 
 	return 0;
 }
 
 static inline void
-otg_shutdown(struct otg_transceiver *otg)
+usb_phy_shutdown(struct usb_phy *x)
 {
-	if (otg->shutdown)
-		otg->shutdown(otg);
+	if (x->shutdown)
+		x->shutdown(x);
 }
 
 /* for usb host and peripheral controller drivers */
 #ifdef CONFIG_USB_OTG_UTILS
-extern struct otg_transceiver *otg_get_transceiver(void);
-extern void otg_put_transceiver(struct otg_transceiver *);
+extern struct usb_phy *usb_get_transceiver(void);
+extern void usb_put_transceiver(struct usb_phy *);
 extern const char *otg_state_string(enum usb_otg_state state);
 #else
-static inline struct otg_transceiver *otg_get_transceiver(void)
+static inline struct usb_phy *usb_get_transceiver(void)
 {
 	return NULL;
 }
 
-static inline void otg_put_transceiver(struct otg_transceiver *x)
+static inline void usb_put_transceiver(struct usb_phy *x)
 {
 }
 
@@ -187,67 +192,84 @@
 
 /* Context: can sleep */
 static inline int
-otg_start_hnp(struct otg_transceiver *otg)
+otg_start_hnp(struct usb_otg *otg)
 {
-	return otg->start_hnp(otg);
+	if (otg && otg->start_hnp)
+		return otg->start_hnp(otg);
+
+	return -ENOTSUPP;
 }
 
 /* Context: can sleep */
 static inline int
-otg_set_vbus(struct otg_transceiver *otg, bool enabled)
+otg_set_vbus(struct usb_otg *otg, bool enabled)
 {
-	return otg->set_vbus(otg, enabled);
+	if (otg && otg->set_vbus)
+		return otg->set_vbus(otg, enabled);
+
+	return -ENOTSUPP;
 }
 
 /* for HCDs */
 static inline int
-otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
+otg_set_host(struct usb_otg *otg, struct usb_bus *host)
 {
-	return otg->set_host(otg, host);
+	if (otg && otg->set_host)
+		return otg->set_host(otg, host);
+
+	return -ENOTSUPP;
 }
 
 /* for usb peripheral controller drivers */
 
 /* Context: can sleep */
 static inline int
-otg_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *periph)
+otg_set_peripheral(struct usb_otg *otg, struct usb_gadget *periph)
 {
-	return otg->set_peripheral(otg, periph);
+	if (otg && otg->set_peripheral)
+		return otg->set_peripheral(otg, periph);
+
+	return -ENOTSUPP;
 }
 
 static inline int
-otg_set_power(struct otg_transceiver *otg, unsigned mA)
+usb_phy_set_power(struct usb_phy *x, unsigned mA)
 {
-	return otg->set_power(otg, mA);
+	if (x && x->set_power)
+		return x->set_power(x, mA);
+	return 0;
 }
 
 /* Context: can sleep */
 static inline int
-otg_set_suspend(struct otg_transceiver *otg, int suspend)
+usb_phy_set_suspend(struct usb_phy *x, int suspend)
 {
-	if (otg->set_suspend != NULL)
-		return otg->set_suspend(otg, suspend);
+	if (x->set_suspend != NULL)
+		return x->set_suspend(x, suspend);
 	else
 		return 0;
 }
 
 static inline int
-otg_start_srp(struct otg_transceiver *otg)
+otg_start_srp(struct usb_otg *otg)
 {
-	return otg->start_srp(otg);
+	if (otg && otg->start_srp)
+		return otg->start_srp(otg);
+
+	return -ENOTSUPP;
 }
 
 /* notifiers */
 static inline int
-otg_register_notifier(struct otg_transceiver *otg, struct notifier_block *nb)
+usb_register_notifier(struct usb_phy *x, struct notifier_block *nb)
 {
-	return atomic_notifier_chain_register(&otg->notifier, nb);
+	return atomic_notifier_chain_register(&x->notifier, nb);
 }
 
 static inline void
-otg_unregister_notifier(struct otg_transceiver *otg, struct notifier_block *nb)
+usb_unregister_notifier(struct usb_phy *x, struct notifier_block *nb)
 {
-	atomic_notifier_chain_unregister(&otg->notifier, nb);
+	atomic_notifier_chain_unregister(&x->notifier, nb);
 }
 
 /* for OTG controller drivers (and maybe other stuff) */
diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h
index 0d3f988..547e59c 100644
--- a/include/linux/usb/renesas_usbhs.h
+++ b/include/linux/usb/renesas_usbhs.h
@@ -149,6 +149,7 @@
 	 * option:
 	 */
 	u32 has_otg:1; /* for controlling PWEN/EXTLP */
+	u32 has_sudmac:1; /* for SUDMAC */
 };
 
 /*
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 4267a9c..fbb666b 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -300,8 +300,10 @@
 #define to_usb_serial_driver(d) \
 	container_of(d, struct usb_serial_driver, driver)
 
-extern int  usb_serial_register(struct usb_serial_driver *driver);
-extern void usb_serial_deregister(struct usb_serial_driver *driver);
+extern int usb_serial_register_drivers(struct usb_driver *udriver,
+		struct usb_serial_driver * const serial_drivers[]);
+extern void usb_serial_deregister_drivers(struct usb_driver *udriver,
+		struct usb_serial_driver * const serial_drivers[]);
 extern void usb_serial_port_softint(struct usb_serial_port *port);
 
 extern int usb_serial_probe(struct usb_interface *iface,
@@ -389,5 +391,35 @@
 		printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg);	\
 } while (0)
 
+/*
+ * Macro for reporting errors in write path to avoid inifinite loop
+ * when port is used as a console.
+ */
+#define dev_err_console(usport, fmt, ...)				\
+do {									\
+	static bool __print_once;					\
+	struct usb_serial_port *__port = (usport);			\
+									\
+	if (!__port->port.console || !__print_once) {			\
+		__print_once = true;					\
+		dev_err(&__port->dev, fmt, ##__VA_ARGS__);		\
+	}								\
+} while (0)
+
+/*
+ * module_usb_serial_driver() - Helper macro for registering a USB Serial driver
+ * @__usb_driver: usb_driver struct to register
+ * @__serial_drivers: list of usb_serial drivers to register
+ *
+ * Helper macro for USB serial drivers which do not do anything special
+ * in module init/exit. This eliminates a lot of boilerplate. Each
+ * module may only use this macro once, and calling it replaces
+ * module_init() and module_exit()
+ *
+ */
+#define module_usb_serial_driver(__usb_driver, __serial_drivers)	\
+	module_driver(__usb_driver, usb_serial_register_drivers,	\
+		       usb_serial_deregister_drivers, __serial_drivers)
+
 #endif /* __LINUX_USB_SERIAL_H */
 
diff --git a/include/linux/usb/storage.h b/include/linux/usb/storage.h
index d7fc910..cb33fff 100644
--- a/include/linux/usb/storage.h
+++ b/include/linux/usb/storage.h
@@ -45,4 +45,42 @@
 
 #define USB_PR_DEVICE	0xff		/* Use device's value */
 
+ /*
+  * Bulk only data structures
+  */
+
+/* command block wrapper */
+struct bulk_cb_wrap {
+	__le32	Signature;		/* contains 'USBC' */
+	__u32	Tag;			/* unique per command id */
+	__le32	DataTransferLength;	/* size of data */
+	__u8	Flags;			/* direction in bit 0 */
+	__u8	Lun;			/* LUN normally 0 */
+	__u8	Length;			/* of of the CDB */
+	__u8	CDB[16];		/* max command */
+};
+
+#define US_BULK_CB_WRAP_LEN	31
+#define US_BULK_CB_SIGN		0x43425355	/*spells out USBC */
+#define US_BULK_FLAG_IN		(1 << 7)
+#define US_BULK_FLAG_OUT	0
+
+/* command status wrapper */
+struct bulk_cs_wrap {
+	__le32	Signature;	/* should = 'USBS' */
+	__u32	Tag;		/* same as original command */
+	__le32	Residue;	/* amount not transferred */
+	__u8	Status;		/* see below */
+};
+
+#define US_BULK_CS_WRAP_LEN	13
+#define US_BULK_CS_SIGN		0x53425355      /* spells out 'USBS' */
+#define US_BULK_STAT_OK		0
+#define US_BULK_STAT_FAIL	1
+#define US_BULK_STAT_PHASE	2
+
+/* bulk-only class specific requests */
+#define US_BULK_RESET_REQUEST   0xff
+#define US_BULK_GET_MAX_LUN     0xfe
+
 #endif
diff --git a/include/linux/usb/uas.h b/include/linux/usb/uas.h
new file mode 100644
index 0000000..9a988e4
--- /dev/null
+++ b/include/linux/usb/uas.h
@@ -0,0 +1,69 @@
+#ifndef __USB_UAS_H__
+#define __USB_UAS_H__
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+/* Common header for all IUs */
+struct iu {
+	__u8 iu_id;
+	__u8 rsvd1;
+	__be16 tag;
+};
+
+enum {
+	IU_ID_COMMAND		= 0x01,
+	IU_ID_STATUS		= 0x03,
+	IU_ID_RESPONSE		= 0x04,
+	IU_ID_TASK_MGMT		= 0x05,
+	IU_ID_READ_READY	= 0x06,
+	IU_ID_WRITE_READY	= 0x07,
+};
+
+struct command_iu {
+	__u8 iu_id;
+	__u8 rsvd1;
+	__be16 tag;
+	__u8 prio_attr;
+	__u8 rsvd5;
+	__u8 len;
+	__u8 rsvd7;
+	struct scsi_lun lun;
+	__u8 cdb[16];	/* XXX: Overflow-checking tools may misunderstand */
+};
+
+/*
+ * Also used for the Read Ready and Write Ready IUs since they have the
+ * same first four bytes
+ */
+struct sense_iu {
+	__u8 iu_id;
+	__u8 rsvd1;
+	__be16 tag;
+	__be16 status_qual;
+	__u8 status;
+	__u8 rsvd7[7];
+	__be16 len;
+	__u8 sense[SCSI_SENSE_BUFFERSIZE];
+};
+
+struct usb_pipe_usage_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+
+	__u8  bPipeID;
+	__u8  Reserved;
+} __attribute__((__packed__));
+
+enum {
+	CMD_PIPE_ID		= 1,
+	STATUS_PIPE_ID		= 2,
+	DATA_IN_PIPE_ID		= 3,
+	DATA_OUT_PIPE_ID	= 4,
+
+	UAS_SIMPLE_TAG		= 0,
+	UAS_HEAD_TAG		= 1,
+	UAS_ORDERED_TAG		= 2,
+	UAS_ACA			= 4,
+};
+#endif
diff --git a/include/linux/usb/ulpi.h b/include/linux/usb/ulpi.h
index 9595796..6f033a4 100644
--- a/include/linux/usb/ulpi.h
+++ b/include/linux/usb/ulpi.h
@@ -181,12 +181,12 @@
 
 /*-------------------------------------------------------------------------*/
 
-struct otg_transceiver *otg_ulpi_create(struct otg_io_access_ops *ops,
+struct usb_phy *otg_ulpi_create(struct usb_phy_io_ops *ops,
 					unsigned int flags);
 
 #ifdef CONFIG_USB_ULPI_VIEWPORT
 /* access ops for controllers with a viewport register */
-extern struct otg_io_access_ops ulpi_viewport_access_ops;
+extern struct usb_phy_io_ops ulpi_viewport_access_ops;
 #endif
 
 #endif /* __LINUX_USB_ULPI_H */
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index c2164fa..e33d77f 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -167,4 +167,30 @@
 
 extern void hide_boot_cursor(bool hide);
 
+/* keyboard  provided interfaces */
+extern int vt_do_diacrit(unsigned int cmd, void __user *up, int eperm);
+extern int vt_do_kdskbmode(int console, unsigned int arg);
+extern int vt_do_kdskbmeta(int console, unsigned int arg);
+extern int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc,
+								int perm);
+extern int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe,
+					int perm, int console);
+extern int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb,
+                                        int perm);
+extern int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm);
+extern int vt_do_kdgkbmode(int console);
+extern int vt_do_kdgkbmeta(int console);
+extern void vt_reset_unicode(int console);
+extern int vt_get_shift_state(void);
+extern void vt_reset_keyboard(int console);
+extern int vt_get_leds(int console, int flag);
+extern int vt_get_kbd_mode_bit(int console, int bit);
+extern void vt_set_kbd_mode_bit(int console, int bit);
+extern void vt_clr_kbd_mode_bit(int console, int bit);
+extern void vt_set_led_state(int console, int leds);
+extern void vt_set_led_state(int console, int leds);
+extern void vt_kbd_con_start(int console);
+extern void vt_kbd_con_stop(int console);
+
+
 #endif /* _VT_KERN_H */
diff --git a/include/linux/wait.h b/include/linux/wait.h
index a9ce45e..7d9a9e9 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -157,7 +157,7 @@
 void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key);
 void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode, int nr,
 			void *key);
-void __wake_up_locked(wait_queue_head_t *q, unsigned int mode);
+void __wake_up_locked(wait_queue_head_t *q, unsigned int mode, int nr);
 void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr);
 void __wake_up_bit(wait_queue_head_t *, void *, int);
 int __wait_on_bit(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned);
@@ -170,7 +170,8 @@
 #define wake_up(x)			__wake_up(x, TASK_NORMAL, 1, NULL)
 #define wake_up_nr(x, nr)		__wake_up(x, TASK_NORMAL, nr, NULL)
 #define wake_up_all(x)			__wake_up(x, TASK_NORMAL, 0, NULL)
-#define wake_up_locked(x)		__wake_up_locked((x), TASK_NORMAL)
+#define wake_up_locked(x)		__wake_up_locked((x), TASK_NORMAL, 1)
+#define wake_up_all_locked(x)		__wake_up_locked((x), TASK_NORMAL, 0)
 
 #define wake_up_interruptible(x)	__wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)
 #define wake_up_interruptible_nr(x, nr)	__wake_up(x, TASK_INTERRUPTIBLE, nr, NULL)
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index eb8b9f1..af15545 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -289,12 +289,16 @@
  *
  * system_freezable_wq is equivalent to system_wq except that it's
  * freezable.
+ *
+ * system_nrt_freezable_wq is equivalent to system_nrt_wq except that
+ * it's freezable.
  */
 extern struct workqueue_struct *system_wq;
 extern struct workqueue_struct *system_long_wq;
 extern struct workqueue_struct *system_nrt_wq;
 extern struct workqueue_struct *system_unbound_wq;
 extern struct workqueue_struct *system_freezable_wq;
+extern struct workqueue_struct *system_nrt_freezable_wq;
 
 extern struct workqueue_struct *
 __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
diff --git a/include/net/sock.h b/include/net/sock.h
index 91c1c8b..7ef5c58 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -55,7 +55,7 @@
 #include <linux/uaccess.h>
 #include <linux/memcontrol.h>
 #include <linux/res_counter.h>
-#include <linux/jump_label.h>
+#include <linux/static_key.h>
 
 #include <linux/filter.h>
 #include <linux/rculist_nulls.h>
@@ -69,7 +69,7 @@
 struct cgroup_subsys;
 #ifdef CONFIG_NET
 int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss);
-void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss);
+void mem_cgroup_sockets_destroy(struct cgroup *cgrp);
 #else
 static inline
 int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss)
@@ -77,7 +77,7 @@
 	return 0;
 }
 static inline
-void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss)
+void mem_cgroup_sockets_destroy(struct cgroup *cgrp)
 {
 }
 #endif
@@ -871,8 +871,7 @@
 	 */
 	int			(*init_cgroup)(struct cgroup *cgrp,
 					       struct cgroup_subsys *ss);
-	void			(*destroy_cgroup)(struct cgroup *cgrp,
-						  struct cgroup_subsys *ss);
+	void			(*destroy_cgroup)(struct cgroup *cgrp);
 	struct cg_proto		*(*proto_cgroup)(struct mem_cgroup *memcg);
 #endif
 };
@@ -924,13 +923,13 @@
 #endif /* SOCK_REFCNT_DEBUG */
 
 #if defined(CONFIG_CGROUP_MEM_RES_CTLR_KMEM) && defined(CONFIG_NET)
-extern struct jump_label_key memcg_socket_limit_enabled;
+extern struct static_key memcg_socket_limit_enabled;
 static inline struct cg_proto *parent_cg_proto(struct proto *proto,
 					       struct cg_proto *cg_proto)
 {
 	return proto->proto_cgroup(parent_mem_cgroup(cg_proto->memcg));
 }
-#define mem_cgroup_sockets_enabled static_branch(&memcg_socket_limit_enabled)
+#define mem_cgroup_sockets_enabled static_key_false(&memcg_socket_limit_enabled)
 #else
 #define mem_cgroup_sockets_enabled 0
 static inline struct cg_proto *parent_cg_proto(struct proto *proto,
diff --git a/include/net/tcp_memcontrol.h b/include/net/tcp_memcontrol.h
index 3512082..48410ff 100644
--- a/include/net/tcp_memcontrol.h
+++ b/include/net/tcp_memcontrol.h
@@ -13,7 +13,7 @@
 
 struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg);
 int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss);
-void tcp_destroy_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss);
+void tcp_destroy_cgroup(struct cgroup *cgrp);
 unsigned long long tcp_max_memory(const struct mem_cgroup *memcg);
 void tcp_prot_mem(struct mem_cgroup *memcg, long val, int idx);
 #endif /* _TCP_MEMCG_H */
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 77273f2..b3a1c2d 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -136,6 +136,7 @@
 	unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */
 	unsigned skip_ms_page_8:1;	/* do not use MODE SENSE page 0x08 */
 	unsigned skip_ms_page_3f:1;	/* do not use MODE SENSE page 0x3f */
+	unsigned skip_vpd_pages:1;	/* do not read VPD pages */
 	unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */
 	unsigned no_start_on_add:1;	/* do not issue start on add */
 	unsigned allow_restart:1; /* issue START_UNIT in error handler */
@@ -246,8 +247,10 @@
 	unsigned int		single_lun:1;	/* Indicates we should only
 						 * allow I/O to one of the luns
 						 * for the device at a time. */
-	unsigned int		pdt_1f_for_no_lun;	/* PDT = 0x1f */
-						/* means no lun present */
+	unsigned int		pdt_1f_for_no_lun:1;	/* PDT = 0x1f
+						 * means no lun present. */
+	unsigned int		no_report_luns:1;	/* Don't use
+						 * REPORT LUNS for scanning. */
 	/* commands actually active on LLD. protected by host lock. */
 	unsigned int		target_busy;
 	/*
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index 1bcc2a8..14b3894 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -151,6 +151,8 @@
    events get removed */
 static inline void trace_power_start(u64 type, u64 state, u64 cpuid) {};
 static inline void trace_power_end(u64 cpuid) {};
+static inline void trace_power_start_rcuidle(u64 type, u64 state, u64 cpuid) {};
+static inline void trace_power_end_rcuidle(u64 cpuid) {};
 static inline void trace_power_frequency(u64 type, u64 state, u64 cpuid) {};
 #endif /* _PWR_EVENT_AVOID_DOUBLE_DEFINING_DEPRECATED */
 
diff --git a/include/trace/events/printk.h b/include/trace/events/printk.h
new file mode 100644
index 0000000..94ec79c
--- /dev/null
+++ b/include/trace/events/printk.h
@@ -0,0 +1,41 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM printk
+
+#if !defined(_TRACE_PRINTK_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_PRINTK_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT_CONDITION(console,
+	TP_PROTO(const char *log_buf, unsigned start, unsigned end,
+		 unsigned log_buf_len),
+
+	TP_ARGS(log_buf, start, end, log_buf_len),
+
+	TP_CONDITION(start != end),
+
+	TP_STRUCT__entry(
+		__dynamic_array(char, msg, end - start + 1)
+	),
+
+	TP_fast_assign(
+		if ((start & (log_buf_len - 1)) > (end & (log_buf_len - 1))) {
+			memcpy(__get_dynamic_array(msg),
+			       log_buf + (start & (log_buf_len - 1)),
+			       log_buf_len - (start & (log_buf_len - 1)));
+			memcpy((char *)__get_dynamic_array(msg) +
+			       log_buf_len - (start & (log_buf_len - 1)),
+			       log_buf, end & (log_buf_len - 1));
+		} else
+			memcpy(__get_dynamic_array(msg),
+			       log_buf + (start & (log_buf_len - 1)),
+			       end - start);
+		((char *)__get_dynamic_array(msg))[end - start] = 0;
+	),
+
+	TP_printk("%s", __get_str(msg))
+);
+#endif /* _TRACE_PRINTK_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h
index d2d88be..3370997 100644
--- a/include/trace/events/rcu.h
+++ b/include/trace/events/rcu.h
@@ -313,19 +313,22 @@
 /*
  * Tracepoint for the registration of a single RCU callback function.
  * The first argument is the type of RCU, the second argument is
- * a pointer to the RCU callback itself, and the third element is the
- * new RCU callback queue length for the current CPU.
+ * a pointer to the RCU callback itself, the third element is the
+ * number of lazy callbacks queued, and the fourth element is the
+ * total number of callbacks queued.
  */
 TRACE_EVENT(rcu_callback,
 
-	TP_PROTO(char *rcuname, struct rcu_head *rhp, long qlen),
+	TP_PROTO(char *rcuname, struct rcu_head *rhp, long qlen_lazy,
+		 long qlen),
 
-	TP_ARGS(rcuname, rhp, qlen),
+	TP_ARGS(rcuname, rhp, qlen_lazy, qlen),
 
 	TP_STRUCT__entry(
 		__field(char *, rcuname)
 		__field(void *, rhp)
 		__field(void *, func)
+		__field(long, qlen_lazy)
 		__field(long, qlen)
 	),
 
@@ -333,11 +336,13 @@
 		__entry->rcuname = rcuname;
 		__entry->rhp = rhp;
 		__entry->func = rhp->func;
+		__entry->qlen_lazy = qlen_lazy;
 		__entry->qlen = qlen;
 	),
 
-	TP_printk("%s rhp=%p func=%pf %ld",
-		  __entry->rcuname, __entry->rhp, __entry->func, __entry->qlen)
+	TP_printk("%s rhp=%p func=%pf %ld/%ld",
+		  __entry->rcuname, __entry->rhp, __entry->func,
+		  __entry->qlen_lazy, __entry->qlen)
 );
 
 /*
@@ -345,20 +350,21 @@
  * kfree() form.  The first argument is the RCU type, the second argument
  * is a pointer to the RCU callback, the third argument is the offset
  * of the callback within the enclosing RCU-protected data structure,
- * and the fourth argument is the new RCU callback queue length for the
- * current CPU.
+ * the fourth argument is the number of lazy callbacks queued, and the
+ * fifth argument is the total number of callbacks queued.
  */
 TRACE_EVENT(rcu_kfree_callback,
 
 	TP_PROTO(char *rcuname, struct rcu_head *rhp, unsigned long offset,
-		 long qlen),
+		 long qlen_lazy, long qlen),
 
-	TP_ARGS(rcuname, rhp, offset, qlen),
+	TP_ARGS(rcuname, rhp, offset, qlen_lazy, qlen),
 
 	TP_STRUCT__entry(
 		__field(char *, rcuname)
 		__field(void *, rhp)
 		__field(unsigned long, offset)
+		__field(long, qlen_lazy)
 		__field(long, qlen)
 	),
 
@@ -366,41 +372,45 @@
 		__entry->rcuname = rcuname;
 		__entry->rhp = rhp;
 		__entry->offset = offset;
+		__entry->qlen_lazy = qlen_lazy;
 		__entry->qlen = qlen;
 	),
 
-	TP_printk("%s rhp=%p func=%ld %ld",
+	TP_printk("%s rhp=%p func=%ld %ld/%ld",
 		  __entry->rcuname, __entry->rhp, __entry->offset,
-		  __entry->qlen)
+		  __entry->qlen_lazy, __entry->qlen)
 );
 
 /*
  * Tracepoint for marking the beginning rcu_do_batch, performed to start
  * RCU callback invocation.  The first argument is the RCU flavor,
- * the second is the total number of callbacks (including those that
- * are not yet ready to be invoked), and the third argument is the
- * current RCU-callback batch limit.
+ * the second is the number of lazy callbacks queued, the third is
+ * the total number of callbacks queued, and the fourth argument is
+ * the current RCU-callback batch limit.
  */
 TRACE_EVENT(rcu_batch_start,
 
-	TP_PROTO(char *rcuname, long qlen, int blimit),
+	TP_PROTO(char *rcuname, long qlen_lazy, long qlen, int blimit),
 
-	TP_ARGS(rcuname, qlen, blimit),
+	TP_ARGS(rcuname, qlen_lazy, qlen, blimit),
 
 	TP_STRUCT__entry(
 		__field(char *, rcuname)
+		__field(long, qlen_lazy)
 		__field(long, qlen)
 		__field(int, blimit)
 	),
 
 	TP_fast_assign(
 		__entry->rcuname = rcuname;
+		__entry->qlen_lazy = qlen_lazy;
 		__entry->qlen = qlen;
 		__entry->blimit = blimit;
 	),
 
-	TP_printk("%s CBs=%ld bl=%d",
-		  __entry->rcuname, __entry->qlen, __entry->blimit)
+	TP_printk("%s CBs=%ld/%ld bl=%d",
+		  __entry->rcuname, __entry->qlen_lazy, __entry->qlen,
+		  __entry->blimit)
 );
 
 /*
@@ -531,16 +541,21 @@
 #else /* #ifdef CONFIG_RCU_TRACE */
 
 #define trace_rcu_grace_period(rcuname, gpnum, gpevent) do { } while (0)
-#define trace_rcu_grace_period_init(rcuname, gpnum, level, grplo, grphi, qsmask) do { } while (0)
+#define trace_rcu_grace_period_init(rcuname, gpnum, level, grplo, grphi, \
+				    qsmask) do { } while (0)
 #define trace_rcu_preempt_task(rcuname, pid, gpnum) do { } while (0)
 #define trace_rcu_unlock_preempted_task(rcuname, gpnum, pid) do { } while (0)
-#define trace_rcu_quiescent_state_report(rcuname, gpnum, mask, qsmask, level, grplo, grphi, gp_tasks) do { } while (0)
+#define trace_rcu_quiescent_state_report(rcuname, gpnum, mask, qsmask, level, \
+					 grplo, grphi, gp_tasks) do { } \
+	while (0)
 #define trace_rcu_fqs(rcuname, gpnum, cpu, qsevent) do { } while (0)
 #define trace_rcu_dyntick(polarity, oldnesting, newnesting) do { } while (0)
 #define trace_rcu_prep_idle(reason) do { } while (0)
-#define trace_rcu_callback(rcuname, rhp, qlen) do { } while (0)
-#define trace_rcu_kfree_callback(rcuname, rhp, offset, qlen) do { } while (0)
-#define trace_rcu_batch_start(rcuname, qlen, blimit) do { } while (0)
+#define trace_rcu_callback(rcuname, rhp, qlen_lazy, qlen) do { } while (0)
+#define trace_rcu_kfree_callback(rcuname, rhp, offset, qlen_lazy, qlen) \
+	do { } while (0)
+#define trace_rcu_batch_start(rcuname, qlen_lazy, qlen, blimit) \
+	do { } while (0)
 #define trace_rcu_invoke_callback(rcuname, rhp) do { } while (0)
 #define trace_rcu_invoke_kfree_callback(rcuname, rhp, offset) do { } while (0)
 #define trace_rcu_batch_end(rcuname, callbacks_invoked, cb, nr, iit, risk) \
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index e33ed1b..fbc7b1a 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -6,6 +6,7 @@
 
 #include <linux/sched.h>
 #include <linux/tracepoint.h>
+#include <linux/binfmts.h>
 
 /*
  * Tracepoint for calling kthread_stop, performed to end a kthread:
@@ -276,6 +277,32 @@
 );
 
 /*
+ * Tracepoint for exec:
+ */
+TRACE_EVENT(sched_process_exec,
+
+	TP_PROTO(struct task_struct *p, pid_t old_pid,
+		 struct linux_binprm *bprm),
+
+	TP_ARGS(p, old_pid, bprm),
+
+	TP_STRUCT__entry(
+		__string(	filename,	bprm->filename	)
+		__field(	pid_t,		pid		)
+		__field(	pid_t,		old_pid		)
+	),
+
+	TP_fast_assign(
+		__assign_str(filename, bprm->filename);
+		__entry->pid		= p->pid;
+		__entry->old_pid	= p->pid;
+	),
+
+	TP_printk("filename=%s pid=%d old_pid=%d", __get_str(filename),
+		  __entry->pid, __entry->old_pid)
+);
+
+/*
  * XXX the below sched_stat tracepoints only apply to SCHED_OTHER/BATCH/IDLE
  *     adding sched_stat support to SCHED_FIFO/RR would be welcome.
  */
diff --git a/include/trace/events/signal.h b/include/trace/events/signal.h
index 17df434..39a8a43 100644
--- a/include/trace/events/signal.h
+++ b/include/trace/events/signal.h
@@ -23,11 +23,23 @@
 		}						\
 	} while (0)
 
+#ifndef TRACE_HEADER_MULTI_READ
+enum {
+	TRACE_SIGNAL_DELIVERED,
+	TRACE_SIGNAL_IGNORED,
+	TRACE_SIGNAL_ALREADY_PENDING,
+	TRACE_SIGNAL_OVERFLOW_FAIL,
+	TRACE_SIGNAL_LOSE_INFO,
+};
+#endif
+
 /**
  * signal_generate - called when a signal is generated
  * @sig: signal number
  * @info: pointer to struct siginfo
  * @task: pointer to struct task_struct
+ * @group: shared or private
+ * @result: TRACE_SIGNAL_*
  *
  * Current process sends a 'sig' signal to 'task' process with
  * 'info' siginfo. If 'info' is SEND_SIG_NOINFO or SEND_SIG_PRIV,
@@ -37,9 +49,10 @@
  */
 TRACE_EVENT(signal_generate,
 
-	TP_PROTO(int sig, struct siginfo *info, struct task_struct *task),
+	TP_PROTO(int sig, struct siginfo *info, struct task_struct *task,
+			int group, int result),
 
-	TP_ARGS(sig, info, task),
+	TP_ARGS(sig, info, task, group, result),
 
 	TP_STRUCT__entry(
 		__field(	int,	sig			)
@@ -47,6 +60,8 @@
 		__field(	int,	code			)
 		__array(	char,	comm,	TASK_COMM_LEN	)
 		__field(	pid_t,	pid			)
+		__field(	int,	group			)
+		__field(	int,	result			)
 	),
 
 	TP_fast_assign(
@@ -54,11 +69,14 @@
 		TP_STORE_SIGINFO(__entry, info);
 		memcpy(__entry->comm, task->comm, TASK_COMM_LEN);
 		__entry->pid	= task->pid;
+		__entry->group	= group;
+		__entry->result	= result;
 	),
 
-	TP_printk("sig=%d errno=%d code=%d comm=%s pid=%d",
+	TP_printk("sig=%d errno=%d code=%d comm=%s pid=%d grp=%d res=%d",
 		  __entry->sig, __entry->errno, __entry->code,
-		  __entry->comm, __entry->pid)
+		  __entry->comm, __entry->pid, __entry->group,
+		  __entry->result)
 );
 
 /**
@@ -101,65 +119,6 @@
 		  __entry->sa_handler, __entry->sa_flags)
 );
 
-DECLARE_EVENT_CLASS(signal_queue_overflow,
-
-	TP_PROTO(int sig, int group, struct siginfo *info),
-
-	TP_ARGS(sig, group, info),
-
-	TP_STRUCT__entry(
-		__field(	int,	sig	)
-		__field(	int,	group	)
-		__field(	int,	errno	)
-		__field(	int,	code	)
-	),
-
-	TP_fast_assign(
-		__entry->sig	= sig;
-		__entry->group	= group;
-		TP_STORE_SIGINFO(__entry, info);
-	),
-
-	TP_printk("sig=%d group=%d errno=%d code=%d",
-		  __entry->sig, __entry->group, __entry->errno, __entry->code)
-);
-
-/**
- * signal_overflow_fail - called when signal queue is overflow
- * @sig: signal number
- * @group: signal to process group or not (bool)
- * @info: pointer to struct siginfo
- *
- * Kernel fails to generate 'sig' signal with 'info' siginfo, because
- * siginfo queue is overflow, and the signal is dropped.
- * 'group' is not 0 if the signal will be sent to a process group.
- * 'sig' is always one of RT signals.
- */
-DEFINE_EVENT(signal_queue_overflow, signal_overflow_fail,
-
-	TP_PROTO(int sig, int group, struct siginfo *info),
-
-	TP_ARGS(sig, group, info)
-);
-
-/**
- * signal_lose_info - called when siginfo is lost
- * @sig: signal number
- * @group: signal to process group or not (bool)
- * @info: pointer to struct siginfo
- *
- * Kernel generates 'sig' signal but loses 'info' siginfo, because siginfo
- * queue is overflow.
- * 'group' is not 0 if the signal will be sent to a process group.
- * 'sig' is always one of non-RT signals.
- */
-DEFINE_EVENT(signal_queue_overflow, signal_lose_info,
-
-	TP_PROTO(int sig, int group, struct siginfo *info),
-
-	TP_ARGS(sig, group, info)
-);
-
 #endif /* _TRACE_SIGNAL_H */
 
 /* This part must be outside protection */
diff --git a/init/Kconfig b/init/Kconfig
index 3f42cd6..72f33fa 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -438,15 +438,6 @@
 	  This option enables preemptible-RCU code that is common between
 	  the TREE_PREEMPT_RCU and TINY_PREEMPT_RCU implementations.
 
-config RCU_TRACE
-	bool "Enable tracing for RCU"
-	help
-	  This option provides tracing in RCU which presents stats
-	  in debugfs for debugging RCU implementation.
-
-	  Say Y here if you want to enable RCU tracing
-	  Say N if you are unsure.
-
 config RCU_FANOUT
 	int "Tree-based hierarchical RCU fanout value"
 	range 2 64 if 64BIT
diff --git a/init/main.c b/init/main.c
index ff49a6d..4990f7e 100644
--- a/init/main.c
+++ b/init/main.c
@@ -374,11 +374,8 @@
 	 * at least once to get things moving:
 	 */
 	init_idle_bootup_task(current);
-	preempt_enable_no_resched();
-	schedule();
-
+	schedule_preempt_disabled();
 	/* Call into cpu_idle with preempt disabled */
-	preempt_disable();
 	cpu_idle();
 }
 
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index a5d3b53..c6877fe 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -818,7 +818,7 @@
 
 	for_each_subsys(cgrp->root, ss)
 		if (ss->pre_destroy) {
-			ret = ss->pre_destroy(ss, cgrp);
+			ret = ss->pre_destroy(cgrp);
 			if (ret)
 				break;
 		}
@@ -846,7 +846,7 @@
 		 * Release the subsystem state objects.
 		 */
 		for_each_subsys(cgrp->root, ss)
-			ss->destroy(ss, cgrp);
+			ss->destroy(cgrp);
 
 		cgrp->root->number_of_cgroups--;
 		mutex_unlock(&cgroup_mutex);
@@ -1015,7 +1015,7 @@
 			list_move(&ss->sibling, &root->subsys_list);
 			ss->root = root;
 			if (ss->bind)
-				ss->bind(ss, cgrp);
+				ss->bind(cgrp);
 			mutex_unlock(&ss->hierarchy_mutex);
 			/* refcount was already taken, and we're keeping it */
 		} else if (bit & removed_bits) {
@@ -1025,7 +1025,7 @@
 			BUG_ON(cgrp->subsys[i]->cgroup != cgrp);
 			mutex_lock(&ss->hierarchy_mutex);
 			if (ss->bind)
-				ss->bind(ss, dummytop);
+				ss->bind(dummytop);
 			dummytop->subsys[i]->cgroup = dummytop;
 			cgrp->subsys[i] = NULL;
 			subsys[i]->root = &rootnode;
@@ -1763,6 +1763,7 @@
 struct task_and_cgroup {
 	struct task_struct	*task;
 	struct cgroup		*cgrp;
+	struct css_set		*cg;
 };
 
 struct cgroup_taskset {
@@ -1843,11 +1844,10 @@
  * will already exist. If not set, this function might sleep, and can fail with
  * -ENOMEM. Must be called with cgroup_mutex and threadgroup locked.
  */
-static int cgroup_task_migrate(struct cgroup *cgrp, struct cgroup *oldcgrp,
-			       struct task_struct *tsk, bool guarantee)
+static void cgroup_task_migrate(struct cgroup *cgrp, struct cgroup *oldcgrp,
+				struct task_struct *tsk, struct css_set *newcg)
 {
 	struct css_set *oldcg;
-	struct css_set *newcg;
 
 	/*
 	 * We are synchronized through threadgroup_lock() against PF_EXITING
@@ -1857,23 +1857,6 @@
 	WARN_ON_ONCE(tsk->flags & PF_EXITING);
 	oldcg = tsk->cgroups;
 
-	/* locate or allocate a new css_set for this task. */
-	if (guarantee) {
-		/* we know the css_set we want already exists. */
-		struct cgroup_subsys_state *template[CGROUP_SUBSYS_COUNT];
-		read_lock(&css_set_lock);
-		newcg = find_existing_css_set(oldcg, cgrp, template);
-		BUG_ON(!newcg);
-		get_css_set(newcg);
-		read_unlock(&css_set_lock);
-	} else {
-		might_sleep();
-		/* find_css_set will give us newcg already referenced. */
-		newcg = find_css_set(oldcg, cgrp);
-		if (!newcg)
-			return -ENOMEM;
-	}
-
 	task_lock(tsk);
 	rcu_assign_pointer(tsk->cgroups, newcg);
 	task_unlock(tsk);
@@ -1892,7 +1875,6 @@
 	put_css_set(oldcg);
 
 	set_bit(CGRP_RELEASABLE, &oldcgrp->flags);
-	return 0;
 }
 
 /**
@@ -1910,6 +1892,7 @@
 	struct cgroup *oldcgrp;
 	struct cgroupfs_root *root = cgrp->root;
 	struct cgroup_taskset tset = { };
+	struct css_set *newcg;
 
 	/* @tsk either already exited or can't exit until the end */
 	if (tsk->flags & PF_EXITING)
@@ -1925,7 +1908,7 @@
 
 	for_each_subsys(root, ss) {
 		if (ss->can_attach) {
-			retval = ss->can_attach(ss, cgrp, &tset);
+			retval = ss->can_attach(cgrp, &tset);
 			if (retval) {
 				/*
 				 * Remember on which subsystem the can_attach()
@@ -1939,13 +1922,17 @@
 		}
 	}
 
-	retval = cgroup_task_migrate(cgrp, oldcgrp, tsk, false);
-	if (retval)
+	newcg = find_css_set(tsk->cgroups, cgrp);
+	if (!newcg) {
+		retval = -ENOMEM;
 		goto out;
+	}
+
+	cgroup_task_migrate(cgrp, oldcgrp, tsk, newcg);
 
 	for_each_subsys(root, ss) {
 		if (ss->attach)
-			ss->attach(ss, cgrp, &tset);
+			ss->attach(cgrp, &tset);
 	}
 
 	synchronize_rcu();
@@ -1967,7 +1954,7 @@
 				 */
 				break;
 			if (ss->cancel_attach)
-				ss->cancel_attach(ss, cgrp, &tset);
+				ss->cancel_attach(cgrp, &tset);
 		}
 	}
 	return retval;
@@ -1997,66 +1984,6 @@
 }
 EXPORT_SYMBOL_GPL(cgroup_attach_task_all);
 
-/*
- * cgroup_attach_proc works in two stages, the first of which prefetches all
- * new css_sets needed (to make sure we have enough memory before committing
- * to the move) and stores them in a list of entries of the following type.
- * TODO: possible optimization: use css_set->rcu_head for chaining instead
- */
-struct cg_list_entry {
-	struct css_set *cg;
-	struct list_head links;
-};
-
-static bool css_set_check_fetched(struct cgroup *cgrp,
-				  struct task_struct *tsk, struct css_set *cg,
-				  struct list_head *newcg_list)
-{
-	struct css_set *newcg;
-	struct cg_list_entry *cg_entry;
-	struct cgroup_subsys_state *template[CGROUP_SUBSYS_COUNT];
-
-	read_lock(&css_set_lock);
-	newcg = find_existing_css_set(cg, cgrp, template);
-	read_unlock(&css_set_lock);
-
-	/* doesn't exist at all? */
-	if (!newcg)
-		return false;
-	/* see if it's already in the list */
-	list_for_each_entry(cg_entry, newcg_list, links)
-		if (cg_entry->cg == newcg)
-			return true;
-
-	/* not found */
-	return false;
-}
-
-/*
- * Find the new css_set and store it in the list in preparation for moving the
- * given task to the given cgroup. Returns 0 or -ENOMEM.
- */
-static int css_set_prefetch(struct cgroup *cgrp, struct css_set *cg,
-			    struct list_head *newcg_list)
-{
-	struct css_set *newcg;
-	struct cg_list_entry *cg_entry;
-
-	/* ensure a new css_set will exist for this thread */
-	newcg = find_css_set(cg, cgrp);
-	if (!newcg)
-		return -ENOMEM;
-	/* add it to the list */
-	cg_entry = kmalloc(sizeof(struct cg_list_entry), GFP_KERNEL);
-	if (!cg_entry) {
-		put_css_set(newcg);
-		return -ENOMEM;
-	}
-	cg_entry->cg = newcg;
-	list_add(&cg_entry->links, newcg_list);
-	return 0;
-}
-
 /**
  * cgroup_attach_proc - attach all threads in a threadgroup to a cgroup
  * @cgrp: the cgroup to attach to
@@ -2070,20 +1997,12 @@
 	int retval, i, group_size;
 	struct cgroup_subsys *ss, *failed_ss = NULL;
 	/* guaranteed to be initialized later, but the compiler needs this */
-	struct css_set *oldcg;
 	struct cgroupfs_root *root = cgrp->root;
 	/* threadgroup list cursor and array */
 	struct task_struct *tsk;
 	struct task_and_cgroup *tc;
 	struct flex_array *group;
 	struct cgroup_taskset tset = { };
-	/*
-	 * we need to make sure we have css_sets for all the tasks we're
-	 * going to move -before- we actually start moving them, so that in
-	 * case we get an ENOMEM we can bail out before making any changes.
-	 */
-	struct list_head newcg_list;
-	struct cg_list_entry *cg_entry, *temp_nobe;
 
 	/*
 	 * step 0: in order to do expensive, possibly blocking operations for
@@ -2102,23 +2021,14 @@
 	if (retval)
 		goto out_free_group_list;
 
-	/* prevent changes to the threadgroup list while we take a snapshot. */
-	read_lock(&tasklist_lock);
-	if (!thread_group_leader(leader)) {
-		/*
-		 * a race with de_thread from another thread's exec() may strip
-		 * us of our leadership, making while_each_thread unsafe to use
-		 * on this task. if this happens, there is no choice but to
-		 * throw this task away and try again (from cgroup_procs_write);
-		 * this is "double-double-toil-and-trouble-check locking".
-		 */
-		read_unlock(&tasklist_lock);
-		retval = -EAGAIN;
-		goto out_free_group_list;
-	}
-
 	tsk = leader;
 	i = 0;
+	/*
+	 * Prevent freeing of tasks while we take a snapshot. Tasks that are
+	 * already PF_EXITING could be freed from underneath us unless we
+	 * take an rcu_read_lock.
+	 */
+	rcu_read_lock();
 	do {
 		struct task_and_cgroup ent;
 
@@ -2128,24 +2038,24 @@
 
 		/* as per above, nr_threads may decrease, but not increase. */
 		BUG_ON(i >= group_size);
-		/*
-		 * saying GFP_ATOMIC has no effect here because we did prealloc
-		 * earlier, but it's good form to communicate our expectations.
-		 */
 		ent.task = tsk;
 		ent.cgrp = task_cgroup_from_root(tsk, root);
 		/* nothing to do if this task is already in the cgroup */
 		if (ent.cgrp == cgrp)
 			continue;
+		/*
+		 * saying GFP_ATOMIC has no effect here because we did prealloc
+		 * earlier, but it's good form to communicate our expectations.
+		 */
 		retval = flex_array_put(group, i, &ent, GFP_ATOMIC);
 		BUG_ON(retval != 0);
 		i++;
 	} while_each_thread(leader, tsk);
+	rcu_read_unlock();
 	/* remember the number of threads in the array for later. */
 	group_size = i;
 	tset.tc_array = group;
 	tset.tc_array_len = group_size;
-	read_unlock(&tasklist_lock);
 
 	/* methods shouldn't be called if no task is actually migrating */
 	retval = 0;
@@ -2157,7 +2067,7 @@
 	 */
 	for_each_subsys(root, ss) {
 		if (ss->can_attach) {
-			retval = ss->can_attach(ss, cgrp, &tset);
+			retval = ss->can_attach(cgrp, &tset);
 			if (retval) {
 				failed_ss = ss;
 				goto out_cancel_attach;
@@ -2169,17 +2079,12 @@
 	 * step 2: make sure css_sets exist for all threads to be migrated.
 	 * we use find_css_set, which allocates a new one if necessary.
 	 */
-	INIT_LIST_HEAD(&newcg_list);
 	for (i = 0; i < group_size; i++) {
 		tc = flex_array_get(group, i);
-		oldcg = tc->task->cgroups;
-
-		/* if we don't already have it in the list get a new one */
-		if (!css_set_check_fetched(cgrp, tc->task, oldcg,
-					   &newcg_list)) {
-			retval = css_set_prefetch(cgrp, oldcg, &newcg_list);
-			if (retval)
-				goto out_list_teardown;
+		tc->cg = find_css_set(tc->task->cgroups, cgrp);
+		if (!tc->cg) {
+			retval = -ENOMEM;
+			goto out_put_css_set_refs;
 		}
 	}
 
@@ -2190,8 +2095,7 @@
 	 */
 	for (i = 0; i < group_size; i++) {
 		tc = flex_array_get(group, i);
-		retval = cgroup_task_migrate(cgrp, tc->cgrp, tc->task, true);
-		BUG_ON(retval);
+		cgroup_task_migrate(cgrp, tc->cgrp, tc->task, tc->cg);
 	}
 	/* nothing is sensitive to fork() after this point. */
 
@@ -2200,7 +2104,7 @@
 	 */
 	for_each_subsys(root, ss) {
 		if (ss->attach)
-			ss->attach(ss, cgrp, &tset);
+			ss->attach(cgrp, &tset);
 	}
 
 	/*
@@ -2209,21 +2113,22 @@
 	synchronize_rcu();
 	cgroup_wakeup_rmdir_waiter(cgrp);
 	retval = 0;
-out_list_teardown:
-	/* clean up the list of prefetched css_sets. */
-	list_for_each_entry_safe(cg_entry, temp_nobe, &newcg_list, links) {
-		list_del(&cg_entry->links);
-		put_css_set(cg_entry->cg);
-		kfree(cg_entry);
+out_put_css_set_refs:
+	if (retval) {
+		for (i = 0; i < group_size; i++) {
+			tc = flex_array_get(group, i);
+			if (!tc->cg)
+				break;
+			put_css_set(tc->cg);
+		}
 	}
 out_cancel_attach:
-	/* same deal as in cgroup_attach_task */
 	if (retval) {
 		for_each_subsys(root, ss) {
 			if (ss == failed_ss)
 				break;
 			if (ss->cancel_attach)
-				ss->cancel_attach(ss, cgrp, &tset);
+				ss->cancel_attach(cgrp, &tset);
 		}
 	}
 out_free_group_list:
@@ -2245,22 +2150,14 @@
 	if (!cgroup_lock_live_group(cgrp))
 		return -ENODEV;
 
+retry_find_task:
+	rcu_read_lock();
 	if (pid) {
-		rcu_read_lock();
 		tsk = find_task_by_vpid(pid);
 		if (!tsk) {
 			rcu_read_unlock();
-			cgroup_unlock();
-			return -ESRCH;
-		}
-		if (threadgroup) {
-			/*
-			 * RCU protects this access, since tsk was found in the
-			 * tid map. a race with de_thread may cause group_leader
-			 * to stop being the leader, but cgroup_attach_proc will
-			 * detect it later.
-			 */
-			tsk = tsk->group_leader;
+			ret= -ESRCH;
+			goto out_unlock_cgroup;
 		}
 		/*
 		 * even if we're attaching all tasks in the thread group, we
@@ -2271,29 +2168,38 @@
 		    cred->euid != tcred->uid &&
 		    cred->euid != tcred->suid) {
 			rcu_read_unlock();
-			cgroup_unlock();
-			return -EACCES;
+			ret = -EACCES;
+			goto out_unlock_cgroup;
 		}
-		get_task_struct(tsk);
-		rcu_read_unlock();
-	} else {
-		if (threadgroup)
-			tsk = current->group_leader;
-		else
-			tsk = current;
-		get_task_struct(tsk);
-	}
-
-	threadgroup_lock(tsk);
+	} else
+		tsk = current;
 
 	if (threadgroup)
-		ret = cgroup_attach_proc(cgrp, tsk);
-	else
-		ret = cgroup_attach_task(cgrp, tsk);
+		tsk = tsk->group_leader;
+	get_task_struct(tsk);
+	rcu_read_unlock();
 
+	threadgroup_lock(tsk);
+	if (threadgroup) {
+		if (!thread_group_leader(tsk)) {
+			/*
+			 * a race with de_thread from another thread's exec()
+			 * may strip us of our leadership, if this happens,
+			 * there is no choice but to throw this task away and
+			 * try again; this is
+			 * "double-double-toil-and-trouble-check locking".
+			 */
+			threadgroup_unlock(tsk);
+			put_task_struct(tsk);
+			goto retry_find_task;
+		}
+		ret = cgroup_attach_proc(cgrp, tsk);
+	} else
+		ret = cgroup_attach_task(cgrp, tsk);
 	threadgroup_unlock(tsk);
 
 	put_task_struct(tsk);
+out_unlock_cgroup:
 	cgroup_unlock();
 	return ret;
 }
@@ -2305,16 +2211,7 @@
 
 static int cgroup_procs_write(struct cgroup *cgrp, struct cftype *cft, u64 tgid)
 {
-	int ret;
-	do {
-		/*
-		 * attach_proc fails with -EAGAIN if threadgroup leadership
-		 * changes in the middle of the operation, in which case we need
-		 * to find the task_struct for the new leader and start over.
-		 */
-		ret = attach_task_by_pid(cgrp, tgid, true);
-	} while (ret == -EAGAIN);
-	return ret;
+	return attach_task_by_pid(cgrp, tgid, true);
 }
 
 /**
@@ -2804,15 +2701,20 @@
  * using their cgroups capability, we don't maintain the lists running
  * through each css_set to its tasks until we see the list actually
  * used - in other words after the first call to cgroup_iter_start().
- *
- * The tasklist_lock is not held here, as do_each_thread() and
- * while_each_thread() are protected by RCU.
  */
 static void cgroup_enable_task_cg_lists(void)
 {
 	struct task_struct *p, *g;
 	write_lock(&css_set_lock);
 	use_task_css_set_links = 1;
+	/*
+	 * We need tasklist_lock because RCU is not safe against
+	 * while_each_thread(). Besides, a forking task that has passed
+	 * cgroup_post_fork() without seeing use_task_css_set_links = 1
+	 * is not guaranteed to have its child immediately visible in the
+	 * tasklist if we walk through it with RCU.
+	 */
+	read_lock(&tasklist_lock);
 	do_each_thread(g, p) {
 		task_lock(p);
 		/*
@@ -2824,6 +2726,7 @@
 			list_add(&p->cg_list, &p->cgroups->tasks);
 		task_unlock(p);
 	} while_each_thread(g, p);
+	read_unlock(&tasklist_lock);
 	write_unlock(&css_set_lock);
 }
 
@@ -3043,6 +2946,38 @@
  *
  */
 
+/* which pidlist file are we talking about? */
+enum cgroup_filetype {
+	CGROUP_FILE_PROCS,
+	CGROUP_FILE_TASKS,
+};
+
+/*
+ * A pidlist is a list of pids that virtually represents the contents of one
+ * of the cgroup files ("procs" or "tasks"). We keep a list of such pidlists,
+ * a pair (one each for procs, tasks) for each pid namespace that's relevant
+ * to the cgroup.
+ */
+struct cgroup_pidlist {
+	/*
+	 * used to find which pidlist is wanted. doesn't change as long as
+	 * this particular list stays in the list.
+	*/
+	struct { enum cgroup_filetype type; struct pid_namespace *ns; } key;
+	/* array of xids */
+	pid_t *list;
+	/* how many elements the above list has */
+	int length;
+	/* how many files are using the current array */
+	int use_count;
+	/* each of these stored in a list by its cgroup */
+	struct list_head links;
+	/* pointer to the cgroup we belong to, for list removal purposes */
+	struct cgroup *owner;
+	/* protects the other fields */
+	struct rw_semaphore mutex;
+};
+
 /*
  * The following two functions "fix" the issue where there are more pids
  * than kmalloc will give memory for; in such cases, we use vmalloc/vfree.
@@ -3827,7 +3762,7 @@
 		set_bit(CGRP_CLONE_CHILDREN, &cgrp->flags);
 
 	for_each_subsys(root, ss) {
-		struct cgroup_subsys_state *css = ss->create(ss, cgrp);
+		struct cgroup_subsys_state *css = ss->create(cgrp);
 
 		if (IS_ERR(css)) {
 			err = PTR_ERR(css);
@@ -3841,7 +3776,7 @@
 		}
 		/* At error, ->destroy() callback has to free assigned ID. */
 		if (clone_children(parent) && ss->post_clone)
-			ss->post_clone(ss, cgrp);
+			ss->post_clone(cgrp);
 	}
 
 	cgroup_lock_hierarchy(root);
@@ -3875,7 +3810,7 @@
 
 	for_each_subsys(root, ss) {
 		if (cgrp->subsys[ss->subsys_id])
-			ss->destroy(ss, cgrp);
+			ss->destroy(cgrp);
 	}
 
 	mutex_unlock(&cgroup_mutex);
@@ -4099,7 +4034,7 @@
 	/* Create the top cgroup state for this subsystem */
 	list_add(&ss->sibling, &rootnode.subsys_list);
 	ss->root = &rootnode;
-	css = ss->create(ss, dummytop);
+	css = ss->create(dummytop);
 	/* We don't handle early failures gracefully */
 	BUG_ON(IS_ERR(css));
 	init_cgroup_css(css, ss, dummytop);
@@ -4188,7 +4123,7 @@
 	 * no ss->create seems to need anything important in the ss struct, so
 	 * this can happen first (i.e. before the rootnode attachment).
 	 */
-	css = ss->create(ss, dummytop);
+	css = ss->create(dummytop);
 	if (IS_ERR(css)) {
 		/* failure case - need to deassign the subsys[] slot. */
 		subsys[i] = NULL;
@@ -4206,7 +4141,7 @@
 		int ret = cgroup_init_idr(ss, css);
 		if (ret) {
 			dummytop->subsys[ss->subsys_id] = NULL;
-			ss->destroy(ss, dummytop);
+			ss->destroy(dummytop);
 			subsys[i] = NULL;
 			mutex_unlock(&cgroup_mutex);
 			return ret;
@@ -4304,7 +4239,7 @@
 	 * pointer to find their state. note that this also takes care of
 	 * freeing the css_id.
 	 */
-	ss->destroy(ss, dummytop);
+	ss->destroy(dummytop);
 	dummytop->subsys[ss->subsys_id] = NULL;
 
 	mutex_unlock(&cgroup_mutex);
@@ -4580,7 +4515,7 @@
 		for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
 			struct cgroup_subsys *ss = subsys[i];
 			if (ss->fork)
-				ss->fork(ss, child);
+				ss->fork(child);
 		}
 	}
 }
@@ -4596,6 +4531,17 @@
  */
 void cgroup_post_fork(struct task_struct *child)
 {
+	/*
+	 * use_task_css_set_links is set to 1 before we walk the tasklist
+	 * under the tasklist_lock and we read it here after we added the child
+	 * to the tasklist under the tasklist_lock as well. If the child wasn't
+	 * yet in the tasklist when we walked through it from
+	 * cgroup_enable_task_cg_lists(), then use_task_css_set_links value
+	 * should be visible now due to the paired locking and barriers implied
+	 * by LOCK/UNLOCK: it is written before the tasklist_lock unlock
+	 * in cgroup_enable_task_cg_lists() and read here after the tasklist_lock
+	 * lock on fork.
+	 */
 	if (use_task_css_set_links) {
 		write_lock(&css_set_lock);
 		if (list_empty(&child->cg_list)) {
@@ -4682,7 +4628,7 @@
 				struct cgroup *old_cgrp =
 					rcu_dereference_raw(cg->subsys[i])->cgroup;
 				struct cgroup *cgrp = task_cgroup(tsk, i);
-				ss->exit(ss, cgrp, old_cgrp, tsk);
+				ss->exit(cgrp, old_cgrp, tsk);
 			}
 		}
 	}
@@ -5137,8 +5083,7 @@
 }
 
 #ifdef CONFIG_CGROUP_DEBUG
-static struct cgroup_subsys_state *debug_create(struct cgroup_subsys *ss,
-						   struct cgroup *cont)
+static struct cgroup_subsys_state *debug_create(struct cgroup *cont)
 {
 	struct cgroup_subsys_state *css = kzalloc(sizeof(*css), GFP_KERNEL);
 
@@ -5148,7 +5093,7 @@
 	return css;
 }
 
-static void debug_destroy(struct cgroup_subsys *ss, struct cgroup *cont)
+static void debug_destroy(struct cgroup *cont)
 {
 	kfree(cont->subsys[debug_subsys_id]);
 }
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c
index fc0646b..f86e939 100644
--- a/kernel/cgroup_freezer.c
+++ b/kernel/cgroup_freezer.c
@@ -128,8 +128,7 @@
  *    task->alloc_lock (inside __thaw_task(), prevents race with refrigerator())
  *     sighand->siglock
  */
-static struct cgroup_subsys_state *freezer_create(struct cgroup_subsys *ss,
-						  struct cgroup *cgroup)
+static struct cgroup_subsys_state *freezer_create(struct cgroup *cgroup)
 {
 	struct freezer *freezer;
 
@@ -142,8 +141,7 @@
 	return &freezer->css;
 }
 
-static void freezer_destroy(struct cgroup_subsys *ss,
-			    struct cgroup *cgroup)
+static void freezer_destroy(struct cgroup *cgroup)
 {
 	struct freezer *freezer = cgroup_freezer(cgroup);
 
@@ -164,8 +162,7 @@
  * a write to that file racing against an attach, and hence the
  * can_attach() result will remain valid until the attach completes.
  */
-static int freezer_can_attach(struct cgroup_subsys *ss,
-			      struct cgroup *new_cgroup,
+static int freezer_can_attach(struct cgroup *new_cgroup,
 			      struct cgroup_taskset *tset)
 {
 	struct freezer *freezer;
@@ -185,7 +182,7 @@
 	return 0;
 }
 
-static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task)
+static void freezer_fork(struct task_struct *task)
 {
 	struct freezer *freezer;
 
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index a09ac2b..5d57583 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -1399,8 +1399,7 @@
 static nodemask_t cpuset_attach_nodemask_to;
 
 /* Called by cgroups to determine if a cpuset is usable; cgroup_mutex held */
-static int cpuset_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
-			     struct cgroup_taskset *tset)
+static int cpuset_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
 {
 	struct cpuset *cs = cgroup_cs(cgrp);
 	struct task_struct *task;
@@ -1436,8 +1435,7 @@
 	return 0;
 }
 
-static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
-			  struct cgroup_taskset *tset)
+static void cpuset_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
 {
 	struct mm_struct *mm;
 	struct task_struct *task;
@@ -1833,8 +1831,7 @@
  * (and likewise for mems) to the new cgroup. Called with cgroup_mutex
  * held.
  */
-static void cpuset_post_clone(struct cgroup_subsys *ss,
-			      struct cgroup *cgroup)
+static void cpuset_post_clone(struct cgroup *cgroup)
 {
 	struct cgroup *parent, *child;
 	struct cpuset *cs, *parent_cs;
@@ -1857,13 +1854,10 @@
 
 /*
  *	cpuset_create - create a cpuset
- *	ss:	cpuset cgroup subsystem
  *	cont:	control group that the new cpuset will be part of
  */
 
-static struct cgroup_subsys_state *cpuset_create(
-	struct cgroup_subsys *ss,
-	struct cgroup *cont)
+static struct cgroup_subsys_state *cpuset_create(struct cgroup *cont)
 {
 	struct cpuset *cs;
 	struct cpuset *parent;
@@ -1902,7 +1896,7 @@
  * will call async_rebuild_sched_domains().
  */
 
-static void cpuset_destroy(struct cgroup_subsys *ss, struct cgroup *cont)
+static void cpuset_destroy(struct cgroup *cont)
 {
 	struct cpuset *cs = cgroup_cs(cont);
 
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 1b5c081..4b50357 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -118,6 +118,13 @@
 		       PERF_FLAG_FD_OUTPUT  |\
 		       PERF_FLAG_PID_CGROUP)
 
+/*
+ * branch priv levels that need permission checks
+ */
+#define PERF_SAMPLE_BRANCH_PERM_PLM \
+	(PERF_SAMPLE_BRANCH_KERNEL |\
+	 PERF_SAMPLE_BRANCH_HV)
+
 enum event_type_t {
 	EVENT_FLEXIBLE = 0x1,
 	EVENT_PINNED = 0x2,
@@ -128,8 +135,9 @@
  * perf_sched_events : >0 events exist
  * perf_cgroup_events: >0 per-cpu cgroup events exist on this cpu
  */
-struct jump_label_key_deferred perf_sched_events __read_mostly;
+struct static_key_deferred perf_sched_events __read_mostly;
 static DEFINE_PER_CPU(atomic_t, perf_cgroup_events);
+static DEFINE_PER_CPU(atomic_t, perf_branch_stack_events);
 
 static atomic_t nr_mmap_events __read_mostly;
 static atomic_t nr_comm_events __read_mostly;
@@ -881,6 +889,9 @@
 	if (is_cgroup_event(event))
 		ctx->nr_cgroups++;
 
+	if (has_branch_stack(event))
+		ctx->nr_branch_stack++;
+
 	list_add_rcu(&event->event_entry, &ctx->event_list);
 	if (!ctx->nr_events)
 		perf_pmu_rotate_start(ctx->pmu);
@@ -1020,6 +1031,9 @@
 			cpuctx->cgrp = NULL;
 	}
 
+	if (has_branch_stack(event))
+		ctx->nr_branch_stack--;
+
 	ctx->nr_events--;
 	if (event->attr.inherit_stat)
 		ctx->nr_stat--;
@@ -2195,6 +2209,66 @@
 }
 
 /*
+ * When sampling the branck stack in system-wide, it may be necessary
+ * to flush the stack on context switch. This happens when the branch
+ * stack does not tag its entries with the pid of the current task.
+ * Otherwise it becomes impossible to associate a branch entry with a
+ * task. This ambiguity is more likely to appear when the branch stack
+ * supports priv level filtering and the user sets it to monitor only
+ * at the user level (which could be a useful measurement in system-wide
+ * mode). In that case, the risk is high of having a branch stack with
+ * branch from multiple tasks. Flushing may mean dropping the existing
+ * entries or stashing them somewhere in the PMU specific code layer.
+ *
+ * This function provides the context switch callback to the lower code
+ * layer. It is invoked ONLY when there is at least one system-wide context
+ * with at least one active event using taken branch sampling.
+ */
+static void perf_branch_stack_sched_in(struct task_struct *prev,
+				       struct task_struct *task)
+{
+	struct perf_cpu_context *cpuctx;
+	struct pmu *pmu;
+	unsigned long flags;
+
+	/* no need to flush branch stack if not changing task */
+	if (prev == task)
+		return;
+
+	local_irq_save(flags);
+
+	rcu_read_lock();
+
+	list_for_each_entry_rcu(pmu, &pmus, entry) {
+		cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+
+		/*
+		 * check if the context has at least one
+		 * event using PERF_SAMPLE_BRANCH_STACK
+		 */
+		if (cpuctx->ctx.nr_branch_stack > 0
+		    && pmu->flush_branch_stack) {
+
+			pmu = cpuctx->ctx.pmu;
+
+			perf_ctx_lock(cpuctx, cpuctx->task_ctx);
+
+			perf_pmu_disable(pmu);
+
+			pmu->flush_branch_stack();
+
+			perf_pmu_enable(pmu);
+
+			perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
+		}
+	}
+
+	rcu_read_unlock();
+
+	local_irq_restore(flags);
+}
+
+/*
  * Called from scheduler to add the events of the current task
  * with interrupts disabled.
  *
@@ -2225,6 +2299,10 @@
 	 */
 	if (atomic_read(&__get_cpu_var(perf_cgroup_events)))
 		perf_cgroup_sched_in(prev, task);
+
+	/* check for system-wide branch_stack events */
+	if (atomic_read(&__get_cpu_var(perf_branch_stack_events)))
+		perf_branch_stack_sched_in(prev, task);
 }
 
 static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count)
@@ -2778,7 +2856,7 @@
 
 	if (!event->parent) {
 		if (event->attach_state & PERF_ATTACH_TASK)
-			jump_label_dec_deferred(&perf_sched_events);
+			static_key_slow_dec_deferred(&perf_sched_events);
 		if (event->attr.mmap || event->attr.mmap_data)
 			atomic_dec(&nr_mmap_events);
 		if (event->attr.comm)
@@ -2789,7 +2867,15 @@
 			put_callchain_buffers();
 		if (is_cgroup_event(event)) {
 			atomic_dec(&per_cpu(perf_cgroup_events, event->cpu));
-			jump_label_dec_deferred(&perf_sched_events);
+			static_key_slow_dec_deferred(&perf_sched_events);
+		}
+
+		if (has_branch_stack(event)) {
+			static_key_slow_dec_deferred(&perf_sched_events);
+			/* is system-wide event */
+			if (!(event->attach_state & PERF_ATTACH_TASK))
+				atomic_dec(&per_cpu(perf_branch_stack_events,
+						    event->cpu));
 		}
 	}
 
@@ -3238,10 +3324,6 @@
 	return 0;
 }
 
-#ifndef PERF_EVENT_INDEX_OFFSET
-# define PERF_EVENT_INDEX_OFFSET 0
-#endif
-
 static int perf_event_index(struct perf_event *event)
 {
 	if (event->hw.state & PERF_HES_STOPPED)
@@ -3250,21 +3332,26 @@
 	if (event->state != PERF_EVENT_STATE_ACTIVE)
 		return 0;
 
-	return event->hw.idx + 1 - PERF_EVENT_INDEX_OFFSET;
+	return event->pmu->event_idx(event);
 }
 
 static void calc_timer_values(struct perf_event *event,
+				u64 *now,
 				u64 *enabled,
 				u64 *running)
 {
-	u64 now, ctx_time;
+	u64 ctx_time;
 
-	now = perf_clock();
-	ctx_time = event->shadow_ctx_time + now;
+	*now = perf_clock();
+	ctx_time = event->shadow_ctx_time + *now;
 	*enabled = ctx_time - event->tstamp_enabled;
 	*running = ctx_time - event->tstamp_running;
 }
 
+void __weak perf_update_user_clock(struct perf_event_mmap_page *userpg, u64 now)
+{
+}
+
 /*
  * Callers need to ensure there can be no nesting of this function, otherwise
  * the seqlock logic goes bad. We can not serialize this because the arch
@@ -3274,7 +3361,7 @@
 {
 	struct perf_event_mmap_page *userpg;
 	struct ring_buffer *rb;
-	u64 enabled, running;
+	u64 enabled, running, now;
 
 	rcu_read_lock();
 	/*
@@ -3286,7 +3373,7 @@
 	 * because of locking issue as we can be called in
 	 * NMI context
 	 */
-	calc_timer_values(event, &enabled, &running);
+	calc_timer_values(event, &now, &enabled, &running);
 	rb = rcu_dereference(event->rb);
 	if (!rb)
 		goto unlock;
@@ -3302,7 +3389,7 @@
 	barrier();
 	userpg->index = perf_event_index(event);
 	userpg->offset = perf_event_count(event);
-	if (event->state == PERF_EVENT_STATE_ACTIVE)
+	if (userpg->index)
 		userpg->offset -= local64_read(&event->hw.prev_count);
 
 	userpg->time_enabled = enabled +
@@ -3311,6 +3398,8 @@
 	userpg->time_running = running +
 			atomic64_read(&event->child_total_time_running);
 
+	perf_update_user_clock(userpg, now);
+
 	barrier();
 	++userpg->lock;
 	preempt_enable();
@@ -3568,6 +3657,8 @@
 	event->mmap_user = get_current_user();
 	vma->vm_mm->pinned_vm += event->mmap_locked;
 
+	perf_event_update_userpage(event);
+
 unlock:
 	if (!ret)
 		atomic_inc(&event->mmap_count);
@@ -3799,7 +3890,7 @@
 static void perf_output_read(struct perf_output_handle *handle,
 			     struct perf_event *event)
 {
-	u64 enabled = 0, running = 0;
+	u64 enabled = 0, running = 0, now;
 	u64 read_format = event->attr.read_format;
 
 	/*
@@ -3812,7 +3903,7 @@
 	 * NMI context
 	 */
 	if (read_format & PERF_FORMAT_TOTAL_TIMES)
-		calc_timer_values(event, &enabled, &running);
+		calc_timer_values(event, &now, &enabled, &running);
 
 	if (event->attr.read_format & PERF_FORMAT_GROUP)
 		perf_output_read_group(handle, event, enabled, running);
@@ -3902,6 +3993,24 @@
 			}
 		}
 	}
+
+	if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
+		if (data->br_stack) {
+			size_t size;
+
+			size = data->br_stack->nr
+			     * sizeof(struct perf_branch_entry);
+
+			perf_output_put(handle, data->br_stack->nr);
+			perf_output_copy(handle, data->br_stack->entries, size);
+		} else {
+			/*
+			 * we always store at least the value of nr
+			 */
+			u64 nr = 0;
+			perf_output_put(handle, nr);
+		}
+	}
 }
 
 void perf_prepare_sample(struct perf_event_header *header,
@@ -3944,6 +4053,15 @@
 		WARN_ON_ONCE(size & (sizeof(u64)-1));
 		header->size += size;
 	}
+
+	if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
+		int size = sizeof(u64); /* nr */
+		if (data->br_stack) {
+			size += data->br_stack->nr
+			      * sizeof(struct perf_branch_entry);
+		}
+		header->size += size;
+	}
 }
 
 static void perf_event_output(struct perf_event *event,
@@ -4986,7 +5104,7 @@
 	return err;
 }
 
-struct jump_label_key perf_swevent_enabled[PERF_COUNT_SW_MAX];
+struct static_key perf_swevent_enabled[PERF_COUNT_SW_MAX];
 
 static void sw_perf_event_destroy(struct perf_event *event)
 {
@@ -4994,7 +5112,7 @@
 
 	WARN_ON(event->parent);
 
-	jump_label_dec(&perf_swevent_enabled[event_id]);
+	static_key_slow_dec(&perf_swevent_enabled[event_id]);
 	swevent_hlist_put(event);
 }
 
@@ -5005,6 +5123,12 @@
 	if (event->attr.type != PERF_TYPE_SOFTWARE)
 		return -ENOENT;
 
+	/*
+	 * no branch sampling for software events
+	 */
+	if (has_branch_stack(event))
+		return -EOPNOTSUPP;
+
 	switch (event_id) {
 	case PERF_COUNT_SW_CPU_CLOCK:
 	case PERF_COUNT_SW_TASK_CLOCK:
@@ -5024,13 +5148,18 @@
 		if (err)
 			return err;
 
-		jump_label_inc(&perf_swevent_enabled[event_id]);
+		static_key_slow_inc(&perf_swevent_enabled[event_id]);
 		event->destroy = sw_perf_event_destroy;
 	}
 
 	return 0;
 }
 
+static int perf_swevent_event_idx(struct perf_event *event)
+{
+	return 0;
+}
+
 static struct pmu perf_swevent = {
 	.task_ctx_nr	= perf_sw_context,
 
@@ -5040,6 +5169,8 @@
 	.start		= perf_swevent_start,
 	.stop		= perf_swevent_stop,
 	.read		= perf_swevent_read,
+
+	.event_idx	= perf_swevent_event_idx,
 };
 
 #ifdef CONFIG_EVENT_TRACING
@@ -5108,6 +5239,12 @@
 	if (event->attr.type != PERF_TYPE_TRACEPOINT)
 		return -ENOENT;
 
+	/*
+	 * no branch sampling for tracepoint events
+	 */
+	if (has_branch_stack(event))
+		return -EOPNOTSUPP;
+
 	err = perf_trace_init(event);
 	if (err)
 		return err;
@@ -5126,6 +5263,8 @@
 	.start		= perf_swevent_start,
 	.stop		= perf_swevent_stop,
 	.read		= perf_swevent_read,
+
+	.event_idx	= perf_swevent_event_idx,
 };
 
 static inline void perf_tp_register(void)
@@ -5331,6 +5470,12 @@
 	if (event->attr.config != PERF_COUNT_SW_CPU_CLOCK)
 		return -ENOENT;
 
+	/*
+	 * no branch sampling for software events
+	 */
+	if (has_branch_stack(event))
+		return -EOPNOTSUPP;
+
 	perf_swevent_init_hrtimer(event);
 
 	return 0;
@@ -5345,6 +5490,8 @@
 	.start		= cpu_clock_event_start,
 	.stop		= cpu_clock_event_stop,
 	.read		= cpu_clock_event_read,
+
+	.event_idx	= perf_swevent_event_idx,
 };
 
 /*
@@ -5403,6 +5550,12 @@
 	if (event->attr.config != PERF_COUNT_SW_TASK_CLOCK)
 		return -ENOENT;
 
+	/*
+	 * no branch sampling for software events
+	 */
+	if (has_branch_stack(event))
+		return -EOPNOTSUPP;
+
 	perf_swevent_init_hrtimer(event);
 
 	return 0;
@@ -5417,6 +5570,8 @@
 	.start		= task_clock_event_start,
 	.stop		= task_clock_event_stop,
 	.read		= task_clock_event_read,
+
+	.event_idx	= perf_swevent_event_idx,
 };
 
 static void perf_pmu_nop_void(struct pmu *pmu)
@@ -5444,6 +5599,11 @@
 	perf_pmu_enable(pmu);
 }
 
+static int perf_event_idx_default(struct perf_event *event)
+{
+	return event->hw.idx + 1;
+}
+
 /*
  * Ensures all contexts with the same task_ctx_nr have the same
  * pmu_cpu_context too.
@@ -5530,6 +5690,7 @@
 	if (!pmu->dev)
 		goto out;
 
+	pmu->dev->groups = pmu->attr_groups;
 	device_initialize(pmu->dev);
 	ret = dev_set_name(pmu->dev, "%s", pmu->name);
 	if (ret)
@@ -5633,6 +5794,9 @@
 		pmu->pmu_disable = perf_pmu_nop_void;
 	}
 
+	if (!pmu->event_idx)
+		pmu->event_idx = perf_event_idx_default;
+
 	list_add_rcu(&pmu->entry, &pmus);
 	ret = 0;
 unlock:
@@ -5825,7 +5989,7 @@
 
 	if (!event->parent) {
 		if (event->attach_state & PERF_ATTACH_TASK)
-			jump_label_inc(&perf_sched_events.key);
+			static_key_slow_inc(&perf_sched_events.key);
 		if (event->attr.mmap || event->attr.mmap_data)
 			atomic_inc(&nr_mmap_events);
 		if (event->attr.comm)
@@ -5839,6 +6003,12 @@
 				return ERR_PTR(err);
 			}
 		}
+		if (has_branch_stack(event)) {
+			static_key_slow_inc(&perf_sched_events.key);
+			if (!(event->attach_state & PERF_ATTACH_TASK))
+				atomic_inc(&per_cpu(perf_branch_stack_events,
+						    event->cpu));
+		}
 	}
 
 	return event;
@@ -5908,6 +6078,40 @@
 	if (attr->read_format & ~(PERF_FORMAT_MAX-1))
 		return -EINVAL;
 
+	if (attr->sample_type & PERF_SAMPLE_BRANCH_STACK) {
+		u64 mask = attr->branch_sample_type;
+
+		/* only using defined bits */
+		if (mask & ~(PERF_SAMPLE_BRANCH_MAX-1))
+			return -EINVAL;
+
+		/* at least one branch bit must be set */
+		if (!(mask & ~PERF_SAMPLE_BRANCH_PLM_ALL))
+			return -EINVAL;
+
+		/* kernel level capture: check permissions */
+		if ((mask & PERF_SAMPLE_BRANCH_PERM_PLM)
+		    && perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN))
+			return -EACCES;
+
+		/* propagate priv level, when not set for branch */
+		if (!(mask & PERF_SAMPLE_BRANCH_PLM_ALL)) {
+
+			/* exclude_kernel checked on syscall entry */
+			if (!attr->exclude_kernel)
+				mask |= PERF_SAMPLE_BRANCH_KERNEL;
+
+			if (!attr->exclude_user)
+				mask |= PERF_SAMPLE_BRANCH_USER;
+
+			if (!attr->exclude_hv)
+				mask |= PERF_SAMPLE_BRANCH_HV;
+			/*
+			 * adjust user setting (for HW filter setup)
+			 */
+			attr->branch_sample_type = mask;
+		}
+	}
 out:
 	return ret;
 
@@ -6063,7 +6267,7 @@
 		 * - that may need work on context switch
 		 */
 		atomic_inc(&per_cpu(perf_cgroup_events, event->cpu));
-		jump_label_inc(&perf_sched_events.key);
+		static_key_slow_inc(&perf_sched_events.key);
 	}
 
 	/*
@@ -6943,8 +7147,7 @@
 device_initcall(perf_event_sysfs_init);
 
 #ifdef CONFIG_CGROUP_PERF
-static struct cgroup_subsys_state *perf_cgroup_create(
-	struct cgroup_subsys *ss, struct cgroup *cont)
+static struct cgroup_subsys_state *perf_cgroup_create(struct cgroup *cont)
 {
 	struct perf_cgroup *jc;
 
@@ -6961,8 +7164,7 @@
 	return &jc->css;
 }
 
-static void perf_cgroup_destroy(struct cgroup_subsys *ss,
-				struct cgroup *cont)
+static void perf_cgroup_destroy(struct cgroup *cont)
 {
 	struct perf_cgroup *jc;
 	jc = container_of(cgroup_subsys_state(cont, perf_subsys_id),
@@ -6978,8 +7180,7 @@
 	return 0;
 }
 
-static void perf_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
-			       struct cgroup_taskset *tset)
+static void perf_cgroup_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
 {
 	struct task_struct *task;
 
@@ -6987,8 +7188,8 @@
 		task_function_call(task, __perf_cgroup_move, task);
 }
 
-static void perf_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp,
-		struct cgroup *old_cgrp, struct task_struct *task)
+static void perf_cgroup_exit(struct cgroup *cgrp, struct cgroup *old_cgrp,
+			     struct task_struct *task)
 {
 	/*
 	 * cgroup_exit() is called in the copy_process() failure path.
diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c
index ee706ce..bb38c4d 100644
--- a/kernel/events/hw_breakpoint.c
+++ b/kernel/events/hw_breakpoint.c
@@ -581,6 +581,12 @@
 	if (bp->attr.type != PERF_TYPE_BREAKPOINT)
 		return -ENOENT;
 
+	/*
+	 * no branch sampling for breakpoint events
+	 */
+	if (has_branch_stack(bp))
+		return -EOPNOTSUPP;
+
 	err = register_perf_hw_breakpoint(bp);
 	if (err)
 		return err;
@@ -613,6 +619,11 @@
 	bp->hw.state = PERF_HES_STOPPED;
 }
 
+static int hw_breakpoint_event_idx(struct perf_event *bp)
+{
+	return 0;
+}
+
 static struct pmu perf_breakpoint = {
 	.task_ctx_nr	= perf_sw_context, /* could eventually get its own */
 
@@ -622,6 +633,8 @@
 	.start		= hw_breakpoint_start,
 	.stop		= hw_breakpoint_stop,
 	.read		= hw_breakpoint_pmu_read,
+
+	.event_idx	= hw_breakpoint_event_idx,
 };
 
 int __init init_hw_breakpoint(void)
diff --git a/kernel/exit.c b/kernel/exit.c
index 4b4042f..ce5f758 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -818,25 +818,6 @@
 	if (group_dead)
 		kill_orphaned_pgrp(tsk->group_leader, NULL);
 
-	/* Let father know we died
-	 *
-	 * Thread signals are configurable, but you aren't going to use
-	 * that to send signals to arbitrary processes.
-	 * That stops right now.
-	 *
-	 * If the parent exec id doesn't match the exec id we saved
-	 * when we started then we know the parent has changed security
-	 * domain.
-	 *
-	 * If our self_exec id doesn't match our parent_exec_id then
-	 * we have changed execution domain as these two values started
-	 * the same after a fork.
-	 */
-	if (thread_group_leader(tsk) && tsk->exit_signal != SIGCHLD &&
-	    (tsk->parent_exec_id != tsk->real_parent->self_exec_id ||
-	     tsk->self_exec_id != tsk->parent_exec_id))
-		tsk->exit_signal = SIGCHLD;
-
 	if (unlikely(tsk->ptrace)) {
 		int sig = thread_group_leader(tsk) &&
 				thread_group_empty(tsk) &&
@@ -935,8 +916,6 @@
 		schedule();
 	}
 
-	exit_irq_thread();
-
 	exit_signals(tsk);  /* sets PF_EXITING */
 	/*
 	 * tsk->flags are checked in the futex code to protect against
@@ -945,6 +924,8 @@
 	smp_mb();
 	raw_spin_unlock_wait(&tsk->pi_lock);
 
+	exit_irq_thread();
+
 	if (unlikely(in_atomic()))
 		printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n",
 				current->comm, task_pid_nr(current),
diff --git a/kernel/fork.c b/kernel/fork.c
index 26a7a67..c4f38a8 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1340,7 +1340,13 @@
 	clear_all_latency_tracing(p);
 
 	/* ok, now we should be set up.. */
-	p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL);
+	if (clone_flags & CLONE_THREAD)
+		p->exit_signal = -1;
+	else if (clone_flags & CLONE_PARENT)
+		p->exit_signal = current->group_leader->exit_signal;
+	else
+		p->exit_signal = (clone_flags & CSIGNAL);
+
 	p->pdeath_signal = 0;
 	p->exit_state = 0;
 
diff --git a/kernel/futex.c b/kernel/futex.c
index 1614be2..72efa1e 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -2628,7 +2628,7 @@
 long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
 		u32 __user *uaddr2, u32 val2, u32 val3)
 {
-	int ret = -ENOSYS, cmd = op & FUTEX_CMD_MASK;
+	int cmd = op & FUTEX_CMD_MASK;
 	unsigned int flags = 0;
 
 	if (!(op & FUTEX_PRIVATE_FLAG))
@@ -2641,49 +2641,44 @@
 	}
 
 	switch (cmd) {
+	case FUTEX_LOCK_PI:
+	case FUTEX_UNLOCK_PI:
+	case FUTEX_TRYLOCK_PI:
+	case FUTEX_WAIT_REQUEUE_PI:
+	case FUTEX_CMP_REQUEUE_PI:
+		if (!futex_cmpxchg_enabled)
+			return -ENOSYS;
+	}
+
+	switch (cmd) {
 	case FUTEX_WAIT:
 		val3 = FUTEX_BITSET_MATCH_ANY;
 	case FUTEX_WAIT_BITSET:
-		ret = futex_wait(uaddr, flags, val, timeout, val3);
-		break;
+		return futex_wait(uaddr, flags, val, timeout, val3);
 	case FUTEX_WAKE:
 		val3 = FUTEX_BITSET_MATCH_ANY;
 	case FUTEX_WAKE_BITSET:
-		ret = futex_wake(uaddr, flags, val, val3);
-		break;
+		return futex_wake(uaddr, flags, val, val3);
 	case FUTEX_REQUEUE:
-		ret = futex_requeue(uaddr, flags, uaddr2, val, val2, NULL, 0);
-		break;
+		return futex_requeue(uaddr, flags, uaddr2, val, val2, NULL, 0);
 	case FUTEX_CMP_REQUEUE:
-		ret = futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 0);
-		break;
+		return futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 0);
 	case FUTEX_WAKE_OP:
-		ret = futex_wake_op(uaddr, flags, uaddr2, val, val2, val3);
-		break;
+		return futex_wake_op(uaddr, flags, uaddr2, val, val2, val3);
 	case FUTEX_LOCK_PI:
-		if (futex_cmpxchg_enabled)
-			ret = futex_lock_pi(uaddr, flags, val, timeout, 0);
-		break;
+		return futex_lock_pi(uaddr, flags, val, timeout, 0);
 	case FUTEX_UNLOCK_PI:
-		if (futex_cmpxchg_enabled)
-			ret = futex_unlock_pi(uaddr, flags);
-		break;
+		return futex_unlock_pi(uaddr, flags);
 	case FUTEX_TRYLOCK_PI:
-		if (futex_cmpxchg_enabled)
-			ret = futex_lock_pi(uaddr, flags, 0, timeout, 1);
-		break;
+		return futex_lock_pi(uaddr, flags, 0, timeout, 1);
 	case FUTEX_WAIT_REQUEUE_PI:
 		val3 = FUTEX_BITSET_MATCH_ANY;
-		ret = futex_wait_requeue_pi(uaddr, flags, val, timeout, val3,
-					    uaddr2);
-		break;
+		return futex_wait_requeue_pi(uaddr, flags, val, timeout, val3,
+					     uaddr2);
 	case FUTEX_CMP_REQUEUE_PI:
-		ret = futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 1);
-		break;
-	default:
-		ret = -ENOSYS;
+		return futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 1);
 	}
-	return ret;
+	return -ENOSYS;
 }
 
 
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index fb7db75..6080f6b 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -16,6 +16,8 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 
+#include <trace/events/irq.h>
+
 #include "internals.h"
 
 /**
@@ -61,8 +63,7 @@
 		return -EINVAL;
 
 	type &= IRQ_TYPE_SENSE_MASK;
-	if (type != IRQ_TYPE_NONE)
-		ret = __irq_set_trigger(desc, irq, type);
+	ret = __irq_set_trigger(desc, irq, type);
 	irq_put_desc_busunlock(desc, flags);
 	return ret;
 }
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 470d08c..6ff84e6 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -60,7 +60,7 @@
 	 * device interrupt, so no irq storm is lurking. If the
 	 * RUNTHREAD bit is already set, nothing to do.
 	 */
-	if (test_bit(IRQTF_DIED, &action->thread_flags) ||
+	if ((action->thread->flags & PF_EXITING) ||
 	    test_and_set_bit(IRQTF_RUNTHREAD, &action->thread_flags))
 		return;
 
@@ -110,6 +110,18 @@
 	 * threads_oneshot untouched and runs the thread another time.
 	 */
 	desc->threads_oneshot |= action->thread_mask;
+
+	/*
+	 * We increment the threads_active counter in case we wake up
+	 * the irq thread. The irq thread decrements the counter when
+	 * it returns from the handler or in the exit path and wakes
+	 * up waiters which are stuck in synchronize_irq() when the
+	 * active count becomes zero. synchronize_irq() is serialized
+	 * against this code (hard irq handler) via IRQS_INPROGRESS
+	 * like the finalize_oneshot() code. See comment above.
+	 */
+	atomic_inc(&desc->threads_active);
+
 	wake_up_process(action->thread);
 }
 
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 40378ff..8e5c56b 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -20,14 +20,12 @@
 /*
  * Bits used by threaded handlers:
  * IRQTF_RUNTHREAD - signals that the interrupt handler thread should run
- * IRQTF_DIED      - handler thread died
  * IRQTF_WARNED    - warning "IRQ_WAKE_THREAD w/o thread_fn" has been printed
  * IRQTF_AFFINITY  - irq thread is requested to adjust affinity
  * IRQTF_FORCED_THREAD  - irq action is force threaded
  */
 enum {
 	IRQTF_RUNTHREAD,
-	IRQTF_DIED,
 	IRQTF_WARNED,
 	IRQTF_AFFINITY,
 	IRQTF_FORCED_THREAD,
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 0f0d470..b0ccd1a 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -759,6 +759,13 @@
 	return ret;
 }
 
+static void wake_threads_waitq(struct irq_desc *desc)
+{
+	if (atomic_dec_and_test(&desc->threads_active) &&
+	    waitqueue_active(&desc->wait_for_threads))
+		wake_up(&desc->wait_for_threads);
+}
+
 /*
  * Interrupt handler thread
  */
@@ -771,57 +778,41 @@
 	struct irq_desc *desc = irq_to_desc(action->irq);
 	irqreturn_t (*handler_fn)(struct irq_desc *desc,
 			struct irqaction *action);
-	int wake;
 
-	if (force_irqthreads & test_bit(IRQTF_FORCED_THREAD,
+	if (force_irqthreads && test_bit(IRQTF_FORCED_THREAD,
 					&action->thread_flags))
 		handler_fn = irq_forced_thread_fn;
 	else
 		handler_fn = irq_thread_fn;
 
 	sched_setscheduler(current, SCHED_FIFO, &param);
-	current->irqaction = action;
+	current->irq_thread = 1;
 
 	while (!irq_wait_for_interrupt(action)) {
+		irqreturn_t action_ret;
 
 		irq_thread_check_affinity(desc, action);
 
-		atomic_inc(&desc->threads_active);
+		action_ret = handler_fn(desc, action);
+		if (!noirqdebug)
+			note_interrupt(action->irq, desc, action_ret);
 
-		raw_spin_lock_irq(&desc->lock);
-		if (unlikely(irqd_irq_disabled(&desc->irq_data))) {
-			/*
-			 * CHECKME: We might need a dedicated
-			 * IRQ_THREAD_PENDING flag here, which
-			 * retriggers the thread in check_irq_resend()
-			 * but AFAICT IRQS_PENDING should be fine as it
-			 * retriggers the interrupt itself --- tglx
-			 */
-			desc->istate |= IRQS_PENDING;
-			raw_spin_unlock_irq(&desc->lock);
-		} else {
-			irqreturn_t action_ret;
-
-			raw_spin_unlock_irq(&desc->lock);
-			action_ret = handler_fn(desc, action);
-			if (!noirqdebug)
-				note_interrupt(action->irq, desc, action_ret);
-		}
-
-		wake = atomic_dec_and_test(&desc->threads_active);
-
-		if (wake && waitqueue_active(&desc->wait_for_threads))
-			wake_up(&desc->wait_for_threads);
+		wake_threads_waitq(desc);
 	}
 
-	/* Prevent a stale desc->threads_oneshot */
-	irq_finalize_oneshot(desc, action, true);
-
 	/*
-	 * Clear irqaction. Otherwise exit_irq_thread() would make
+	 * This is the regular exit path. __free_irq() is stopping the
+	 * thread via kthread_stop() after calling
+	 * synchronize_irq(). So neither IRQTF_RUNTHREAD nor the
+	 * oneshot mask bit can be set. We cannot verify that as we
+	 * cannot touch the oneshot mask at this point anymore as
+	 * __setup_irq() might have given out currents thread_mask
+	 * again.
+	 *
+	 * Clear irq_thread. Otherwise exit_irq_thread() would make
 	 * fuzz about an active irq thread going into nirvana.
 	 */
-	current->irqaction = NULL;
+	current->irq_thread = 0;
 	return 0;
 }
 
@@ -832,27 +823,28 @@
 {
 	struct task_struct *tsk = current;
 	struct irq_desc *desc;
+	struct irqaction *action;
 
-	if (!tsk->irqaction)
+	if (!tsk->irq_thread)
 		return;
 
+	action = kthread_data(tsk);
+
 	printk(KERN_ERR
 	       "exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n",
-	       tsk->comm ? tsk->comm : "", tsk->pid, tsk->irqaction->irq);
+	       tsk->comm ? tsk->comm : "", tsk->pid, action->irq);
 
-	desc = irq_to_desc(tsk->irqaction->irq);
+	desc = irq_to_desc(action->irq);
 
 	/*
-	 * Prevent a stale desc->threads_oneshot. Must be called
-	 * before setting the IRQTF_DIED flag.
+	 * If IRQTF_RUNTHREAD is set, we need to decrement
+	 * desc->threads_active and wake possible waiters.
 	 */
-	irq_finalize_oneshot(desc, tsk->irqaction, true);
+	if (test_and_clear_bit(IRQTF_RUNTHREAD, &action->thread_flags))
+		wake_threads_waitq(desc);
 
-	/*
-	 * Set the THREAD DIED flag to prevent further wakeups of the
-	 * soon to be gone threaded handler.
-	 */
-	set_bit(IRQTF_DIED, &tsk->irqaction->flags);
+	/* Prevent a stale desc->threads_oneshot */
+	irq_finalize_oneshot(desc, action, true);
 }
 
 static void irq_setup_forced_threading(struct irqaction *new)
@@ -1135,8 +1127,7 @@
 		struct task_struct *t = new->thread;
 
 		new->thread = NULL;
-		if (likely(!test_bit(IRQTF_DIED, &new->thread_flags)))
-			kthread_stop(t);
+		kthread_stop(t);
 		put_task_struct(t);
 	}
 out_mput:
@@ -1246,8 +1237,7 @@
 #endif
 
 	if (action->thread) {
-		if (!test_bit(IRQTF_DIED, &action->thread_flags))
-			kthread_stop(action->thread);
+		kthread_stop(action->thread);
 		put_task_struct(action->thread);
 	}
 
diff --git a/kernel/jump_label.c b/kernel/jump_label.c
index 01d3b70..4304919 100644
--- a/kernel/jump_label.c
+++ b/kernel/jump_label.c
@@ -12,7 +12,7 @@
 #include <linux/slab.h>
 #include <linux/sort.h>
 #include <linux/err.h>
-#include <linux/jump_label.h>
+#include <linux/static_key.h>
 
 #ifdef HAVE_JUMP_LABEL
 
@@ -29,11 +29,6 @@
 	mutex_unlock(&jump_label_mutex);
 }
 
-bool jump_label_enabled(struct jump_label_key *key)
-{
-	return !!atomic_read(&key->enabled);
-}
-
 static int jump_label_cmp(const void *a, const void *b)
 {
 	const struct jump_entry *jea = a;
@@ -58,56 +53,66 @@
 	sort(start, size, sizeof(struct jump_entry), jump_label_cmp, NULL);
 }
 
-static void jump_label_update(struct jump_label_key *key, int enable);
+static void jump_label_update(struct static_key *key, int enable);
 
-void jump_label_inc(struct jump_label_key *key)
+void static_key_slow_inc(struct static_key *key)
 {
 	if (atomic_inc_not_zero(&key->enabled))
 		return;
 
 	jump_label_lock();
-	if (atomic_read(&key->enabled) == 0)
-		jump_label_update(key, JUMP_LABEL_ENABLE);
+	if (atomic_read(&key->enabled) == 0) {
+		if (!jump_label_get_branch_default(key))
+			jump_label_update(key, JUMP_LABEL_ENABLE);
+		else
+			jump_label_update(key, JUMP_LABEL_DISABLE);
+	}
 	atomic_inc(&key->enabled);
 	jump_label_unlock();
 }
-EXPORT_SYMBOL_GPL(jump_label_inc);
+EXPORT_SYMBOL_GPL(static_key_slow_inc);
 
-static void __jump_label_dec(struct jump_label_key *key,
+static void __static_key_slow_dec(struct static_key *key,
 		unsigned long rate_limit, struct delayed_work *work)
 {
-	if (!atomic_dec_and_mutex_lock(&key->enabled, &jump_label_mutex))
+	if (!atomic_dec_and_mutex_lock(&key->enabled, &jump_label_mutex)) {
+		WARN(atomic_read(&key->enabled) < 0,
+		     "jump label: negative count!\n");
 		return;
+	}
 
 	if (rate_limit) {
 		atomic_inc(&key->enabled);
 		schedule_delayed_work(work, rate_limit);
-	} else
-		jump_label_update(key, JUMP_LABEL_DISABLE);
-
+	} else {
+		if (!jump_label_get_branch_default(key))
+			jump_label_update(key, JUMP_LABEL_DISABLE);
+		else
+			jump_label_update(key, JUMP_LABEL_ENABLE);
+	}
 	jump_label_unlock();
 }
-EXPORT_SYMBOL_GPL(jump_label_dec);
 
 static void jump_label_update_timeout(struct work_struct *work)
 {
-	struct jump_label_key_deferred *key =
-		container_of(work, struct jump_label_key_deferred, work.work);
-	__jump_label_dec(&key->key, 0, NULL);
+	struct static_key_deferred *key =
+		container_of(work, struct static_key_deferred, work.work);
+	__static_key_slow_dec(&key->key, 0, NULL);
 }
 
-void jump_label_dec(struct jump_label_key *key)
+void static_key_slow_dec(struct static_key *key)
 {
-	__jump_label_dec(key, 0, NULL);
+	__static_key_slow_dec(key, 0, NULL);
 }
+EXPORT_SYMBOL_GPL(static_key_slow_dec);
 
-void jump_label_dec_deferred(struct jump_label_key_deferred *key)
+void static_key_slow_dec_deferred(struct static_key_deferred *key)
 {
-	__jump_label_dec(&key->key, key->timeout, &key->work);
+	__static_key_slow_dec(&key->key, key->timeout, &key->work);
 }
+EXPORT_SYMBOL_GPL(static_key_slow_dec_deferred);
 
-
-void jump_label_rate_limit(struct jump_label_key_deferred *key,
+void jump_label_rate_limit(struct static_key_deferred *key,
 		unsigned long rl)
 {
 	key->timeout = rl;
@@ -150,7 +155,7 @@
 	arch_jump_label_transform(entry, type);	
 }
 
-static void __jump_label_update(struct jump_label_key *key,
+static void __jump_label_update(struct static_key *key,
 				struct jump_entry *entry,
 				struct jump_entry *stop, int enable)
 {
@@ -167,27 +172,40 @@
 	}
 }
 
+static enum jump_label_type jump_label_type(struct static_key *key)
+{
+	bool true_branch = jump_label_get_branch_default(key);
+	bool state = static_key_enabled(key);
+
+	if ((!true_branch && state) || (true_branch && !state))
+		return JUMP_LABEL_ENABLE;
+
+	return JUMP_LABEL_DISABLE;
+}
+
 void __init jump_label_init(void)
 {
 	struct jump_entry *iter_start = __start___jump_table;
 	struct jump_entry *iter_stop = __stop___jump_table;
-	struct jump_label_key *key = NULL;
+	struct static_key *key = NULL;
 	struct jump_entry *iter;
 
 	jump_label_lock();
 	jump_label_sort_entries(iter_start, iter_stop);
 
 	for (iter = iter_start; iter < iter_stop; iter++) {
-		struct jump_label_key *iterk;
+		struct static_key *iterk;
 
-		iterk = (struct jump_label_key *)(unsigned long)iter->key;
-		arch_jump_label_transform_static(iter, jump_label_enabled(iterk) ?
-						 JUMP_LABEL_ENABLE : JUMP_LABEL_DISABLE);
+		iterk = (struct static_key *)(unsigned long)iter->key;
+		arch_jump_label_transform_static(iter, jump_label_type(iterk));
 		if (iterk == key)
 			continue;
 
 		key = iterk;
-		key->entries = iter;
+		/*
+		 * Set key->entries to iter, but preserve JUMP_LABEL_TRUE_BRANCH.
+		 */
+		*((unsigned long *)&key->entries) += (unsigned long)iter;
 #ifdef CONFIG_MODULES
 		key->next = NULL;
 #endif
@@ -197,8 +215,8 @@
 
 #ifdef CONFIG_MODULES
 
-struct jump_label_mod {
-	struct jump_label_mod *next;
+struct static_key_mod {
+	struct static_key_mod *next;
 	struct jump_entry *entries;
 	struct module *mod;
 };
@@ -218,9 +236,9 @@
 				start, end);
 }
 
-static void __jump_label_mod_update(struct jump_label_key *key, int enable)
+static void __jump_label_mod_update(struct static_key *key, int enable)
 {
-	struct jump_label_mod *mod = key->next;
+	struct static_key_mod *mod = key->next;
 
 	while (mod) {
 		struct module *m = mod->mod;
@@ -251,11 +269,7 @@
 		return;
 
 	for (iter = iter_start; iter < iter_stop; iter++) {
-		struct jump_label_key *iterk;
-
-		iterk = (struct jump_label_key *)(unsigned long)iter->key;
-		arch_jump_label_transform_static(iter, jump_label_enabled(iterk) ?
-				JUMP_LABEL_ENABLE : JUMP_LABEL_DISABLE);
+		arch_jump_label_transform_static(iter, JUMP_LABEL_DISABLE);
 	}
 }
 
@@ -264,8 +278,8 @@
 	struct jump_entry *iter_start = mod->jump_entries;
 	struct jump_entry *iter_stop = iter_start + mod->num_jump_entries;
 	struct jump_entry *iter;
-	struct jump_label_key *key = NULL;
-	struct jump_label_mod *jlm;
+	struct static_key *key = NULL;
+	struct static_key_mod *jlm;
 
 	/* if the module doesn't have jump label entries, just return */
 	if (iter_start == iter_stop)
@@ -274,28 +288,30 @@
 	jump_label_sort_entries(iter_start, iter_stop);
 
 	for (iter = iter_start; iter < iter_stop; iter++) {
-		if (iter->key == (jump_label_t)(unsigned long)key)
+		struct static_key *iterk;
+
+		iterk = (struct static_key *)(unsigned long)iter->key;
+		if (iterk == key)
 			continue;
 
-		key = (struct jump_label_key *)(unsigned long)iter->key;
-
+		key = iterk;
 		if (__module_address(iter->key) == mod) {
-			atomic_set(&key->enabled, 0);
-			key->entries = iter;
+			/*
+			 * Set key->entries to iter, but preserve JUMP_LABEL_TRUE_BRANCH.
+			 */
+			*((unsigned long *)&key->entries) += (unsigned long)iter;
 			key->next = NULL;
 			continue;
 		}
-
-		jlm = kzalloc(sizeof(struct jump_label_mod), GFP_KERNEL);
+		jlm = kzalloc(sizeof(struct static_key_mod), GFP_KERNEL);
 		if (!jlm)
 			return -ENOMEM;
-
 		jlm->mod = mod;
 		jlm->entries = iter;
 		jlm->next = key->next;
 		key->next = jlm;
 
-		if (jump_label_enabled(key))
+		if (jump_label_type(key) == JUMP_LABEL_ENABLE)
 			__jump_label_update(key, iter, iter_stop, JUMP_LABEL_ENABLE);
 	}
 
@@ -307,14 +323,14 @@
 	struct jump_entry *iter_start = mod->jump_entries;
 	struct jump_entry *iter_stop = iter_start + mod->num_jump_entries;
 	struct jump_entry *iter;
-	struct jump_label_key *key = NULL;
-	struct jump_label_mod *jlm, **prev;
+	struct static_key *key = NULL;
+	struct static_key_mod *jlm, **prev;
 
 	for (iter = iter_start; iter < iter_stop; iter++) {
 		if (iter->key == (jump_label_t)(unsigned long)key)
 			continue;
 
-		key = (struct jump_label_key *)(unsigned long)iter->key;
+		key = (struct static_key *)(unsigned long)iter->key;
 
 		if (__module_address(iter->key) == mod)
 			continue;
@@ -416,12 +432,13 @@
 	return ret;
 }
 
-static void jump_label_update(struct jump_label_key *key, int enable)
+static void jump_label_update(struct static_key *key, int enable)
 {
-	struct jump_entry *entry = key->entries, *stop = __stop___jump_table;
+	struct jump_entry *stop = __stop___jump_table;
+	struct jump_entry *entry = jump_label_get_entries(key);
 
 #ifdef CONFIG_MODULES
-	struct module *mod = __module_address((jump_label_t)key);
+	struct module *mod = __module_address((unsigned long)key);
 
 	__jump_label_mod_update(key, enable);
 
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index 8889f7d..ea9ee45 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -4176,7 +4176,13 @@
 	printk("-------------------------------\n");
 	printk("%s:%d %s!\n", file, line, s);
 	printk("\nother info that might help us debug this:\n\n");
-	printk("\nrcu_scheduler_active = %d, debug_locks = %d\n", rcu_scheduler_active, debug_locks);
+	printk("\n%srcu_scheduler_active = %d, debug_locks = %d\n",
+	       !rcu_lockdep_current_cpu_online()
+			? "RCU used illegally from offline CPU!\n"
+			: rcu_is_cpu_idle()
+				? "RCU used illegally from idle CPU!\n"
+				: "",
+	       rcu_scheduler_active, debug_locks);
 
 	/*
 	 * If a CPU is in the RCU-free window in idle (ie: in the section
diff --git a/kernel/mutex.c b/kernel/mutex.c
index 89096dd..a307cc9 100644
--- a/kernel/mutex.c
+++ b/kernel/mutex.c
@@ -240,9 +240,7 @@
 
 		/* didn't get the lock, go to sleep: */
 		spin_unlock_mutex(&lock->wait_lock, flags);
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
+		schedule_preempt_disabled();
 		spin_lock_mutex(&lock->wait_lock, flags);
 	}
 
diff --git a/kernel/printk.c b/kernel/printk.c
index 32690a0..b663c2c 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -44,6 +44,9 @@
 
 #include <asm/uaccess.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/printk.h>
+
 /*
  * Architectures can override it:
  */
@@ -542,6 +545,8 @@
 static void _call_console_drivers(unsigned start,
 				unsigned end, int msg_log_level)
 {
+	trace_console(&LOG_BUF(0), start, end, log_buf_len);
+
 	if ((msg_log_level < console_loglevel || ignore_loglevel) &&
 			console_drivers && start != end) {
 		if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
@@ -1211,13 +1216,27 @@
 	return console_locked;
 }
 
+/*
+ * Delayed printk facility, for scheduler-internal messages:
+ */
+#define PRINTK_BUF_SIZE		512
+
+#define PRINTK_PENDING_WAKEUP	0x01
+#define PRINTK_PENDING_SCHED	0x02
+
 static DEFINE_PER_CPU(int, printk_pending);
+static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf);
 
 void printk_tick(void)
 {
 	if (__this_cpu_read(printk_pending)) {
-		__this_cpu_write(printk_pending, 0);
-		wake_up_interruptible(&log_wait);
+		int pending = __this_cpu_xchg(printk_pending, 0);
+		if (pending & PRINTK_PENDING_SCHED) {
+			char *buf = __get_cpu_var(printk_sched_buf);
+			printk(KERN_WARNING "[sched_delayed] %s", buf);
+		}
+		if (pending & PRINTK_PENDING_WAKEUP)
+			wake_up_interruptible(&log_wait);
 	}
 }
 
@@ -1231,7 +1250,7 @@
 void wake_up_klogd(void)
 {
 	if (waitqueue_active(&log_wait))
-		this_cpu_write(printk_pending, 1);
+		this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
 }
 
 /**
@@ -1624,6 +1643,26 @@
 
 #if defined CONFIG_PRINTK
 
+int printk_sched(const char *fmt, ...)
+{
+	unsigned long flags;
+	va_list args;
+	char *buf;
+	int r;
+
+	local_irq_save(flags);
+	buf = __get_cpu_var(printk_sched_buf);
+
+	va_start(args, fmt);
+	r = vsnprintf(buf, PRINTK_BUF_SIZE, fmt, args);
+	va_end(args);
+
+	__this_cpu_or(printk_pending, PRINTK_PENDING_SCHED);
+	local_irq_restore(flags);
+
+	return r;
+}
+
 /*
  * printk rate limiting, lifted from the networking subsystem.
  *
diff --git a/kernel/rcu.h b/kernel/rcu.h
index aa88baa..8ba99cd 100644
--- a/kernel/rcu.h
+++ b/kernel/rcu.h
@@ -33,8 +33,27 @@
  * Process-level increment to ->dynticks_nesting field.  This allows for
  * architectures that use half-interrupts and half-exceptions from
  * process context.
+ *
+ * DYNTICK_TASK_NEST_MASK defines a field of width DYNTICK_TASK_NEST_WIDTH
+ * that counts the number of process-based reasons why RCU cannot
+ * consider the corresponding CPU to be idle, and DYNTICK_TASK_NEST_VALUE
+ * is the value used to increment or decrement this field.
+ *
+ * The rest of the bits could in principle be used to count interrupts,
+ * but this would mean that a negative-one value in the interrupt
+ * field could incorrectly zero out the DYNTICK_TASK_NEST_MASK field.
+ * We therefore provide a two-bit guard field defined by DYNTICK_TASK_MASK
+ * that is set to DYNTICK_TASK_FLAG upon initial exit from idle.
+ * The DYNTICK_TASK_EXIT_IDLE value is thus the combined value used upon
+ * initial exit from idle.
  */
-#define DYNTICK_TASK_NESTING (LLONG_MAX / 2 - 1)
+#define DYNTICK_TASK_NEST_WIDTH 7
+#define DYNTICK_TASK_NEST_VALUE ((LLONG_MAX >> DYNTICK_TASK_NEST_WIDTH) + 1)
+#define DYNTICK_TASK_NEST_MASK  (LLONG_MAX - DYNTICK_TASK_NEST_VALUE + 1)
+#define DYNTICK_TASK_FLAG	   ((DYNTICK_TASK_NEST_VALUE / 8) * 2)
+#define DYNTICK_TASK_MASK	   ((DYNTICK_TASK_NEST_VALUE / 8) * 3)
+#define DYNTICK_TASK_EXIT_IDLE	   (DYNTICK_TASK_NEST_VALUE + \
+				    DYNTICK_TASK_FLAG)
 
 /*
  * debug_rcu_head_queue()/debug_rcu_head_unqueue() are used internally
@@ -50,7 +69,6 @@
 
 static inline void debug_rcu_head_queue(struct rcu_head *head)
 {
-	WARN_ON_ONCE((unsigned long)head & 0x3);
 	debug_object_activate(head, &rcuhead_debug_descr);
 	debug_object_active_state(head, &rcuhead_debug_descr,
 				  STATE_RCU_HEAD_READY,
@@ -76,16 +94,18 @@
 
 extern void kfree(const void *);
 
-static inline void __rcu_reclaim(char *rn, struct rcu_head *head)
+static inline bool __rcu_reclaim(char *rn, struct rcu_head *head)
 {
 	unsigned long offset = (unsigned long)head->func;
 
 	if (__is_kfree_rcu_offset(offset)) {
 		RCU_TRACE(trace_rcu_invoke_kfree_callback(rn, head, offset));
 		kfree((void *)head - offset);
+		return 1;
 	} else {
 		RCU_TRACE(trace_rcu_invoke_callback(rn, head));
 		head->func(head);
+		return 0;
 	}
 }
 
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 2bc4e13..a86f174 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -88,6 +88,9 @@
  * section.
  *
  * Check debug_lockdep_rcu_enabled() to prevent false positives during boot.
+ *
+ * Note that rcu_read_lock() is disallowed if the CPU is either idle or
+ * offline from an RCU perspective, so check for those as well.
  */
 int rcu_read_lock_bh_held(void)
 {
@@ -95,6 +98,8 @@
 		return 1;
 	if (rcu_is_cpu_idle())
 		return 0;
+	if (!rcu_lockdep_current_cpu_online())
+		return 0;
 	return in_softirq() || irqs_disabled();
 }
 EXPORT_SYMBOL_GPL(rcu_read_lock_bh_held);
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c
index 977296d..37a5444 100644
--- a/kernel/rcutiny.c
+++ b/kernel/rcutiny.c
@@ -53,7 +53,7 @@
 
 #include "rcutiny_plugin.h"
 
-static long long rcu_dynticks_nesting = DYNTICK_TASK_NESTING;
+static long long rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
 
 /* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcutree.c. */
 static void rcu_idle_enter_common(long long oldval)
@@ -88,10 +88,16 @@
 
 	local_irq_save(flags);
 	oldval = rcu_dynticks_nesting;
-	rcu_dynticks_nesting = 0;
+	WARN_ON_ONCE((rcu_dynticks_nesting & DYNTICK_TASK_NEST_MASK) == 0);
+	if ((rcu_dynticks_nesting & DYNTICK_TASK_NEST_MASK) ==
+	    DYNTICK_TASK_NEST_VALUE)
+		rcu_dynticks_nesting = 0;
+	else
+		rcu_dynticks_nesting  -= DYNTICK_TASK_NEST_VALUE;
 	rcu_idle_enter_common(oldval);
 	local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(rcu_idle_enter);
 
 /*
  * Exit an interrupt handler towards idle.
@@ -140,11 +146,15 @@
 
 	local_irq_save(flags);
 	oldval = rcu_dynticks_nesting;
-	WARN_ON_ONCE(oldval != 0);
-	rcu_dynticks_nesting = DYNTICK_TASK_NESTING;
+	WARN_ON_ONCE(rcu_dynticks_nesting < 0);
+	if (rcu_dynticks_nesting & DYNTICK_TASK_NEST_MASK)
+		rcu_dynticks_nesting += DYNTICK_TASK_NEST_VALUE;
+	else
+		rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
 	rcu_idle_exit_common(oldval);
 	local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(rcu_idle_exit);
 
 /*
  * Enter an interrupt handler, moving away from idle.
@@ -258,7 +268,7 @@
 
 	/* If no RCU callbacks ready to invoke, just return. */
 	if (&rcp->rcucblist == rcp->donetail) {
-		RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, -1));
+		RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, 0, -1));
 		RCU_TRACE(trace_rcu_batch_end(rcp->name, 0,
 					      ACCESS_ONCE(rcp->rcucblist),
 					      need_resched(),
@@ -269,7 +279,7 @@
 
 	/* Move the ready-to-invoke callbacks to a local list. */
 	local_irq_save(flags);
-	RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, -1));
+	RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, rcp->qlen, -1));
 	list = rcp->rcucblist;
 	rcp->rcucblist = *rcp->donetail;
 	*rcp->donetail = NULL;
@@ -319,6 +329,10 @@
  */
 void synchronize_sched(void)
 {
+	rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) &&
+			   !lock_is_held(&rcu_lock_map) &&
+			   !lock_is_held(&rcu_sched_lock_map),
+			   "Illegal synchronize_sched() in RCU read-side critical section");
 	cond_resched();
 }
 EXPORT_SYMBOL_GPL(synchronize_sched);
diff --git a/kernel/rcutiny_plugin.h b/kernel/rcutiny_plugin.h
index 9cb1ae4..22ecea0 100644
--- a/kernel/rcutiny_plugin.h
+++ b/kernel/rcutiny_plugin.h
@@ -132,6 +132,7 @@
 	RCU_TRACE(.rcb.name = "rcu_preempt")
 };
 
+static void rcu_read_unlock_special(struct task_struct *t);
 static int rcu_preempted_readers_exp(void);
 static void rcu_report_exp_done(void);
 
@@ -146,6 +147,16 @@
 /*
  * Check for a running RCU reader.  Because there is only one CPU,
  * there can be but one running RCU reader at a time.  ;-)
+ *
+ * Returns zero if there are no running readers.  Returns a positive
+ * number if there is at least one reader within its RCU read-side
+ * critical section.  Returns a negative number if an outermost reader
+ * is in the midst of exiting from its RCU read-side critical section
+ *
+ * Returns zero if there are no running readers.  Returns a positive
+ * number if there is at least one reader within its RCU read-side
+ * critical section.  Returns a negative number if an outermost reader
+ * is in the midst of exiting from its RCU read-side critical section.
  */
 static int rcu_preempt_running_reader(void)
 {
@@ -307,7 +318,6 @@
 	t = container_of(tb, struct task_struct, rcu_node_entry);
 	rt_mutex_init_proxy_locked(&mtx, t);
 	t->rcu_boost_mutex = &mtx;
-	t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BOOSTED;
 	raw_local_irq_restore(flags);
 	rt_mutex_lock(&mtx);
 	rt_mutex_unlock(&mtx);  /* Keep lockdep happy. */
@@ -475,7 +485,7 @@
 	unsigned long flags;
 
 	local_irq_save(flags); /* must exclude scheduler_tick(). */
-	if (rcu_preempt_running_reader() &&
+	if (rcu_preempt_running_reader() > 0 &&
 	    (t->rcu_read_unlock_special & RCU_READ_UNLOCK_BLOCKED) == 0) {
 
 		/* Possibly blocking in an RCU read-side critical section. */
@@ -494,6 +504,13 @@
 		list_add(&t->rcu_node_entry, &rcu_preempt_ctrlblk.blkd_tasks);
 		if (rcu_cpu_blocking_cur_gp())
 			rcu_preempt_ctrlblk.gp_tasks = &t->rcu_node_entry;
+	} else if (rcu_preempt_running_reader() < 0 &&
+		   t->rcu_read_unlock_special) {
+		/*
+		 * Complete exit from RCU read-side critical section on
+		 * behalf of preempted instance of __rcu_read_unlock().
+		 */
+		rcu_read_unlock_special(t);
 	}
 
 	/*
@@ -526,12 +543,15 @@
  * notify RCU core processing or task having blocked during the RCU
  * read-side critical section.
  */
-static void rcu_read_unlock_special(struct task_struct *t)
+static noinline void rcu_read_unlock_special(struct task_struct *t)
 {
 	int empty;
 	int empty_exp;
 	unsigned long flags;
 	struct list_head *np;
+#ifdef CONFIG_RCU_BOOST
+	struct rt_mutex *rbmp = NULL;
+#endif /* #ifdef CONFIG_RCU_BOOST */
 	int special;
 
 	/*
@@ -552,7 +572,7 @@
 		rcu_preempt_cpu_qs();
 
 	/* Hardware IRQ handlers cannot block. */
-	if (in_irq()) {
+	if (in_irq() || in_serving_softirq()) {
 		local_irq_restore(flags);
 		return;
 	}
@@ -597,10 +617,10 @@
 	}
 #ifdef CONFIG_RCU_BOOST
 	/* Unboost self if was boosted. */
-	if (special & RCU_READ_UNLOCK_BOOSTED) {
-		t->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_BOOSTED;
-		rt_mutex_unlock(t->rcu_boost_mutex);
+	if (t->rcu_boost_mutex != NULL) {
+		rbmp = t->rcu_boost_mutex;
 		t->rcu_boost_mutex = NULL;
+		rt_mutex_unlock(rbmp);
 	}
 #endif /* #ifdef CONFIG_RCU_BOOST */
 	local_irq_restore(flags);
@@ -618,13 +638,22 @@
 	struct task_struct *t = current;
 
 	barrier();  /* needed if we ever invoke rcu_read_unlock in rcutiny.c */
-	--t->rcu_read_lock_nesting;
-	barrier();  /* decrement before load of ->rcu_read_unlock_special */
-	if (t->rcu_read_lock_nesting == 0 &&
-	    unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
-		rcu_read_unlock_special(t);
+	if (t->rcu_read_lock_nesting != 1)
+		--t->rcu_read_lock_nesting;
+	else {
+		t->rcu_read_lock_nesting = INT_MIN;
+		barrier();  /* assign before ->rcu_read_unlock_special load */
+		if (unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
+			rcu_read_unlock_special(t);
+		barrier();  /* ->rcu_read_unlock_special load before assign */
+		t->rcu_read_lock_nesting = 0;
+	}
 #ifdef CONFIG_PROVE_LOCKING
-	WARN_ON_ONCE(t->rcu_read_lock_nesting < 0);
+	{
+		int rrln = ACCESS_ONCE(t->rcu_read_lock_nesting);
+
+		WARN_ON_ONCE(rrln < 0 && rrln > INT_MIN / 2);
+	}
 #endif /* #ifdef CONFIG_PROVE_LOCKING */
 }
 EXPORT_SYMBOL_GPL(__rcu_read_unlock);
@@ -649,7 +678,7 @@
 		invoke_rcu_callbacks();
 	if (rcu_preempt_gp_in_progress() &&
 	    rcu_cpu_blocking_cur_gp() &&
-	    rcu_preempt_running_reader())
+	    rcu_preempt_running_reader() > 0)
 		t->rcu_read_unlock_special |= RCU_READ_UNLOCK_NEED_QS;
 }
 
@@ -706,6 +735,11 @@
  */
 void synchronize_rcu(void)
 {
+	rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) &&
+			   !lock_is_held(&rcu_lock_map) &&
+			   !lock_is_held(&rcu_sched_lock_map),
+			   "Illegal synchronize_rcu() in RCU read-side critical section");
+
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 	if (!rcu_scheduler_active)
 		return;
@@ -882,7 +916,8 @@
 static void invoke_rcu_callbacks(void)
 {
 	have_rcu_kthread_work = 1;
-	wake_up(&rcu_kthread_wq);
+	if (rcu_kthread_task != NULL)
+		wake_up(&rcu_kthread_wq);
 }
 
 #ifdef CONFIG_RCU_TRACE
@@ -943,12 +978,16 @@
 
 #else /* #ifdef CONFIG_RCU_BOOST */
 
+/* Hold off callback invocation until early_initcall() time. */
+static int rcu_scheduler_fully_active __read_mostly;
+
 /*
  * Start up softirq processing of callbacks.
  */
 void invoke_rcu_callbacks(void)
 {
-	raise_softirq(RCU_SOFTIRQ);
+	if (rcu_scheduler_fully_active)
+		raise_softirq(RCU_SOFTIRQ);
 }
 
 #ifdef CONFIG_RCU_TRACE
@@ -963,10 +1002,14 @@
 
 #endif /* #ifdef CONFIG_RCU_TRACE */
 
-void rcu_init(void)
+static int __init rcu_scheduler_really_started(void)
 {
+	rcu_scheduler_fully_active = 1;
 	open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
+	raise_softirq(RCU_SOFTIRQ);  /* Invoke any callbacks from early boot. */
+	return 0;
 }
+early_initcall(rcu_scheduler_really_started);
 
 #endif /* #else #ifdef CONFIG_RCU_BOOST */
 
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index a58ac28..a89b381 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -65,7 +65,10 @@
 static int fqs_holdoff;		/* Hold time within burst (us). */
 static int fqs_stutter = 3;	/* Wait time between bursts (s). */
 static int onoff_interval;	/* Wait time between CPU hotplugs, 0=disable. */
+static int onoff_holdoff;	/* Seconds after boot before CPU hotplugs. */
 static int shutdown_secs;	/* Shutdown time (s).  <=0 for no shutdown. */
+static int stall_cpu;		/* CPU-stall duration (s).  0 for no stall. */
+static int stall_cpu_holdoff = 10; /* Time to wait until stall (s).  */
 static int test_boost = 1;	/* Test RCU prio boost: 0=no, 1=maybe, 2=yes. */
 static int test_boost_interval = 7; /* Interval between boost tests, seconds. */
 static int test_boost_duration = 4; /* Duration of each boost test, seconds. */
@@ -95,8 +98,14 @@
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
 module_param(onoff_interval, int, 0444);
 MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
+module_param(onoff_holdoff, int, 0444);
+MODULE_PARM_DESC(onoff_holdoff, "Time after boot before CPU hotplugs (s)");
 module_param(shutdown_secs, int, 0444);
 MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), zero to disable.");
+module_param(stall_cpu, int, 0444);
+MODULE_PARM_DESC(stall_cpu, "Stall duration (s), zero to disable.");
+module_param(stall_cpu_holdoff, int, 0444);
+MODULE_PARM_DESC(stall_cpu_holdoff, "Time to wait before starting stall (s).");
 module_param(test_boost, int, 0444);
 MODULE_PARM_DESC(test_boost, "Test RCU prio boost: 0=no, 1=maybe, 2=yes.");
 module_param(test_boost_interval, int, 0444);
@@ -129,6 +138,7 @@
 #ifdef CONFIG_HOTPLUG_CPU
 static struct task_struct *onoff_task;
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
+static struct task_struct *stall_task;
 
 #define RCU_TORTURE_PIPE_LEN 10
 
@@ -990,12 +1000,12 @@
 				  rcu_read_lock_bh_held() ||
 				  rcu_read_lock_sched_held() ||
 				  srcu_read_lock_held(&srcu_ctl));
-	do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu);
 	if (p == NULL) {
 		/* Leave because rcu_torture_writer is not yet underway */
 		cur_ops->readunlock(idx);
 		return;
 	}
+	do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu);
 	if (p->rtort_mbtest == 0)
 		atomic_inc(&n_rcu_torture_mberror);
 	spin_lock(&rand_lock);
@@ -1053,13 +1063,13 @@
 					  rcu_read_lock_bh_held() ||
 					  rcu_read_lock_sched_held() ||
 					  srcu_read_lock_held(&srcu_ctl));
-		do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu);
 		if (p == NULL) {
 			/* Wait for rcu_torture_writer to get underway */
 			cur_ops->readunlock(idx);
 			schedule_timeout_interruptible(HZ);
 			continue;
 		}
+		do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu);
 		if (p->rtort_mbtest == 0)
 			atomic_inc(&n_rcu_torture_mberror);
 		cur_ops->read_delay(&rand);
@@ -1300,13 +1310,13 @@
 		"fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d "
 		"test_boost=%d/%d test_boost_interval=%d "
 		"test_boost_duration=%d shutdown_secs=%d "
-		"onoff_interval=%d\n",
+		"onoff_interval=%d onoff_holdoff=%d\n",
 		torture_type, tag, nrealreaders, nfakewriters,
 		stat_interval, verbose, test_no_idle_hz, shuffle_interval,
 		stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter,
 		test_boost, cur_ops->can_boost,
 		test_boost_interval, test_boost_duration, shutdown_secs,
-		onoff_interval);
+		onoff_interval, onoff_holdoff);
 }
 
 static struct notifier_block rcutorture_shutdown_nb = {
@@ -1410,6 +1420,11 @@
 	for_each_online_cpu(cpu)
 		maxcpu = cpu;
 	WARN_ON(maxcpu < 0);
+	if (onoff_holdoff > 0) {
+		VERBOSE_PRINTK_STRING("rcu_torture_onoff begin holdoff");
+		schedule_timeout_interruptible(onoff_holdoff * HZ);
+		VERBOSE_PRINTK_STRING("rcu_torture_onoff end holdoff");
+	}
 	while (!kthread_should_stop()) {
 		cpu = (rcu_random(&rand) >> 4) % (maxcpu + 1);
 		if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) {
@@ -1450,12 +1465,15 @@
 static int __cpuinit
 rcu_torture_onoff_init(void)
 {
+	int ret;
+
 	if (onoff_interval <= 0)
 		return 0;
 	onoff_task = kthread_run(rcu_torture_onoff, NULL, "rcu_torture_onoff");
 	if (IS_ERR(onoff_task)) {
+		ret = PTR_ERR(onoff_task);
 		onoff_task = NULL;
-		return PTR_ERR(onoff_task);
+		return ret;
 	}
 	return 0;
 }
@@ -1481,6 +1499,63 @@
 
 #endif /* #else #ifdef CONFIG_HOTPLUG_CPU */
 
+/*
+ * CPU-stall kthread.  It waits as specified by stall_cpu_holdoff, then
+ * induces a CPU stall for the time specified by stall_cpu.
+ */
+static int __cpuinit rcu_torture_stall(void *args)
+{
+	unsigned long stop_at;
+
+	VERBOSE_PRINTK_STRING("rcu_torture_stall task started");
+	if (stall_cpu_holdoff > 0) {
+		VERBOSE_PRINTK_STRING("rcu_torture_stall begin holdoff");
+		schedule_timeout_interruptible(stall_cpu_holdoff * HZ);
+		VERBOSE_PRINTK_STRING("rcu_torture_stall end holdoff");
+	}
+	if (!kthread_should_stop()) {
+		stop_at = get_seconds() + stall_cpu;
+		/* RCU CPU stall is expected behavior in following code. */
+		printk(KERN_ALERT "rcu_torture_stall start.\n");
+		rcu_read_lock();
+		preempt_disable();
+		while (ULONG_CMP_LT(get_seconds(), stop_at))
+			continue;  /* Induce RCU CPU stall warning. */
+		preempt_enable();
+		rcu_read_unlock();
+		printk(KERN_ALERT "rcu_torture_stall end.\n");
+	}
+	rcutorture_shutdown_absorb("rcu_torture_stall");
+	while (!kthread_should_stop())
+		schedule_timeout_interruptible(10 * HZ);
+	return 0;
+}
+
+/* Spawn CPU-stall kthread, if stall_cpu specified. */
+static int __init rcu_torture_stall_init(void)
+{
+	int ret;
+
+	if (stall_cpu <= 0)
+		return 0;
+	stall_task = kthread_run(rcu_torture_stall, NULL, "rcu_torture_stall");
+	if (IS_ERR(stall_task)) {
+		ret = PTR_ERR(stall_task);
+		stall_task = NULL;
+		return ret;
+	}
+	return 0;
+}
+
+/* Clean up after the CPU-stall kthread, if one was spawned. */
+static void rcu_torture_stall_cleanup(void)
+{
+	if (stall_task == NULL)
+		return;
+	VERBOSE_PRINTK_STRING("Stopping rcu_torture_stall_task.");
+	kthread_stop(stall_task);
+}
+
 static int rcutorture_cpu_notify(struct notifier_block *self,
 				 unsigned long action, void *hcpu)
 {
@@ -1523,6 +1598,7 @@
 	fullstop = FULLSTOP_RMMOD;
 	mutex_unlock(&fullstop_mutex);
 	unregister_reboot_notifier(&rcutorture_shutdown_nb);
+	rcu_torture_stall_cleanup();
 	if (stutter_task) {
 		VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task");
 		kthread_stop(stutter_task);
@@ -1602,6 +1678,10 @@
 		cur_ops->cleanup();
 	if (atomic_read(&n_rcu_torture_error))
 		rcu_torture_print_module_parms(cur_ops, "End of test: FAILURE");
+	else if (n_online_successes != n_online_attempts ||
+		 n_offline_successes != n_offline_attempts)
+		rcu_torture_print_module_parms(cur_ops,
+					       "End of test: RCU_HOTPLUG");
 	else
 		rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
 }
@@ -1819,6 +1899,7 @@
 	}
 	rcu_torture_onoff_init();
 	register_reboot_notifier(&rcutorture_shutdown_nb);
+	rcu_torture_stall_init();
 	rcutorture_record_test_transition();
 	mutex_unlock(&fullstop_mutex);
 	return 0;
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 6c4a672..1050d6d 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -50,6 +50,8 @@
 #include <linux/wait.h>
 #include <linux/kthread.h>
 #include <linux/prefetch.h>
+#include <linux/delay.h>
+#include <linux/stop_machine.h>
 
 #include "rcutree.h"
 #include <trace/events/rcu.h>
@@ -196,7 +198,7 @@
 EXPORT_SYMBOL_GPL(rcu_note_context_switch);
 
 DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = {
-	.dynticks_nesting = DYNTICK_TASK_NESTING,
+	.dynticks_nesting = DYNTICK_TASK_EXIT_IDLE,
 	.dynticks = ATOMIC_INIT(1),
 };
 
@@ -208,8 +210,11 @@
 module_param(qhimark, int, 0);
 module_param(qlowmark, int, 0);
 
-int rcu_cpu_stall_suppress __read_mostly;
+int rcu_cpu_stall_suppress __read_mostly; /* 1 = suppress stall warnings. */
+int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT;
+
 module_param(rcu_cpu_stall_suppress, int, 0644);
+module_param(rcu_cpu_stall_timeout, int, 0644);
 
 static void force_quiescent_state(struct rcu_state *rsp, int relaxed);
 static int rcu_pending(int cpu);
@@ -301,8 +306,6 @@
 	return &rsp->node[0];
 }
 
-#ifdef CONFIG_SMP
-
 /*
  * If the specified CPU is offline, tell the caller that it is in
  * a quiescent state.  Otherwise, whack it with a reschedule IPI.
@@ -317,30 +320,21 @@
 static int rcu_implicit_offline_qs(struct rcu_data *rdp)
 {
 	/*
-	 * If the CPU is offline, it is in a quiescent state.  We can
-	 * trust its state not to change because interrupts are disabled.
+	 * If the CPU is offline for more than a jiffy, it is in a quiescent
+	 * state.  We can trust its state not to change because interrupts
+	 * are disabled.  The reason for the jiffy's worth of slack is to
+	 * handle CPUs initializing on the way up and finding their way
+	 * to the idle loop on the way down.
 	 */
-	if (cpu_is_offline(rdp->cpu)) {
+	if (cpu_is_offline(rdp->cpu) &&
+	    ULONG_CMP_LT(rdp->rsp->gp_start + 2, jiffies)) {
 		trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, "ofl");
 		rdp->offline_fqs++;
 		return 1;
 	}
-
-	/*
-	 * The CPU is online, so send it a reschedule IPI.  This forces
-	 * it through the scheduler, and (inefficiently) also handles cases
-	 * where idle loops fail to inform RCU about the CPU being idle.
-	 */
-	if (rdp->cpu != smp_processor_id())
-		smp_send_reschedule(rdp->cpu);
-	else
-		set_need_resched();
-	rdp->resched_ipi++;
 	return 0;
 }
 
-#endif /* #ifdef CONFIG_SMP */
-
 /*
  * rcu_idle_enter_common - inform RCU that current CPU is moving towards idle
  *
@@ -366,6 +360,17 @@
 	atomic_inc(&rdtp->dynticks);
 	smp_mb__after_atomic_inc();  /* Force ordering with next sojourn. */
 	WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1);
+
+	/*
+	 * The idle task is not permitted to enter the idle loop while
+	 * in an RCU read-side critical section.
+	 */
+	rcu_lockdep_assert(!lock_is_held(&rcu_lock_map),
+			   "Illegal idle entry in RCU read-side critical section.");
+	rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map),
+			   "Illegal idle entry in RCU-bh read-side critical section.");
+	rcu_lockdep_assert(!lock_is_held(&rcu_sched_lock_map),
+			   "Illegal idle entry in RCU-sched read-side critical section.");
 }
 
 /**
@@ -389,10 +394,15 @@
 	local_irq_save(flags);
 	rdtp = &__get_cpu_var(rcu_dynticks);
 	oldval = rdtp->dynticks_nesting;
-	rdtp->dynticks_nesting = 0;
+	WARN_ON_ONCE((oldval & DYNTICK_TASK_NEST_MASK) == 0);
+	if ((oldval & DYNTICK_TASK_NEST_MASK) == DYNTICK_TASK_NEST_VALUE)
+		rdtp->dynticks_nesting = 0;
+	else
+		rdtp->dynticks_nesting -= DYNTICK_TASK_NEST_VALUE;
 	rcu_idle_enter_common(rdtp, oldval);
 	local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(rcu_idle_enter);
 
 /**
  * rcu_irq_exit - inform RCU that current CPU is exiting irq towards idle
@@ -462,7 +472,7 @@
  * Exit idle mode, in other words, -enter- the mode in which RCU
  * read-side critical sections can occur.
  *
- * We crowbar the ->dynticks_nesting field to DYNTICK_TASK_NESTING to
+ * We crowbar the ->dynticks_nesting field to DYNTICK_TASK_NEST to
  * allow for the possibility of usermode upcalls messing up our count
  * of interrupt nesting level during the busy period that is just
  * now starting.
@@ -476,11 +486,15 @@
 	local_irq_save(flags);
 	rdtp = &__get_cpu_var(rcu_dynticks);
 	oldval = rdtp->dynticks_nesting;
-	WARN_ON_ONCE(oldval != 0);
-	rdtp->dynticks_nesting = DYNTICK_TASK_NESTING;
+	WARN_ON_ONCE(oldval < 0);
+	if (oldval & DYNTICK_TASK_NEST_MASK)
+		rdtp->dynticks_nesting += DYNTICK_TASK_NEST_VALUE;
+	else
+		rdtp->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
 	rcu_idle_exit_common(rdtp, oldval);
 	local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(rcu_idle_exit);
 
 /**
  * rcu_irq_enter - inform RCU that current CPU is entering irq away from idle
@@ -581,6 +595,49 @@
 }
 EXPORT_SYMBOL(rcu_is_cpu_idle);
 
+#ifdef CONFIG_HOTPLUG_CPU
+
+/*
+ * Is the current CPU online?  Disable preemption to avoid false positives
+ * that could otherwise happen due to the current CPU number being sampled,
+ * this task being preempted, its old CPU being taken offline, resuming
+ * on some other CPU, then determining that its old CPU is now offline.
+ * It is OK to use RCU on an offline processor during initial boot, hence
+ * the check for rcu_scheduler_fully_active.  Note also that it is OK
+ * for a CPU coming online to use RCU for one jiffy prior to marking itself
+ * online in the cpu_online_mask.  Similarly, it is OK for a CPU going
+ * offline to continue to use RCU for one jiffy after marking itself
+ * offline in the cpu_online_mask.  This leniency is necessary given the
+ * non-atomic nature of the online and offline processing, for example,
+ * the fact that a CPU enters the scheduler after completing the CPU_DYING
+ * notifiers.
+ *
+ * This is also why RCU internally marks CPUs online during the
+ * CPU_UP_PREPARE phase and offline during the CPU_DEAD phase.
+ *
+ * Disable checking if in an NMI handler because we cannot safely report
+ * errors from NMI handlers anyway.
+ */
+bool rcu_lockdep_current_cpu_online(void)
+{
+	struct rcu_data *rdp;
+	struct rcu_node *rnp;
+	bool ret;
+
+	if (in_nmi())
+		return 1;
+	preempt_disable();
+	rdp = &__get_cpu_var(rcu_sched_data);
+	rnp = rdp->mynode;
+	ret = (rdp->grpmask & rnp->qsmaskinit) ||
+	      !rcu_scheduler_fully_active;
+	preempt_enable();
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rcu_lockdep_current_cpu_online);
+
+#endif /* #ifdef CONFIG_HOTPLUG_CPU */
+
 #endif /* #ifdef CONFIG_PROVE_RCU */
 
 /**
@@ -595,8 +652,6 @@
 	return __get_cpu_var(rcu_dynticks).dynticks_nesting <= 1;
 }
 
-#ifdef CONFIG_SMP
-
 /*
  * Snapshot the specified CPU's dynticks counter so that we can later
  * credit them with an implicit quiescent state.  Return 1 if this CPU
@@ -640,12 +695,28 @@
 	return rcu_implicit_offline_qs(rdp);
 }
 
-#endif /* #ifdef CONFIG_SMP */
+static int jiffies_till_stall_check(void)
+{
+	int till_stall_check = ACCESS_ONCE(rcu_cpu_stall_timeout);
+
+	/*
+	 * Limit check must be consistent with the Kconfig limits
+	 * for CONFIG_RCU_CPU_STALL_TIMEOUT.
+	 */
+	if (till_stall_check < 3) {
+		ACCESS_ONCE(rcu_cpu_stall_timeout) = 3;
+		till_stall_check = 3;
+	} else if (till_stall_check > 300) {
+		ACCESS_ONCE(rcu_cpu_stall_timeout) = 300;
+		till_stall_check = 300;
+	}
+	return till_stall_check * HZ + RCU_STALL_DELAY_DELTA;
+}
 
 static void record_gp_stall_check_time(struct rcu_state *rsp)
 {
 	rsp->gp_start = jiffies;
-	rsp->jiffies_stall = jiffies + RCU_SECONDS_TILL_STALL_CHECK;
+	rsp->jiffies_stall = jiffies + jiffies_till_stall_check();
 }
 
 static void print_other_cpu_stall(struct rcu_state *rsp)
@@ -664,13 +735,7 @@
 		raw_spin_unlock_irqrestore(&rnp->lock, flags);
 		return;
 	}
-	rsp->jiffies_stall = jiffies + RCU_SECONDS_TILL_STALL_RECHECK;
-
-	/*
-	 * Now rat on any tasks that got kicked up to the root rcu_node
-	 * due to CPU offlining.
-	 */
-	ndetected = rcu_print_task_stall(rnp);
+	rsp->jiffies_stall = jiffies + 3 * jiffies_till_stall_check() + 3;
 	raw_spin_unlock_irqrestore(&rnp->lock, flags);
 
 	/*
@@ -678,8 +743,9 @@
 	 * See Documentation/RCU/stallwarn.txt for info on how to debug
 	 * RCU CPU stall warnings.
 	 */
-	printk(KERN_ERR "INFO: %s detected stalls on CPUs/tasks: {",
+	printk(KERN_ERR "INFO: %s detected stalls on CPUs/tasks:",
 	       rsp->name);
+	print_cpu_stall_info_begin();
 	rcu_for_each_leaf_node(rsp, rnp) {
 		raw_spin_lock_irqsave(&rnp->lock, flags);
 		ndetected += rcu_print_task_stall(rnp);
@@ -688,11 +754,22 @@
 			continue;
 		for (cpu = 0; cpu <= rnp->grphi - rnp->grplo; cpu++)
 			if (rnp->qsmask & (1UL << cpu)) {
-				printk(" %d", rnp->grplo + cpu);
+				print_cpu_stall_info(rsp, rnp->grplo + cpu);
 				ndetected++;
 			}
 	}
-	printk("} (detected by %d, t=%ld jiffies)\n",
+
+	/*
+	 * Now rat on any tasks that got kicked up to the root rcu_node
+	 * due to CPU offlining.
+	 */
+	rnp = rcu_get_root(rsp);
+	raw_spin_lock_irqsave(&rnp->lock, flags);
+	ndetected = rcu_print_task_stall(rnp);
+	raw_spin_unlock_irqrestore(&rnp->lock, flags);
+
+	print_cpu_stall_info_end();
+	printk(KERN_CONT "(detected by %d, t=%ld jiffies)\n",
 	       smp_processor_id(), (long)(jiffies - rsp->gp_start));
 	if (ndetected == 0)
 		printk(KERN_ERR "INFO: Stall ended before state dump start\n");
@@ -716,15 +793,18 @@
 	 * See Documentation/RCU/stallwarn.txt for info on how to debug
 	 * RCU CPU stall warnings.
 	 */
-	printk(KERN_ERR "INFO: %s detected stall on CPU %d (t=%lu jiffies)\n",
-	       rsp->name, smp_processor_id(), jiffies - rsp->gp_start);
+	printk(KERN_ERR "INFO: %s self-detected stall on CPU", rsp->name);
+	print_cpu_stall_info_begin();
+	print_cpu_stall_info(rsp, smp_processor_id());
+	print_cpu_stall_info_end();
+	printk(KERN_CONT " (t=%lu jiffies)\n", jiffies - rsp->gp_start);
 	if (!trigger_all_cpu_backtrace())
 		dump_stack();
 
 	raw_spin_lock_irqsave(&rnp->lock, flags);
 	if (ULONG_CMP_GE(jiffies, rsp->jiffies_stall))
-		rsp->jiffies_stall =
-			jiffies + RCU_SECONDS_TILL_STALL_RECHECK;
+		rsp->jiffies_stall = jiffies +
+				     3 * jiffies_till_stall_check() + 3;
 	raw_spin_unlock_irqrestore(&rnp->lock, flags);
 
 	set_need_resched();  /* kick ourselves to get things going. */
@@ -807,6 +887,7 @@
 			rdp->passed_quiesce = 0;
 		} else
 			rdp->qs_pending = 0;
+		zero_cpu_stall_ticks(rdp);
 	}
 }
 
@@ -943,6 +1024,10 @@
  * in preparation for detecting the next grace period.  The caller must hold
  * the root node's ->lock, which is released before return.  Hard irqs must
  * be disabled.
+ *
+ * Note that it is legal for a dying CPU (which is marked as offline) to
+ * invoke this function.  This can happen when the dying CPU reports its
+ * quiescent state.
  */
 static void
 rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
@@ -980,26 +1065,8 @@
 	rsp->fqs_state = RCU_GP_INIT; /* Hold off force_quiescent_state. */
 	rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS;
 	record_gp_stall_check_time(rsp);
-
-	/* Special-case the common single-level case. */
-	if (NUM_RCU_NODES == 1) {
-		rcu_preempt_check_blocked_tasks(rnp);
-		rnp->qsmask = rnp->qsmaskinit;
-		rnp->gpnum = rsp->gpnum;
-		rnp->completed = rsp->completed;
-		rsp->fqs_state = RCU_SIGNAL_INIT; /* force_quiescent_state OK */
-		rcu_start_gp_per_cpu(rsp, rnp, rdp);
-		rcu_preempt_boost_start_gp(rnp);
-		trace_rcu_grace_period_init(rsp->name, rnp->gpnum,
-					    rnp->level, rnp->grplo,
-					    rnp->grphi, rnp->qsmask);
-		raw_spin_unlock_irqrestore(&rnp->lock, flags);
-		return;
-	}
-
 	raw_spin_unlock(&rnp->lock);  /* leave irqs disabled. */
 
-
 	/* Exclude any concurrent CPU-hotplug operations. */
 	raw_spin_lock(&rsp->onofflock);  /* irqs already disabled. */
 
@@ -1245,53 +1312,115 @@
 
 /*
  * Move a dying CPU's RCU callbacks to online CPU's callback list.
- * Synchronization is not required because this function executes
- * in stop_machine() context.
+ * Also record a quiescent state for this CPU for the current grace period.
+ * Synchronization and interrupt disabling are not required because
+ * this function executes in stop_machine() context.  Therefore, cleanup
+ * operations that might block must be done later from the CPU_DEAD
+ * notifier.
+ *
+ * Note that the outgoing CPU's bit has already been cleared in the
+ * cpu_online_mask.  This allows us to randomly pick a callback
+ * destination from the bits set in that mask.
  */
-static void rcu_send_cbs_to_online(struct rcu_state *rsp)
+static void rcu_cleanup_dying_cpu(struct rcu_state *rsp)
 {
 	int i;
-	/* current DYING CPU is cleared in the cpu_online_mask */
+	unsigned long mask;
 	int receive_cpu = cpumask_any(cpu_online_mask);
 	struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
 	struct rcu_data *receive_rdp = per_cpu_ptr(rsp->rda, receive_cpu);
+	RCU_TRACE(struct rcu_node *rnp = rdp->mynode); /* For dying CPU. */
 
-	if (rdp->nxtlist == NULL)
-		return;  /* irqs disabled, so comparison is stable. */
+	/* First, adjust the counts. */
+	if (rdp->nxtlist != NULL) {
+		receive_rdp->qlen_lazy += rdp->qlen_lazy;
+		receive_rdp->qlen += rdp->qlen;
+		rdp->qlen_lazy = 0;
+		rdp->qlen = 0;
+	}
 
-	*receive_rdp->nxttail[RCU_NEXT_TAIL] = rdp->nxtlist;
-	receive_rdp->nxttail[RCU_NEXT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
-	receive_rdp->qlen += rdp->qlen;
-	receive_rdp->n_cbs_adopted += rdp->qlen;
-	rdp->n_cbs_orphaned += rdp->qlen;
+	/*
+	 * Next, move ready-to-invoke callbacks to be invoked on some
+	 * other CPU.  These will not be required to pass through another
+	 * grace period:  They are done, regardless of CPU.
+	 */
+	if (rdp->nxtlist != NULL &&
+	    rdp->nxttail[RCU_DONE_TAIL] != &rdp->nxtlist) {
+		struct rcu_head *oldhead;
+		struct rcu_head **oldtail;
+		struct rcu_head **newtail;
 
-	rdp->nxtlist = NULL;
-	for (i = 0; i < RCU_NEXT_SIZE; i++)
-		rdp->nxttail[i] = &rdp->nxtlist;
-	rdp->qlen = 0;
+		oldhead = rdp->nxtlist;
+		oldtail = receive_rdp->nxttail[RCU_DONE_TAIL];
+		rdp->nxtlist = *rdp->nxttail[RCU_DONE_TAIL];
+		*rdp->nxttail[RCU_DONE_TAIL] = *oldtail;
+		*receive_rdp->nxttail[RCU_DONE_TAIL] = oldhead;
+		newtail = rdp->nxttail[RCU_DONE_TAIL];
+		for (i = RCU_DONE_TAIL; i < RCU_NEXT_SIZE; i++) {
+			if (receive_rdp->nxttail[i] == oldtail)
+				receive_rdp->nxttail[i] = newtail;
+			if (rdp->nxttail[i] == newtail)
+				rdp->nxttail[i] = &rdp->nxtlist;
+		}
+	}
+
+	/*
+	 * Finally, put the rest of the callbacks at the end of the list.
+	 * The ones that made it partway through get to start over:  We
+	 * cannot assume that grace periods are synchronized across CPUs.
+	 * (We could splice RCU_WAIT_TAIL into RCU_NEXT_READY_TAIL, but
+	 * this does not seem compelling.  Not yet, anyway.)
+	 */
+	if (rdp->nxtlist != NULL) {
+		*receive_rdp->nxttail[RCU_NEXT_TAIL] = rdp->nxtlist;
+		receive_rdp->nxttail[RCU_NEXT_TAIL] =
+				rdp->nxttail[RCU_NEXT_TAIL];
+		receive_rdp->n_cbs_adopted += rdp->qlen;
+		rdp->n_cbs_orphaned += rdp->qlen;
+
+		rdp->nxtlist = NULL;
+		for (i = 0; i < RCU_NEXT_SIZE; i++)
+			rdp->nxttail[i] = &rdp->nxtlist;
+	}
+
+	/*
+	 * Record a quiescent state for the dying CPU.  This is safe
+	 * only because we have already cleared out the callbacks.
+	 * (Otherwise, the RCU core might try to schedule the invocation
+	 * of callbacks on this now-offline CPU, which would be bad.)
+	 */
+	mask = rdp->grpmask;	/* rnp->grplo is constant. */
+	trace_rcu_grace_period(rsp->name,
+			       rnp->gpnum + 1 - !!(rnp->qsmask & mask),
+			       "cpuofl");
+	rcu_report_qs_rdp(smp_processor_id(), rsp, rdp, rsp->gpnum);
+	/* Note that rcu_report_qs_rdp() might call trace_rcu_grace_period(). */
 }
 
 /*
- * Remove the outgoing CPU from the bitmasks in the rcu_node hierarchy
- * and move all callbacks from the outgoing CPU to the current one.
+ * The CPU has been completely removed, and some other CPU is reporting
+ * this fact from process context.  Do the remainder of the cleanup.
  * There can only be one CPU hotplug operation at a time, so no other
  * CPU can be attempting to update rcu_cpu_kthread_task.
  */
-static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp)
+static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp)
 {
 	unsigned long flags;
 	unsigned long mask;
 	int need_report = 0;
 	struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
-	struct rcu_node *rnp;
+	struct rcu_node *rnp = rdp->mynode;  /* Outgoing CPU's rnp. */
 
+	/* Adjust any no-longer-needed kthreads. */
 	rcu_stop_cpu_kthread(cpu);
+	rcu_node_kthread_setaffinity(rnp, -1);
+
+	/* Remove the dying CPU from the bitmasks in the rcu_node hierarchy. */
 
 	/* Exclude any attempts to start a new grace period. */
 	raw_spin_lock_irqsave(&rsp->onofflock, flags);
 
 	/* Remove the outgoing CPU from the masks in the rcu_node hierarchy. */
-	rnp = rdp->mynode;	/* this is the outgoing CPU's rnp. */
 	mask = rdp->grpmask;	/* rnp->grplo is constant. */
 	do {
 		raw_spin_lock(&rnp->lock);	/* irqs already disabled. */
@@ -1299,20 +1428,11 @@
 		if (rnp->qsmaskinit != 0) {
 			if (rnp != rdp->mynode)
 				raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
-			else
-				trace_rcu_grace_period(rsp->name,
-						       rnp->gpnum + 1 -
-						       !!(rnp->qsmask & mask),
-						       "cpuofl");
 			break;
 		}
-		if (rnp == rdp->mynode) {
-			trace_rcu_grace_period(rsp->name,
-					       rnp->gpnum + 1 -
-					       !!(rnp->qsmask & mask),
-					       "cpuofl");
+		if (rnp == rdp->mynode)
 			need_report = rcu_preempt_offline_tasks(rsp, rnp, rdp);
-		} else
+		else
 			raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
 		mask = rnp->grpmask;
 		rnp = rnp->parent;
@@ -1332,29 +1452,15 @@
 		raw_spin_unlock_irqrestore(&rnp->lock, flags);
 	if (need_report & RCU_OFL_TASKS_EXP_GP)
 		rcu_report_exp_rnp(rsp, rnp, true);
-	rcu_node_kthread_setaffinity(rnp, -1);
-}
-
-/*
- * Remove the specified CPU from the RCU hierarchy and move any pending
- * callbacks that it might have to the current CPU.  This code assumes
- * that at least one CPU in the system will remain running at all times.
- * Any attempt to offline -all- CPUs is likely to strand RCU callbacks.
- */
-static void rcu_offline_cpu(int cpu)
-{
-	__rcu_offline_cpu(cpu, &rcu_sched_state);
-	__rcu_offline_cpu(cpu, &rcu_bh_state);
-	rcu_preempt_offline_cpu(cpu);
 }
 
 #else /* #ifdef CONFIG_HOTPLUG_CPU */
 
-static void rcu_send_cbs_to_online(struct rcu_state *rsp)
+static void rcu_cleanup_dying_cpu(struct rcu_state *rsp)
 {
 }
 
-static void rcu_offline_cpu(int cpu)
+static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp)
 {
 }
 
@@ -1368,11 +1474,11 @@
 {
 	unsigned long flags;
 	struct rcu_head *next, *list, **tail;
-	int bl, count;
+	int bl, count, count_lazy;
 
 	/* If no callbacks are ready, just return.*/
 	if (!cpu_has_callbacks_ready_to_invoke(rdp)) {
-		trace_rcu_batch_start(rsp->name, 0, 0);
+		trace_rcu_batch_start(rsp->name, rdp->qlen_lazy, rdp->qlen, 0);
 		trace_rcu_batch_end(rsp->name, 0, !!ACCESS_ONCE(rdp->nxtlist),
 				    need_resched(), is_idle_task(current),
 				    rcu_is_callbacks_kthread());
@@ -1384,8 +1490,9 @@
 	 * races with call_rcu() from interrupt handlers.
 	 */
 	local_irq_save(flags);
+	WARN_ON_ONCE(cpu_is_offline(smp_processor_id()));
 	bl = rdp->blimit;
-	trace_rcu_batch_start(rsp->name, rdp->qlen, bl);
+	trace_rcu_batch_start(rsp->name, rdp->qlen_lazy, rdp->qlen, bl);
 	list = rdp->nxtlist;
 	rdp->nxtlist = *rdp->nxttail[RCU_DONE_TAIL];
 	*rdp->nxttail[RCU_DONE_TAIL] = NULL;
@@ -1396,12 +1503,13 @@
 	local_irq_restore(flags);
 
 	/* Invoke callbacks. */
-	count = 0;
+	count = count_lazy = 0;
 	while (list) {
 		next = list->next;
 		prefetch(next);
 		debug_rcu_head_unqueue(list);
-		__rcu_reclaim(rsp->name, list);
+		if (__rcu_reclaim(rsp->name, list))
+			count_lazy++;
 		list = next;
 		/* Stop only if limit reached and CPU has something to do. */
 		if (++count >= bl &&
@@ -1416,6 +1524,7 @@
 			    rcu_is_callbacks_kthread());
 
 	/* Update count, and requeue any remaining callbacks. */
+	rdp->qlen_lazy -= count_lazy;
 	rdp->qlen -= count;
 	rdp->n_cbs_invoked += count;
 	if (list != NULL) {
@@ -1458,6 +1567,7 @@
 void rcu_check_callbacks(int cpu, int user)
 {
 	trace_rcu_utilization("Start scheduler-tick");
+	increment_cpu_stall_ticks();
 	if (user || rcu_is_cpu_rrupt_from_idle()) {
 
 		/*
@@ -1492,8 +1602,6 @@
 	trace_rcu_utilization("End scheduler-tick");
 }
 
-#ifdef CONFIG_SMP
-
 /*
  * Scan the leaf rcu_node structures, processing dyntick state for any that
  * have not yet encountered a quiescent state, using the function specified.
@@ -1616,15 +1724,6 @@
 	trace_rcu_utilization("End fqs");
 }
 
-#else /* #ifdef CONFIG_SMP */
-
-static void force_quiescent_state(struct rcu_state *rsp, int relaxed)
-{
-	set_need_resched();
-}
-
-#endif /* #else #ifdef CONFIG_SMP */
-
 /*
  * This does the RCU core processing work for the specified rcu_state
  * and rcu_data structures.  This may be called only from the CPU to
@@ -1702,11 +1801,12 @@
 
 static void
 __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
-	   struct rcu_state *rsp)
+	   struct rcu_state *rsp, bool lazy)
 {
 	unsigned long flags;
 	struct rcu_data *rdp;
 
+	WARN_ON_ONCE((unsigned long)head & 0x3); /* Misaligned rcu_head! */
 	debug_rcu_head_queue(head);
 	head->func = func;
 	head->next = NULL;
@@ -1720,18 +1820,21 @@
 	 * a quiescent state betweentimes.
 	 */
 	local_irq_save(flags);
+	WARN_ON_ONCE(cpu_is_offline(smp_processor_id()));
 	rdp = this_cpu_ptr(rsp->rda);
 
 	/* Add the callback to our list. */
 	*rdp->nxttail[RCU_NEXT_TAIL] = head;
 	rdp->nxttail[RCU_NEXT_TAIL] = &head->next;
 	rdp->qlen++;
+	if (lazy)
+		rdp->qlen_lazy++;
 
 	if (__is_kfree_rcu_offset((unsigned long)func))
 		trace_rcu_kfree_callback(rsp->name, head, (unsigned long)func,
-					 rdp->qlen);
+					 rdp->qlen_lazy, rdp->qlen);
 	else
-		trace_rcu_callback(rsp->name, head, rdp->qlen);
+		trace_rcu_callback(rsp->name, head, rdp->qlen_lazy, rdp->qlen);
 
 	/* If interrupts were disabled, don't dive into RCU core. */
 	if (irqs_disabled_flags(flags)) {
@@ -1778,16 +1881,16 @@
  */
 void call_rcu_sched(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
 {
-	__call_rcu(head, func, &rcu_sched_state);
+	__call_rcu(head, func, &rcu_sched_state, 0);
 }
 EXPORT_SYMBOL_GPL(call_rcu_sched);
 
 /*
- * Queue an RCU for invocation after a quicker grace period.
+ * Queue an RCU callback for invocation after a quicker grace period.
  */
 void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
 {
-	__call_rcu(head, func, &rcu_bh_state);
+	__call_rcu(head, func, &rcu_bh_state, 0);
 }
 EXPORT_SYMBOL_GPL(call_rcu_bh);
 
@@ -1816,6 +1919,10 @@
  */
 void synchronize_sched(void)
 {
+	rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) &&
+			   !lock_is_held(&rcu_lock_map) &&
+			   !lock_is_held(&rcu_sched_lock_map),
+			   "Illegal synchronize_sched() in RCU-sched read-side critical section");
 	if (rcu_blocking_is_gp())
 		return;
 	wait_rcu_gp(call_rcu_sched);
@@ -1833,12 +1940,137 @@
  */
 void synchronize_rcu_bh(void)
 {
+	rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) &&
+			   !lock_is_held(&rcu_lock_map) &&
+			   !lock_is_held(&rcu_sched_lock_map),
+			   "Illegal synchronize_rcu_bh() in RCU-bh read-side critical section");
 	if (rcu_blocking_is_gp())
 		return;
 	wait_rcu_gp(call_rcu_bh);
 }
 EXPORT_SYMBOL_GPL(synchronize_rcu_bh);
 
+static atomic_t sync_sched_expedited_started = ATOMIC_INIT(0);
+static atomic_t sync_sched_expedited_done = ATOMIC_INIT(0);
+
+static int synchronize_sched_expedited_cpu_stop(void *data)
+{
+	/*
+	 * There must be a full memory barrier on each affected CPU
+	 * between the time that try_stop_cpus() is called and the
+	 * time that it returns.
+	 *
+	 * In the current initial implementation of cpu_stop, the
+	 * above condition is already met when the control reaches
+	 * this point and the following smp_mb() is not strictly
+	 * necessary.  Do smp_mb() anyway for documentation and
+	 * robustness against future implementation changes.
+	 */
+	smp_mb(); /* See above comment block. */
+	return 0;
+}
+
+/**
+ * synchronize_sched_expedited - Brute-force RCU-sched grace period
+ *
+ * Wait for an RCU-sched grace period to elapse, but use a "big hammer"
+ * approach to force the grace period to end quickly.  This consumes
+ * significant time on all CPUs and is unfriendly to real-time workloads,
+ * so is thus not recommended for any sort of common-case code.  In fact,
+ * if you are using synchronize_sched_expedited() in a loop, please
+ * restructure your code to batch your updates, and then use a single
+ * synchronize_sched() instead.
+ *
+ * Note that it is illegal to call this function while holding any lock
+ * that is acquired by a CPU-hotplug notifier.  And yes, it is also illegal
+ * to call this function from a CPU-hotplug notifier.  Failing to observe
+ * these restriction will result in deadlock.
+ *
+ * This implementation can be thought of as an application of ticket
+ * locking to RCU, with sync_sched_expedited_started and
+ * sync_sched_expedited_done taking on the roles of the halves
+ * of the ticket-lock word.  Each task atomically increments
+ * sync_sched_expedited_started upon entry, snapshotting the old value,
+ * then attempts to stop all the CPUs.  If this succeeds, then each
+ * CPU will have executed a context switch, resulting in an RCU-sched
+ * grace period.  We are then done, so we use atomic_cmpxchg() to
+ * update sync_sched_expedited_done to match our snapshot -- but
+ * only if someone else has not already advanced past our snapshot.
+ *
+ * On the other hand, if try_stop_cpus() fails, we check the value
+ * of sync_sched_expedited_done.  If it has advanced past our
+ * initial snapshot, then someone else must have forced a grace period
+ * some time after we took our snapshot.  In this case, our work is
+ * done for us, and we can simply return.  Otherwise, we try again,
+ * but keep our initial snapshot for purposes of checking for someone
+ * doing our work for us.
+ *
+ * If we fail too many times in a row, we fall back to synchronize_sched().
+ */
+void synchronize_sched_expedited(void)
+{
+	int firstsnap, s, snap, trycount = 0;
+
+	/* Note that atomic_inc_return() implies full memory barrier. */
+	firstsnap = snap = atomic_inc_return(&sync_sched_expedited_started);
+	get_online_cpus();
+	WARN_ON_ONCE(cpu_is_offline(raw_smp_processor_id()));
+
+	/*
+	 * Each pass through the following loop attempts to force a
+	 * context switch on each CPU.
+	 */
+	while (try_stop_cpus(cpu_online_mask,
+			     synchronize_sched_expedited_cpu_stop,
+			     NULL) == -EAGAIN) {
+		put_online_cpus();
+
+		/* No joy, try again later.  Or just synchronize_sched(). */
+		if (trycount++ < 10)
+			udelay(trycount * num_online_cpus());
+		else {
+			synchronize_sched();
+			return;
+		}
+
+		/* Check to see if someone else did our work for us. */
+		s = atomic_read(&sync_sched_expedited_done);
+		if (UINT_CMP_GE((unsigned)s, (unsigned)firstsnap)) {
+			smp_mb(); /* ensure test happens before caller kfree */
+			return;
+		}
+
+		/*
+		 * Refetching sync_sched_expedited_started allows later
+		 * callers to piggyback on our grace period.  We subtract
+		 * 1 to get the same token that the last incrementer got.
+		 * We retry after they started, so our grace period works
+		 * for them, and they started after our first try, so their
+		 * grace period works for us.
+		 */
+		get_online_cpus();
+		snap = atomic_read(&sync_sched_expedited_started);
+		smp_mb(); /* ensure read is before try_stop_cpus(). */
+	}
+
+	/*
+	 * Everyone up to our most recent fetch is covered by our grace
+	 * period.  Update the counter, but only if our work is still
+	 * relevant -- which it won't be if someone who started later
+	 * than we did beat us to the punch.
+	 */
+	do {
+		s = atomic_read(&sync_sched_expedited_done);
+		if (UINT_CMP_GE((unsigned)s, (unsigned)snap)) {
+			smp_mb(); /* ensure test happens before caller kfree */
+			break;
+		}
+	} while (atomic_cmpxchg(&sync_sched_expedited_done, s, snap) != s);
+
+	put_online_cpus();
+}
+EXPORT_SYMBOL_GPL(synchronize_sched_expedited);
+
 /*
  * Check to see if there is any immediate RCU-related work to be done
  * by the current CPU, for the specified type of RCU, returning 1 if so.
@@ -1932,7 +2164,7 @@
 	/* RCU callbacks either ready or pending? */
 	return per_cpu(rcu_sched_data, cpu).nxtlist ||
 	       per_cpu(rcu_bh_data, cpu).nxtlist ||
-	       rcu_preempt_needs_cpu(cpu);
+	       rcu_preempt_cpu_has_callbacks(cpu);
 }
 
 static DEFINE_PER_CPU(struct rcu_head, rcu_barrier_head) = {NULL};
@@ -2027,9 +2259,10 @@
 	rdp->nxtlist = NULL;
 	for (i = 0; i < RCU_NEXT_SIZE; i++)
 		rdp->nxttail[i] = &rdp->nxtlist;
+	rdp->qlen_lazy = 0;
 	rdp->qlen = 0;
 	rdp->dynticks = &per_cpu(rcu_dynticks, cpu);
-	WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_NESTING);
+	WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_EXIT_IDLE);
 	WARN_ON_ONCE(atomic_read(&rdp->dynticks->dynticks) != 1);
 	rdp->cpu = cpu;
 	rdp->rsp = rsp;
@@ -2057,7 +2290,7 @@
 	rdp->qlen_last_fqs_check = 0;
 	rdp->n_force_qs_snap = rsp->n_force_qs;
 	rdp->blimit = blimit;
-	rdp->dynticks->dynticks_nesting = DYNTICK_TASK_NESTING;
+	rdp->dynticks->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
 	atomic_set(&rdp->dynticks->dynticks,
 		   (atomic_read(&rdp->dynticks->dynticks) & ~0x1) + 1);
 	rcu_prepare_for_idle_init(cpu);
@@ -2139,16 +2372,18 @@
 		 * touch any data without introducing corruption. We send the
 		 * dying CPU's callbacks to an arbitrarily chosen online CPU.
 		 */
-		rcu_send_cbs_to_online(&rcu_bh_state);
-		rcu_send_cbs_to_online(&rcu_sched_state);
-		rcu_preempt_send_cbs_to_online();
+		rcu_cleanup_dying_cpu(&rcu_bh_state);
+		rcu_cleanup_dying_cpu(&rcu_sched_state);
+		rcu_preempt_cleanup_dying_cpu();
 		rcu_cleanup_after_idle(cpu);
 		break;
 	case CPU_DEAD:
 	case CPU_DEAD_FROZEN:
 	case CPU_UP_CANCELED:
 	case CPU_UP_CANCELED_FROZEN:
-		rcu_offline_cpu(cpu);
+		rcu_cleanup_dead_cpu(cpu, &rcu_bh_state);
+		rcu_cleanup_dead_cpu(cpu, &rcu_sched_state);
+		rcu_preempt_cleanup_dead_cpu(cpu);
 		break;
 	default:
 		break;
diff --git a/kernel/rcutree.h b/kernel/rcutree.h
index fddff92..cdd1be0 100644
--- a/kernel/rcutree.h
+++ b/kernel/rcutree.h
@@ -239,6 +239,12 @@
 	bool		preemptible;	/* Preemptible RCU? */
 	struct rcu_node *mynode;	/* This CPU's leaf of hierarchy */
 	unsigned long grpmask;		/* Mask to apply to leaf qsmask. */
+#ifdef CONFIG_RCU_CPU_STALL_INFO
+	unsigned long	ticks_this_gp;	/* The number of scheduling-clock */
+					/*  ticks this CPU has handled */
+					/*  during and after the last grace */
+					/* period it is aware of. */
+#endif /* #ifdef CONFIG_RCU_CPU_STALL_INFO */
 
 	/* 2) batch handling */
 	/*
@@ -265,7 +271,8 @@
 	 */
 	struct rcu_head *nxtlist;
 	struct rcu_head **nxttail[RCU_NEXT_SIZE];
-	long		qlen;		/* # of queued callbacks */
+	long		qlen_lazy;	/* # of lazy queued callbacks */
+	long		qlen;		/* # of queued callbacks, incl lazy */
 	long		qlen_last_fqs_check;
 					/* qlen at last check for QS forcing */
 	unsigned long	n_cbs_invoked;	/* count of RCU cbs invoked. */
@@ -282,7 +289,6 @@
 	/* 4) reasons this CPU needed to be kicked by force_quiescent_state */
 	unsigned long dynticks_fqs;	/* Kicked due to dynticks idle. */
 	unsigned long offline_fqs;	/* Kicked due to being offline. */
-	unsigned long resched_ipi;	/* Sent a resched IPI. */
 
 	/* 5) __rcu_pending() statistics. */
 	unsigned long n_rcu_pending;	/* rcu_pending() calls since boot. */
@@ -313,12 +319,6 @@
 #else
 #define RCU_STALL_DELAY_DELTA	       0
 #endif
-
-#define RCU_SECONDS_TILL_STALL_CHECK   (CONFIG_RCU_CPU_STALL_TIMEOUT * HZ + \
-					RCU_STALL_DELAY_DELTA)
-						/* for rsp->jiffies_stall */
-#define RCU_SECONDS_TILL_STALL_RECHECK (3 * RCU_SECONDS_TILL_STALL_CHECK + 30)
-						/* for rsp->jiffies_stall */
 #define RCU_STALL_RAT_DELAY		2	/* Allow other CPUs time */
 						/*  to take at least one */
 						/*  scheduling clock irq */
@@ -438,8 +438,8 @@
 static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
 				     struct rcu_node *rnp,
 				     struct rcu_data *rdp);
-static void rcu_preempt_offline_cpu(int cpu);
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
+static void rcu_preempt_cleanup_dead_cpu(int cpu);
 static void rcu_preempt_check_callbacks(int cpu);
 static void rcu_preempt_process_callbacks(void);
 void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu));
@@ -448,9 +448,9 @@
 			       bool wake);
 #endif /* #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_TREE_PREEMPT_RCU) */
 static int rcu_preempt_pending(int cpu);
-static int rcu_preempt_needs_cpu(int cpu);
+static int rcu_preempt_cpu_has_callbacks(int cpu);
 static void __cpuinit rcu_preempt_init_percpu_data(int cpu);
-static void rcu_preempt_send_cbs_to_online(void);
+static void rcu_preempt_cleanup_dying_cpu(void);
 static void __init __rcu_init_preempt(void);
 static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags);
 static void rcu_preempt_boost_start_gp(struct rcu_node *rnp);
@@ -471,5 +471,10 @@
 static void rcu_prepare_for_idle_init(int cpu);
 static void rcu_cleanup_after_idle(int cpu);
 static void rcu_prepare_for_idle(int cpu);
+static void print_cpu_stall_info_begin(void);
+static void print_cpu_stall_info(struct rcu_state *rsp, int cpu);
+static void print_cpu_stall_info_end(void);
+static void zero_cpu_stall_ticks(struct rcu_data *rdp);
+static void increment_cpu_stall_ticks(void);
 
 #endif /* #ifndef RCU_TREE_NONCORE */
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index 8bb35d7..c023464 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -25,7 +25,6 @@
  */
 
 #include <linux/delay.h>
-#include <linux/stop_machine.h>
 
 #define RCU_KTHREAD_PRIO 1
 
@@ -63,7 +62,10 @@
 	printk(KERN_INFO "\tRCU torture testing starts during boot.\n");
 #endif
 #if defined(CONFIG_TREE_PREEMPT_RCU) && !defined(CONFIG_RCU_CPU_STALL_VERBOSE)
-	printk(KERN_INFO "\tVerbose stalled-CPUs detection is disabled.\n");
+	printk(KERN_INFO "\tDump stacks of tasks blocking RCU-preempt GP.\n");
+#endif
+#if defined(CONFIG_RCU_CPU_STALL_INFO)
+	printk(KERN_INFO "\tAdditional per-CPU info printed with stalls.\n");
 #endif
 #if NUM_RCU_LVL_4 != 0
 	printk(KERN_INFO "\tExperimental four-level hierarchy is enabled.\n");
@@ -490,6 +492,31 @@
 
 #endif /* #else #ifdef CONFIG_RCU_CPU_STALL_VERBOSE */
 
+#ifdef CONFIG_RCU_CPU_STALL_INFO
+
+static void rcu_print_task_stall_begin(struct rcu_node *rnp)
+{
+	printk(KERN_ERR "\tTasks blocked on level-%d rcu_node (CPUs %d-%d):",
+	       rnp->level, rnp->grplo, rnp->grphi);
+}
+
+static void rcu_print_task_stall_end(void)
+{
+	printk(KERN_CONT "\n");
+}
+
+#else /* #ifdef CONFIG_RCU_CPU_STALL_INFO */
+
+static void rcu_print_task_stall_begin(struct rcu_node *rnp)
+{
+}
+
+static void rcu_print_task_stall_end(void)
+{
+}
+
+#endif /* #else #ifdef CONFIG_RCU_CPU_STALL_INFO */
+
 /*
  * Scan the current list of tasks blocked within RCU read-side critical
  * sections, printing out the tid of each.
@@ -501,12 +528,14 @@
 
 	if (!rcu_preempt_blocked_readers_cgp(rnp))
 		return 0;
+	rcu_print_task_stall_begin(rnp);
 	t = list_entry(rnp->gp_tasks,
 		       struct task_struct, rcu_node_entry);
 	list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) {
-		printk(" P%d", t->pid);
+		printk(KERN_CONT " P%d", t->pid);
 		ndetected++;
 	}
+	rcu_print_task_stall_end();
 	return ndetected;
 }
 
@@ -581,7 +610,7 @@
 	 * absolutely necessary, but this is a good performance/complexity
 	 * tradeoff.
 	 */
-	if (rcu_preempt_blocked_readers_cgp(rnp))
+	if (rcu_preempt_blocked_readers_cgp(rnp) && rnp->qsmask == 0)
 		retval |= RCU_OFL_TASKS_NORM_GP;
 	if (rcu_preempted_readers_exp(rnp))
 		retval |= RCU_OFL_TASKS_EXP_GP;
@@ -618,16 +647,16 @@
 	return retval;
 }
 
+#endif /* #ifdef CONFIG_HOTPLUG_CPU */
+
 /*
  * Do CPU-offline processing for preemptible RCU.
  */
-static void rcu_preempt_offline_cpu(int cpu)
+static void rcu_preempt_cleanup_dead_cpu(int cpu)
 {
-	__rcu_offline_cpu(cpu, &rcu_preempt_state);
+	rcu_cleanup_dead_cpu(cpu, &rcu_preempt_state);
 }
 
-#endif /* #ifdef CONFIG_HOTPLUG_CPU */
-
 /*
  * Check for a quiescent state from the current CPU.  When a task blocks,
  * the task is recorded in the corresponding CPU's rcu_node structure,
@@ -671,10 +700,24 @@
  */
 void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
 {
-	__call_rcu(head, func, &rcu_preempt_state);
+	__call_rcu(head, func, &rcu_preempt_state, 0);
 }
 EXPORT_SYMBOL_GPL(call_rcu);
 
+/*
+ * Queue an RCU callback for lazy invocation after a grace period.
+ * This will likely be later named something like "call_rcu_lazy()",
+ * but this change will require some way of tagging the lazy RCU
+ * callbacks in the list of pending callbacks.  Until then, this
+ * function may only be called from __kfree_rcu().
+ */
+void kfree_call_rcu(struct rcu_head *head,
+		    void (*func)(struct rcu_head *rcu))
+{
+	__call_rcu(head, func, &rcu_preempt_state, 1);
+}
+EXPORT_SYMBOL_GPL(kfree_call_rcu);
+
 /**
  * synchronize_rcu - wait until a grace period has elapsed.
  *
@@ -688,6 +731,10 @@
  */
 void synchronize_rcu(void)
 {
+	rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) &&
+			   !lock_is_held(&rcu_lock_map) &&
+			   !lock_is_held(&rcu_sched_lock_map),
+			   "Illegal synchronize_rcu() in RCU read-side critical section");
 	if (!rcu_scheduler_active)
 		return;
 	wait_rcu_gp(call_rcu);
@@ -788,10 +835,22 @@
 		rcu_report_exp_rnp(rsp, rnp, false); /* Don't wake self. */
 }
 
-/*
- * Wait for an rcu-preempt grace period, but expedite it.  The basic idea
- * is to invoke synchronize_sched_expedited() to push all the tasks to
- * the ->blkd_tasks lists and wait for this list to drain.
+/**
+ * synchronize_rcu_expedited - Brute-force RCU grace period
+ *
+ * Wait for an RCU-preempt grace period, but expedite it.  The basic
+ * idea is to invoke synchronize_sched_expedited() to push all the tasks to
+ * the ->blkd_tasks lists and wait for this list to drain.  This consumes
+ * significant time on all CPUs and is unfriendly to real-time workloads,
+ * so is thus not recommended for any sort of common-case code.
+ * In fact, if you are using synchronize_rcu_expedited() in a loop,
+ * please restructure your code to batch your updates, and then Use a
+ * single synchronize_rcu() instead.
+ *
+ * Note that it is illegal to call this function while holding any lock
+ * that is acquired by a CPU-hotplug notifier.  And yes, it is also illegal
+ * to call this function from a CPU-hotplug notifier.  Failing to observe
+ * these restriction will result in deadlock.
  */
 void synchronize_rcu_expedited(void)
 {
@@ -869,9 +928,9 @@
 }
 
 /*
- * Does preemptible RCU need the CPU to stay out of dynticks mode?
+ * Does preemptible RCU have callbacks on this CPU?
  */
-static int rcu_preempt_needs_cpu(int cpu)
+static int rcu_preempt_cpu_has_callbacks(int cpu)
 {
 	return !!per_cpu(rcu_preempt_data, cpu).nxtlist;
 }
@@ -894,11 +953,12 @@
 }
 
 /*
- * Move preemptible RCU's callbacks from dying CPU to other online CPU.
+ * Move preemptible RCU's callbacks from dying CPU to other online CPU
+ * and record a quiescent state.
  */
-static void rcu_preempt_send_cbs_to_online(void)
+static void rcu_preempt_cleanup_dying_cpu(void)
 {
-	rcu_send_cbs_to_online(&rcu_preempt_state);
+	rcu_cleanup_dying_cpu(&rcu_preempt_state);
 }
 
 /*
@@ -1034,16 +1094,16 @@
 	return 0;
 }
 
+#endif /* #ifdef CONFIG_HOTPLUG_CPU */
+
 /*
  * Because preemptible RCU does not exist, it never needs CPU-offline
  * processing.
  */
-static void rcu_preempt_offline_cpu(int cpu)
+static void rcu_preempt_cleanup_dead_cpu(int cpu)
 {
 }
 
-#endif /* #ifdef CONFIG_HOTPLUG_CPU */
-
 /*
  * Because preemptible RCU does not exist, it never has any callbacks
  * to check.
@@ -1061,6 +1121,22 @@
 }
 
 /*
+ * Queue an RCU callback for lazy invocation after a grace period.
+ * This will likely be later named something like "call_rcu_lazy()",
+ * but this change will require some way of tagging the lazy RCU
+ * callbacks in the list of pending callbacks.  Until then, this
+ * function may only be called from __kfree_rcu().
+ *
+ * Because there is no preemptible RCU, we use RCU-sched instead.
+ */
+void kfree_call_rcu(struct rcu_head *head,
+		    void (*func)(struct rcu_head *rcu))
+{
+	__call_rcu(head, func, &rcu_sched_state, 1);
+}
+EXPORT_SYMBOL_GPL(kfree_call_rcu);
+
+/*
  * Wait for an rcu-preempt grace period, but make it happen quickly.
  * But because preemptible RCU does not exist, map to rcu-sched.
  */
@@ -1093,9 +1169,9 @@
 }
 
 /*
- * Because preemptible RCU does not exist, it never needs any CPU.
+ * Because preemptible RCU does not exist, it never has callbacks
  */
-static int rcu_preempt_needs_cpu(int cpu)
+static int rcu_preempt_cpu_has_callbacks(int cpu)
 {
 	return 0;
 }
@@ -1119,9 +1195,9 @@
 }
 
 /*
- * Because there is no preemptible RCU, there are no callbacks to move.
+ * Because there is no preemptible RCU, there is no cleanup to do.
  */
-static void rcu_preempt_send_cbs_to_online(void)
+static void rcu_preempt_cleanup_dying_cpu(void)
 {
 }
 
@@ -1823,132 +1899,6 @@
 
 #endif /* #else #ifdef CONFIG_RCU_BOOST */
 
-#ifndef CONFIG_SMP
-
-void synchronize_sched_expedited(void)
-{
-	cond_resched();
-}
-EXPORT_SYMBOL_GPL(synchronize_sched_expedited);
-
-#else /* #ifndef CONFIG_SMP */
-
-static atomic_t sync_sched_expedited_started = ATOMIC_INIT(0);
-static atomic_t sync_sched_expedited_done = ATOMIC_INIT(0);
-
-static int synchronize_sched_expedited_cpu_stop(void *data)
-{
-	/*
-	 * There must be a full memory barrier on each affected CPU
-	 * between the time that try_stop_cpus() is called and the
-	 * time that it returns.
-	 *
-	 * In the current initial implementation of cpu_stop, the
-	 * above condition is already met when the control reaches
-	 * this point and the following smp_mb() is not strictly
-	 * necessary.  Do smp_mb() anyway for documentation and
-	 * robustness against future implementation changes.
-	 */
-	smp_mb(); /* See above comment block. */
-	return 0;
-}
-
-/*
- * Wait for an rcu-sched grace period to elapse, but use "big hammer"
- * approach to force grace period to end quickly.  This consumes
- * significant time on all CPUs, and is thus not recommended for
- * any sort of common-case code.
- *
- * Note that it is illegal to call this function while holding any
- * lock that is acquired by a CPU-hotplug notifier.  Failing to
- * observe this restriction will result in deadlock.
- *
- * This implementation can be thought of as an application of ticket
- * locking to RCU, with sync_sched_expedited_started and
- * sync_sched_expedited_done taking on the roles of the halves
- * of the ticket-lock word.  Each task atomically increments
- * sync_sched_expedited_started upon entry, snapshotting the old value,
- * then attempts to stop all the CPUs.  If this succeeds, then each
- * CPU will have executed a context switch, resulting in an RCU-sched
- * grace period.  We are then done, so we use atomic_cmpxchg() to
- * update sync_sched_expedited_done to match our snapshot -- but
- * only if someone else has not already advanced past our snapshot.
- *
- * On the other hand, if try_stop_cpus() fails, we check the value
- * of sync_sched_expedited_done.  If it has advanced past our
- * initial snapshot, then someone else must have forced a grace period
- * some time after we took our snapshot.  In this case, our work is
- * done for us, and we can simply return.  Otherwise, we try again,
- * but keep our initial snapshot for purposes of checking for someone
- * doing our work for us.
- *
- * If we fail too many times in a row, we fall back to synchronize_sched().
- */
-void synchronize_sched_expedited(void)
-{
-	int firstsnap, s, snap, trycount = 0;
-
-	/* Note that atomic_inc_return() implies full memory barrier. */
-	firstsnap = snap = atomic_inc_return(&sync_sched_expedited_started);
-	get_online_cpus();
-
-	/*
-	 * Each pass through the following loop attempts to force a
-	 * context switch on each CPU.
-	 */
-	while (try_stop_cpus(cpu_online_mask,
-			     synchronize_sched_expedited_cpu_stop,
-			     NULL) == -EAGAIN) {
-		put_online_cpus();
-
-		/* No joy, try again later.  Or just synchronize_sched(). */
-		if (trycount++ < 10)
-			udelay(trycount * num_online_cpus());
-		else {
-			synchronize_sched();
-			return;
-		}
-
-		/* Check to see if someone else did our work for us. */
-		s = atomic_read(&sync_sched_expedited_done);
-		if (UINT_CMP_GE((unsigned)s, (unsigned)firstsnap)) {
-			smp_mb(); /* ensure test happens before caller kfree */
-			return;
-		}
-
-		/*
-		 * Refetching sync_sched_expedited_started allows later
-		 * callers to piggyback on our grace period.  We subtract
-		 * 1 to get the same token that the last incrementer got.
-		 * We retry after they started, so our grace period works
-		 * for them, and they started after our first try, so their
-		 * grace period works for us.
-		 */
-		get_online_cpus();
-		snap = atomic_read(&sync_sched_expedited_started);
-		smp_mb(); /* ensure read is before try_stop_cpus(). */
-	}
-
-	/*
-	 * Everyone up to our most recent fetch is covered by our grace
-	 * period.  Update the counter, but only if our work is still
-	 * relevant -- which it won't be if someone who started later
-	 * than we did beat us to the punch.
-	 */
-	do {
-		s = atomic_read(&sync_sched_expedited_done);
-		if (UINT_CMP_GE((unsigned)s, (unsigned)snap)) {
-			smp_mb(); /* ensure test happens before caller kfree */
-			break;
-		}
-	} while (atomic_cmpxchg(&sync_sched_expedited_done, s, snap) != s);
-
-	put_online_cpus();
-}
-EXPORT_SYMBOL_GPL(synchronize_sched_expedited);
-
-#endif /* #else #ifndef CONFIG_SMP */
-
 #if !defined(CONFIG_RCU_FAST_NO_HZ)
 
 /*
@@ -1981,7 +1931,7 @@
 }
 
 /*
- * Do the idle-entry grace-period work, which, because CONFIG_RCU_FAST_NO_HZ=y,
+ * Do the idle-entry grace-period work, which, because CONFIG_RCU_FAST_NO_HZ=n,
  * is nothing.
  */
 static void rcu_prepare_for_idle(int cpu)
@@ -2015,6 +1965,9 @@
  *	number, be warned: Setting RCU_IDLE_GP_DELAY too high can hang your
  *	system.  And if you are -that- concerned about energy efficiency,
  *	just power the system down and be done with it!
+ * RCU_IDLE_LAZY_GP_DELAY gives the number of jiffies that a CPU is
+ *	permitted to sleep in dyntick-idle mode with only lazy RCU
+ *	callbacks pending.  Setting this too high can OOM your system.
  *
  * The values below work well in practice.  If future workloads require
  * adjustment, they can be converted into kernel config parameters, though
@@ -2023,11 +1976,13 @@
 #define RCU_IDLE_FLUSHES 5		/* Number of dyntick-idle tries. */
 #define RCU_IDLE_OPT_FLUSHES 3		/* Optional dyntick-idle tries. */
 #define RCU_IDLE_GP_DELAY 6		/* Roughly one grace period. */
+#define RCU_IDLE_LAZY_GP_DELAY (6 * HZ)	/* Roughly six seconds. */
 
 static DEFINE_PER_CPU(int, rcu_dyntick_drain);
 static DEFINE_PER_CPU(unsigned long, rcu_dyntick_holdoff);
 static DEFINE_PER_CPU(struct hrtimer, rcu_idle_gp_timer);
-static ktime_t rcu_idle_gp_wait;
+static ktime_t rcu_idle_gp_wait;	/* If some non-lazy callbacks. */
+static ktime_t rcu_idle_lazy_gp_wait;	/* If only lazy callbacks. */
 
 /*
  * Allow the CPU to enter dyntick-idle mode if either: (1) There are no
@@ -2048,6 +2003,48 @@
 }
 
 /*
+ * Does the specified flavor of RCU have non-lazy callbacks pending on
+ * the specified CPU?  Both RCU flavor and CPU are specified by the
+ * rcu_data structure.
+ */
+static bool __rcu_cpu_has_nonlazy_callbacks(struct rcu_data *rdp)
+{
+	return rdp->qlen != rdp->qlen_lazy;
+}
+
+#ifdef CONFIG_TREE_PREEMPT_RCU
+
+/*
+ * Are there non-lazy RCU-preempt callbacks?  (There cannot be if there
+ * is no RCU-preempt in the kernel.)
+ */
+static bool rcu_preempt_cpu_has_nonlazy_callbacks(int cpu)
+{
+	struct rcu_data *rdp = &per_cpu(rcu_preempt_data, cpu);
+
+	return __rcu_cpu_has_nonlazy_callbacks(rdp);
+}
+
+#else /* #ifdef CONFIG_TREE_PREEMPT_RCU */
+
+static bool rcu_preempt_cpu_has_nonlazy_callbacks(int cpu)
+{
+	return 0;
+}
+
+#endif /* else #ifdef CONFIG_TREE_PREEMPT_RCU */
+
+/*
+ * Does any flavor of RCU have non-lazy callbacks on the specified CPU?
+ */
+static bool rcu_cpu_has_nonlazy_callbacks(int cpu)
+{
+	return __rcu_cpu_has_nonlazy_callbacks(&per_cpu(rcu_sched_data, cpu)) ||
+	       __rcu_cpu_has_nonlazy_callbacks(&per_cpu(rcu_bh_data, cpu)) ||
+	       rcu_preempt_cpu_has_nonlazy_callbacks(cpu);
+}
+
+/*
  * Timer handler used to force CPU to start pushing its remaining RCU
  * callbacks in the case where it entered dyntick-idle mode with callbacks
  * pending.  The hander doesn't really need to do anything because the
@@ -2074,6 +2071,8 @@
 		unsigned int upj = jiffies_to_usecs(RCU_IDLE_GP_DELAY);
 
 		rcu_idle_gp_wait = ns_to_ktime(upj * (u64)1000);
+		upj = jiffies_to_usecs(RCU_IDLE_LAZY_GP_DELAY);
+		rcu_idle_lazy_gp_wait = ns_to_ktime(upj * (u64)1000);
 		firsttime = 0;
 	}
 }
@@ -2109,10 +2108,6 @@
  */
 static void rcu_prepare_for_idle(int cpu)
 {
-	unsigned long flags;
-
-	local_irq_save(flags);
-
 	/*
 	 * If there are no callbacks on this CPU, enter dyntick-idle mode.
 	 * Also reset state to avoid prejudicing later attempts.
@@ -2120,7 +2115,6 @@
 	if (!rcu_cpu_has_callbacks(cpu)) {
 		per_cpu(rcu_dyntick_holdoff, cpu) = jiffies - 1;
 		per_cpu(rcu_dyntick_drain, cpu) = 0;
-		local_irq_restore(flags);
 		trace_rcu_prep_idle("No callbacks");
 		return;
 	}
@@ -2130,7 +2124,6 @@
 	 * refrained from disabling the scheduling-clock tick.
 	 */
 	if (per_cpu(rcu_dyntick_holdoff, cpu) == jiffies) {
-		local_irq_restore(flags);
 		trace_rcu_prep_idle("In holdoff");
 		return;
 	}
@@ -2140,18 +2133,22 @@
 		/* First time through, initialize the counter. */
 		per_cpu(rcu_dyntick_drain, cpu) = RCU_IDLE_FLUSHES;
 	} else if (per_cpu(rcu_dyntick_drain, cpu) <= RCU_IDLE_OPT_FLUSHES &&
-		   !rcu_pending(cpu)) {
+		   !rcu_pending(cpu) &&
+		   !local_softirq_pending()) {
 		/* Can we go dyntick-idle despite still having callbacks? */
 		trace_rcu_prep_idle("Dyntick with callbacks");
 		per_cpu(rcu_dyntick_drain, cpu) = 0;
-		per_cpu(rcu_dyntick_holdoff, cpu) = jiffies - 1;
-		hrtimer_start(&per_cpu(rcu_idle_gp_timer, cpu),
-			      rcu_idle_gp_wait, HRTIMER_MODE_REL);
+		per_cpu(rcu_dyntick_holdoff, cpu) = jiffies;
+		if (rcu_cpu_has_nonlazy_callbacks(cpu))
+			hrtimer_start(&per_cpu(rcu_idle_gp_timer, cpu),
+				      rcu_idle_gp_wait, HRTIMER_MODE_REL);
+		else
+			hrtimer_start(&per_cpu(rcu_idle_gp_timer, cpu),
+				      rcu_idle_lazy_gp_wait, HRTIMER_MODE_REL);
 		return; /* Nothing more to do immediately. */
 	} else if (--per_cpu(rcu_dyntick_drain, cpu) <= 0) {
 		/* We have hit the limit, so time to give up. */
 		per_cpu(rcu_dyntick_holdoff, cpu) = jiffies;
-		local_irq_restore(flags);
 		trace_rcu_prep_idle("Begin holdoff");
 		invoke_rcu_core();  /* Force the CPU out of dyntick-idle. */
 		return;
@@ -2163,23 +2160,17 @@
 	 */
 #ifdef CONFIG_TREE_PREEMPT_RCU
 	if (per_cpu(rcu_preempt_data, cpu).nxtlist) {
-		local_irq_restore(flags);
 		rcu_preempt_qs(cpu);
 		force_quiescent_state(&rcu_preempt_state, 0);
-		local_irq_save(flags);
 	}
 #endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
 	if (per_cpu(rcu_sched_data, cpu).nxtlist) {
-		local_irq_restore(flags);
 		rcu_sched_qs(cpu);
 		force_quiescent_state(&rcu_sched_state, 0);
-		local_irq_save(flags);
 	}
 	if (per_cpu(rcu_bh_data, cpu).nxtlist) {
-		local_irq_restore(flags);
 		rcu_bh_qs(cpu);
 		force_quiescent_state(&rcu_bh_state, 0);
-		local_irq_save(flags);
 	}
 
 	/*
@@ -2187,13 +2178,124 @@
 	 * So try forcing the callbacks through the grace period.
 	 */
 	if (rcu_cpu_has_callbacks(cpu)) {
-		local_irq_restore(flags);
 		trace_rcu_prep_idle("More callbacks");
 		invoke_rcu_core();
-	} else {
-		local_irq_restore(flags);
+	} else
 		trace_rcu_prep_idle("Callbacks drained");
-	}
 }
 
 #endif /* #else #if !defined(CONFIG_RCU_FAST_NO_HZ) */
+
+#ifdef CONFIG_RCU_CPU_STALL_INFO
+
+#ifdef CONFIG_RCU_FAST_NO_HZ
+
+static void print_cpu_stall_fast_no_hz(char *cp, int cpu)
+{
+	struct hrtimer *hrtp = &per_cpu(rcu_idle_gp_timer, cpu);
+
+	sprintf(cp, "drain=%d %c timer=%lld",
+		per_cpu(rcu_dyntick_drain, cpu),
+		per_cpu(rcu_dyntick_holdoff, cpu) == jiffies ? 'H' : '.',
+		hrtimer_active(hrtp)
+			? ktime_to_us(hrtimer_get_remaining(hrtp))
+			: -1);
+}
+
+#else /* #ifdef CONFIG_RCU_FAST_NO_HZ */
+
+static void print_cpu_stall_fast_no_hz(char *cp, int cpu)
+{
+}
+
+#endif /* #else #ifdef CONFIG_RCU_FAST_NO_HZ */
+
+/* Initiate the stall-info list. */
+static void print_cpu_stall_info_begin(void)
+{
+	printk(KERN_CONT "\n");
+}
+
+/*
+ * Print out diagnostic information for the specified stalled CPU.
+ *
+ * If the specified CPU is aware of the current RCU grace period
+ * (flavor specified by rsp), then print the number of scheduling
+ * clock interrupts the CPU has taken during the time that it has
+ * been aware.  Otherwise, print the number of RCU grace periods
+ * that this CPU is ignorant of, for example, "1" if the CPU was
+ * aware of the previous grace period.
+ *
+ * Also print out idle and (if CONFIG_RCU_FAST_NO_HZ) idle-entry info.
+ */
+static void print_cpu_stall_info(struct rcu_state *rsp, int cpu)
+{
+	char fast_no_hz[72];
+	struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
+	struct rcu_dynticks *rdtp = rdp->dynticks;
+	char *ticks_title;
+	unsigned long ticks_value;
+
+	if (rsp->gpnum == rdp->gpnum) {
+		ticks_title = "ticks this GP";
+		ticks_value = rdp->ticks_this_gp;
+	} else {
+		ticks_title = "GPs behind";
+		ticks_value = rsp->gpnum - rdp->gpnum;
+	}
+	print_cpu_stall_fast_no_hz(fast_no_hz, cpu);
+	printk(KERN_ERR "\t%d: (%lu %s) idle=%03x/%llx/%d %s\n",
+	       cpu, ticks_value, ticks_title,
+	       atomic_read(&rdtp->dynticks) & 0xfff,
+	       rdtp->dynticks_nesting, rdtp->dynticks_nmi_nesting,
+	       fast_no_hz);
+}
+
+/* Terminate the stall-info list. */
+static void print_cpu_stall_info_end(void)
+{
+	printk(KERN_ERR "\t");
+}
+
+/* Zero ->ticks_this_gp for all flavors of RCU. */
+static void zero_cpu_stall_ticks(struct rcu_data *rdp)
+{
+	rdp->ticks_this_gp = 0;
+}
+
+/* Increment ->ticks_this_gp for all flavors of RCU. */
+static void increment_cpu_stall_ticks(void)
+{
+	__get_cpu_var(rcu_sched_data).ticks_this_gp++;
+	__get_cpu_var(rcu_bh_data).ticks_this_gp++;
+#ifdef CONFIG_TREE_PREEMPT_RCU
+	__get_cpu_var(rcu_preempt_data).ticks_this_gp++;
+#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
+}
+
+#else /* #ifdef CONFIG_RCU_CPU_STALL_INFO */
+
+static void print_cpu_stall_info_begin(void)
+{
+	printk(KERN_CONT " {");
+}
+
+static void print_cpu_stall_info(struct rcu_state *rsp, int cpu)
+{
+	printk(KERN_CONT " %d", cpu);
+}
+
+static void print_cpu_stall_info_end(void)
+{
+	printk(KERN_CONT "} ");
+}
+
+static void zero_cpu_stall_ticks(struct rcu_data *rdp)
+{
+}
+
+static void increment_cpu_stall_ticks(void)
+{
+}
+
+#endif /* #else #ifdef CONFIG_RCU_CPU_STALL_INFO */
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c
index 654cfe6..ed459ed 100644
--- a/kernel/rcutree_trace.c
+++ b/kernel/rcutree_trace.c
@@ -72,9 +72,9 @@
 		   rdp->dynticks->dynticks_nesting,
 		   rdp->dynticks->dynticks_nmi_nesting,
 		   rdp->dynticks_fqs);
-	seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi);
-	seq_printf(m, " ql=%ld qs=%c%c%c%c",
-		   rdp->qlen,
+	seq_printf(m, " of=%lu", rdp->offline_fqs);
+	seq_printf(m, " ql=%ld/%ld qs=%c%c%c%c",
+		   rdp->qlen_lazy, rdp->qlen,
 		   ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] !=
 			rdp->nxttail[RCU_NEXT_TAIL]],
 		   ".R"[rdp->nxttail[RCU_WAIT_TAIL] !=
@@ -144,8 +144,8 @@
 		   rdp->dynticks->dynticks_nesting,
 		   rdp->dynticks->dynticks_nmi_nesting,
 		   rdp->dynticks_fqs);
-	seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi);
-	seq_printf(m, ",%ld,\"%c%c%c%c\"", rdp->qlen,
+	seq_printf(m, ",%lu", rdp->offline_fqs);
+	seq_printf(m, ",%ld,%ld,\"%c%c%c%c\"", rdp->qlen_lazy, rdp->qlen,
 		   ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] !=
 			rdp->nxttail[RCU_NEXT_TAIL]],
 		   ".R"[rdp->nxttail[RCU_WAIT_TAIL] !=
@@ -168,7 +168,7 @@
 {
 	seq_puts(m, "\"CPU\",\"Online?\",\"c\",\"g\",\"pq\",\"pgp\",\"pq\",");
 	seq_puts(m, "\"dt\",\"dt nesting\",\"dt NMI nesting\",\"df\",");
-	seq_puts(m, "\"of\",\"ri\",\"ql\",\"qs\"");
+	seq_puts(m, "\"of\",\"qll\",\"ql\",\"qs\"");
 #ifdef CONFIG_RCU_BOOST
 	seq_puts(m, "\"kt\",\"ktl\"");
 #endif /* #ifdef CONFIG_RCU_BOOST */
diff --git a/kernel/sched/auto_group.c b/kernel/sched/auto_group.c
index e8a1f83..0984a21 100644
--- a/kernel/sched/auto_group.c
+++ b/kernel/sched/auto_group.c
@@ -195,20 +195,20 @@
 
 #ifdef CONFIG_PROC_FS
 
-int proc_sched_autogroup_set_nice(struct task_struct *p, int *nice)
+int proc_sched_autogroup_set_nice(struct task_struct *p, int nice)
 {
 	static unsigned long next = INITIAL_JIFFIES;
 	struct autogroup *ag;
 	int err;
 
-	if (*nice < -20 || *nice > 19)
+	if (nice < -20 || nice > 19)
 		return -EINVAL;
 
-	err = security_task_setnice(current, *nice);
+	err = security_task_setnice(current, nice);
 	if (err)
 		return err;
 
-	if (*nice < 0 && !can_nice(current, *nice))
+	if (nice < 0 && !can_nice(current, nice))
 		return -EPERM;
 
 	/* this is a heavy operation taking global locks.. */
@@ -219,9 +219,9 @@
 	ag = autogroup_task_get(p);
 
 	down_write(&ag->lock);
-	err = sched_group_set_shares(ag->tg, prio_to_weight[*nice + 20]);
+	err = sched_group_set_shares(ag->tg, prio_to_weight[nice + 20]);
 	if (!err)
-		ag->nice = *nice;
+		ag->nice = nice;
 	up_write(&ag->lock);
 
 	autogroup_kref_put(ag);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index b342f57..a35cb8db 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -162,13 +162,13 @@
 
 #ifdef HAVE_JUMP_LABEL
 
-#define jump_label_key__true  jump_label_key_enabled
-#define jump_label_key__false jump_label_key_disabled
+#define jump_label_key__true  STATIC_KEY_INIT_TRUE
+#define jump_label_key__false STATIC_KEY_INIT_FALSE
 
 #define SCHED_FEAT(name, enabled)	\
 	jump_label_key__##enabled ,
 
-struct jump_label_key sched_feat_keys[__SCHED_FEAT_NR] = {
+struct static_key sched_feat_keys[__SCHED_FEAT_NR] = {
 #include "features.h"
 };
 
@@ -176,14 +176,14 @@
 
 static void sched_feat_disable(int i)
 {
-	if (jump_label_enabled(&sched_feat_keys[i]))
-		jump_label_dec(&sched_feat_keys[i]);
+	if (static_key_enabled(&sched_feat_keys[i]))
+		static_key_slow_dec(&sched_feat_keys[i]);
 }
 
 static void sched_feat_enable(int i)
 {
-	if (!jump_label_enabled(&sched_feat_keys[i]))
-		jump_label_inc(&sched_feat_keys[i]);
+	if (!static_key_enabled(&sched_feat_keys[i]))
+		static_key_slow_inc(&sched_feat_keys[i]);
 }
 #else
 static void sched_feat_disable(int i) { };
@@ -894,7 +894,7 @@
 	delta -= irq_delta;
 #endif
 #ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
-	if (static_branch((&paravirt_steal_rq_enabled))) {
+	if (static_key_false((&paravirt_steal_rq_enabled))) {
 		u64 st;
 
 		steal = paravirt_steal_clock(cpu_of(rq));
@@ -1284,7 +1284,7 @@
 	 * leave kernel.
 	 */
 	if (p->mm && printk_ratelimit()) {
-		printk(KERN_INFO "process %d (%s) no longer affine to cpu%d\n",
+		printk_sched("process %d (%s) no longer affine to cpu%d\n",
 				task_pid_nr(p), p->comm, cpu);
 	}
 
@@ -1507,7 +1507,7 @@
 }
 #endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */
 
-static inline int ttwu_share_cache(int this_cpu, int that_cpu)
+bool cpus_share_cache(int this_cpu, int that_cpu)
 {
 	return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu);
 }
@@ -1518,7 +1518,7 @@
 	struct rq *rq = cpu_rq(cpu);
 
 #if defined(CONFIG_SMP)
-	if (sched_feat(TTWU_QUEUE) && !ttwu_share_cache(smp_processor_id(), cpu)) {
+	if (sched_feat(TTWU_QUEUE) && !cpus_share_cache(smp_processor_id(), cpu)) {
 		sched_clock_cpu(cpu); /* sync clocks x-cpu */
 		ttwu_queue_remote(p, cpu);
 		return;
@@ -2266,13 +2266,10 @@
  * Once we've updated the global active value, we need to apply the exponential
  * weights adjusted to the number of cycles missed.
  */
-static void calc_global_nohz(unsigned long ticks)
+static void calc_global_nohz(void)
 {
 	long delta, active, n;
 
-	if (time_before(jiffies, calc_load_update))
-		return;
-
 	/*
 	 * If we crossed a calc_load_update boundary, make sure to fold
 	 * any pending idle changes, the respective CPUs might have
@@ -2284,31 +2281,25 @@
 		atomic_long_add(delta, &calc_load_tasks);
 
 	/*
-	 * If we were idle for multiple load cycles, apply them.
+	 * It could be the one fold was all it took, we done!
 	 */
-	if (ticks >= LOAD_FREQ) {
-		n = ticks / LOAD_FREQ;
-
-		active = atomic_long_read(&calc_load_tasks);
-		active = active > 0 ? active * FIXED_1 : 0;
-
-		avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n);
-		avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n);
-		avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
-
-		calc_load_update += n * LOAD_FREQ;
-	}
+	if (time_before(jiffies, calc_load_update + 10))
+		return;
 
 	/*
-	 * Its possible the remainder of the above division also crosses
-	 * a LOAD_FREQ period, the regular check in calc_global_load()
-	 * which comes after this will take care of that.
-	 *
-	 * Consider us being 11 ticks before a cycle completion, and us
-	 * sleeping for 4*LOAD_FREQ + 22 ticks, then the above code will
-	 * age us 4 cycles, and the test in calc_global_load() will
-	 * pick up the final one.
+	 * Catch-up, fold however many we are behind still
 	 */
+	delta = jiffies - calc_load_update - 10;
+	n = 1 + (delta / LOAD_FREQ);
+
+	active = atomic_long_read(&calc_load_tasks);
+	active = active > 0 ? active * FIXED_1 : 0;
+
+	avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n);
+	avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n);
+	avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
+
+	calc_load_update += n * LOAD_FREQ;
 }
 #else
 void calc_load_account_idle(struct rq *this_rq)
@@ -2320,7 +2311,7 @@
 	return 0;
 }
 
-static void calc_global_nohz(unsigned long ticks)
+static void calc_global_nohz(void)
 {
 }
 #endif
@@ -2348,8 +2339,6 @@
 {
 	long active;
 
-	calc_global_nohz(ticks);
-
 	if (time_before(jiffies, calc_load_update + 10))
 		return;
 
@@ -2361,6 +2350,16 @@
 	avenrun[2] = calc_load(avenrun[2], EXP_15, active);
 
 	calc_load_update += LOAD_FREQ;
+
+	/*
+	 * Account one period with whatever state we found before
+	 * folding in the nohz state and ageing the entire idle period.
+	 *
+	 * This avoids loosing a sample when we go idle between 
+	 * calc_load_account_active() (10 ticks ago) and now and thus
+	 * under-accounting.
+	 */
+	calc_global_nohz();
 }
 
 /*
@@ -2755,7 +2754,7 @@
 static __always_inline bool steal_account_process_tick(void)
 {
 #ifdef CONFIG_PARAVIRT
-	if (static_branch(&paravirt_steal_enabled)) {
+	if (static_key_false(&paravirt_steal_enabled)) {
 		u64 steal, st = 0;
 
 		steal = paravirt_steal_clock(smp_processor_id());
@@ -3220,14 +3219,14 @@
 
 	post_schedule(rq);
 
-	preempt_enable_no_resched();
+	sched_preempt_enable_no_resched();
 	if (need_resched())
 		goto need_resched;
 }
 
 static inline void sched_submit_work(struct task_struct *tsk)
 {
-	if (!tsk->state)
+	if (!tsk->state || tsk_is_pi_blocked(tsk))
 		return;
 	/*
 	 * If we are going to sleep and we have plugged IO queued,
@@ -3246,6 +3245,18 @@
 }
 EXPORT_SYMBOL(schedule);
 
+/**
+ * schedule_preempt_disabled - called with preemption disabled
+ *
+ * Returns with preemption disabled. Note: preempt_count must be 1
+ */
+void __sched schedule_preempt_disabled(void)
+{
+	sched_preempt_enable_no_resched();
+	schedule();
+	preempt_disable();
+}
+
 #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
 
 static inline bool owner_running(struct mutex *lock, struct task_struct *owner)
@@ -3406,9 +3417,9 @@
 /*
  * Same as __wake_up but called with the spinlock in wait_queue_head_t held.
  */
-void __wake_up_locked(wait_queue_head_t *q, unsigned int mode)
+void __wake_up_locked(wait_queue_head_t *q, unsigned int mode, int nr)
 {
-	__wake_up_common(q, mode, 1, 0, NULL);
+	__wake_up_common(q, mode, nr, 0, NULL);
 }
 EXPORT_SYMBOL_GPL(__wake_up_locked);
 
@@ -3767,6 +3778,24 @@
 
 	rq = __task_rq_lock(p);
 
+	/*
+	 * Idle task boosting is a nono in general. There is one
+	 * exception, when PREEMPT_RT and NOHZ is active:
+	 *
+	 * The idle task calls get_next_timer_interrupt() and holds
+	 * the timer wheel base->lock on the CPU and another CPU wants
+	 * to access the timer (probably to cancel it). We can safely
+	 * ignore the boosting request, as the idle CPU runs this code
+	 * with interrupts disabled and will complete the lock
+	 * protected section without being interrupted. So there is no
+	 * real need to boost.
+	 */
+	if (unlikely(p == rq->idle)) {
+		WARN_ON(p != rq->curr);
+		WARN_ON(p->pi_blocked_on);
+		goto out_unlock;
+	}
+
 	trace_sched_pi_setprio(p, prio);
 	oldprio = p->prio;
 	prev_class = p->sched_class;
@@ -3790,11 +3819,10 @@
 		enqueue_task(rq, p, oldprio < prio ? ENQUEUE_HEAD : 0);
 
 	check_class_changed(rq, p, prev_class, oldprio);
+out_unlock:
 	__task_rq_unlock(rq);
 }
-
 #endif
-
 void set_user_nice(struct task_struct *p, long nice)
 {
 	int old_prio, delta, on_rq;
@@ -4474,7 +4502,7 @@
 	__release(rq->lock);
 	spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
 	do_raw_spin_unlock(&rq->lock);
-	preempt_enable_no_resched();
+	sched_preempt_enable_no_resched();
 
 	schedule();
 
@@ -4548,8 +4576,24 @@
 /**
  * yield - yield the current processor to other threads.
  *
- * This is a shortcut for kernel-space yielding - it marks the
- * thread runnable and calls sys_sched_yield().
+ * Do not ever use this function, there's a 99% chance you're doing it wrong.
+ *
+ * The scheduler is at all times free to pick the calling task as the most
+ * eligible task to run, if removing the yield() call from your code breaks
+ * it, its already broken.
+ *
+ * Typical broken usage is:
+ *
+ * while (!event)
+ * 	yield();
+ *
+ * where one assumes that yield() will let 'the other' process run that will
+ * make event true. If the current task is a SCHED_FIFO task that will never
+ * happen. Never use yield() as a progress guarantee!!
+ *
+ * If you want to use yield() to wait for something, use wait_event().
+ * If you want to use yield() to be 'nice' for others, use cond_resched().
+ * If you still want to use yield(), do not!
  */
 void __sched yield(void)
 {
@@ -5381,7 +5425,7 @@
 				      unsigned long action, void *hcpu)
 {
 	switch (action & ~CPU_TASKS_FROZEN) {
-	case CPU_ONLINE:
+	case CPU_STARTING:
 	case CPU_DOWN_FAILED:
 		set_cpu_active((long)hcpu, true);
 		return NOTIFY_OK;
@@ -5753,7 +5797,7 @@
  *
  * Also keep a unique ID per domain (we use the first cpu number in
  * the cpumask of the domain), this allows us to quickly tell if
- * two cpus are in the same cache domain, see ttwu_share_cache().
+ * two cpus are in the same cache domain, see cpus_share_cache().
  */
 DEFINE_PER_CPU(struct sched_domain *, sd_llc);
 DEFINE_PER_CPU(int, sd_llc_id);
@@ -6930,6 +6974,9 @@
 		rq->online = 0;
 		rq->idle_stamp = 0;
 		rq->avg_idle = 2*sysctl_sched_migration_cost;
+
+		INIT_LIST_HEAD(&rq->cfs_tasks);
+
 		rq_attach_root(rq, &def_root_domain);
 #ifdef CONFIG_NO_HZ
 		rq->nohz_flags = 0;
@@ -7524,8 +7571,7 @@
 			    struct task_group, css);
 }
 
-static struct cgroup_subsys_state *
-cpu_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cgrp)
+static struct cgroup_subsys_state *cpu_cgroup_create(struct cgroup *cgrp)
 {
 	struct task_group *tg, *parent;
 
@@ -7542,15 +7588,14 @@
 	return &tg->css;
 }
 
-static void
-cpu_cgroup_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp)
+static void cpu_cgroup_destroy(struct cgroup *cgrp)
 {
 	struct task_group *tg = cgroup_tg(cgrp);
 
 	sched_destroy_group(tg);
 }
 
-static int cpu_cgroup_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
+static int cpu_cgroup_can_attach(struct cgroup *cgrp,
 				 struct cgroup_taskset *tset)
 {
 	struct task_struct *task;
@@ -7568,7 +7613,7 @@
 	return 0;
 }
 
-static void cpu_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
+static void cpu_cgroup_attach(struct cgroup *cgrp,
 			      struct cgroup_taskset *tset)
 {
 	struct task_struct *task;
@@ -7578,8 +7623,8 @@
 }
 
 static void
-cpu_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp,
-		struct cgroup *old_cgrp, struct task_struct *task)
+cpu_cgroup_exit(struct cgroup *cgrp, struct cgroup *old_cgrp,
+		struct task_struct *task)
 {
 	/*
 	 * cgroup_exit() is called in the copy_process() failure path.
@@ -7929,8 +7974,7 @@
  */
 
 /* create a new cpu accounting group */
-static struct cgroup_subsys_state *cpuacct_create(
-	struct cgroup_subsys *ss, struct cgroup *cgrp)
+static struct cgroup_subsys_state *cpuacct_create(struct cgroup *cgrp)
 {
 	struct cpuacct *ca;
 
@@ -7960,8 +8004,7 @@
 }
 
 /* destroy an existing cpu accounting group */
-static void
-cpuacct_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp)
+static void cpuacct_destroy(struct cgroup *cgrp)
 {
 	struct cpuacct *ca = cgroup_ca(cgrp);
 
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index 2a075e1..09acaa1 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -288,7 +288,6 @@
 
 	P(yld_count);
 
-	P(sched_switch);
 	P(sched_count);
 	P(sched_goidle);
 #ifdef CONFIG_SMP
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index aca16b8..94340c7 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -776,29 +776,16 @@
  * Scheduling class queueing methods:
  */
 
-#if defined CONFIG_SMP && defined CONFIG_FAIR_GROUP_SCHED
-static void
-add_cfs_task_weight(struct cfs_rq *cfs_rq, unsigned long weight)
-{
-	cfs_rq->task_weight += weight;
-}
-#else
-static inline void
-add_cfs_task_weight(struct cfs_rq *cfs_rq, unsigned long weight)
-{
-}
-#endif
-
 static void
 account_entity_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
 	update_load_add(&cfs_rq->load, se->load.weight);
 	if (!parent_entity(se))
 		update_load_add(&rq_of(cfs_rq)->load, se->load.weight);
-	if (entity_is_task(se)) {
-		add_cfs_task_weight(cfs_rq, se->load.weight);
-		list_add(&se->group_node, &cfs_rq->tasks);
-	}
+#ifdef CONFIG_SMP
+	if (entity_is_task(se))
+		list_add_tail(&se->group_node, &rq_of(cfs_rq)->cfs_tasks);
+#endif
 	cfs_rq->nr_running++;
 }
 
@@ -808,10 +795,8 @@
 	update_load_sub(&cfs_rq->load, se->load.weight);
 	if (!parent_entity(se))
 		update_load_sub(&rq_of(cfs_rq)->load, se->load.weight);
-	if (entity_is_task(se)) {
-		add_cfs_task_weight(cfs_rq, -se->load.weight);
+	if (entity_is_task(se))
 		list_del_init(&se->group_node);
-	}
 	cfs_rq->nr_running--;
 }
 
@@ -1401,20 +1386,20 @@
 #ifdef CONFIG_CFS_BANDWIDTH
 
 #ifdef HAVE_JUMP_LABEL
-static struct jump_label_key __cfs_bandwidth_used;
+static struct static_key __cfs_bandwidth_used;
 
 static inline bool cfs_bandwidth_used(void)
 {
-	return static_branch(&__cfs_bandwidth_used);
+	return static_key_false(&__cfs_bandwidth_used);
 }
 
 void account_cfs_bandwidth_used(int enabled, int was_enabled)
 {
 	/* only need to count groups transitioning between enabled/!enabled */
 	if (enabled && !was_enabled)
-		jump_label_inc(&__cfs_bandwidth_used);
+		static_key_slow_inc(&__cfs_bandwidth_used);
 	else if (!enabled && was_enabled)
-		jump_label_dec(&__cfs_bandwidth_used);
+		static_key_slow_dec(&__cfs_bandwidth_used);
 }
 #else /* HAVE_JUMP_LABEL */
 static bool cfs_bandwidth_used(void)
@@ -2672,8 +2657,6 @@
 	/*
 	 * Otherwise, iterate the domains and find an elegible idle cpu.
 	 */
-	rcu_read_lock();
-
 	sd = rcu_dereference(per_cpu(sd_llc, target));
 	for_each_lower_domain(sd) {
 		sg = sd->groups;
@@ -2695,8 +2678,6 @@
 		} while (sg != sd->groups);
 	}
 done:
-	rcu_read_unlock();
-
 	return target;
 }
 
@@ -2922,7 +2903,7 @@
 		return;
 
 	/*
-	 * This is possible from callers such as pull_task(), in which we
+	 * This is possible from callers such as move_task(), in which we
 	 * unconditionally check_prempt_curr() after an enqueue (which may have
 	 * lead to a throttle).  This both saves work and prevents false
 	 * next-buddy nomination below.
@@ -3086,17 +3067,39 @@
  * Fair scheduling class load-balancing methods:
  */
 
+static unsigned long __read_mostly max_load_balance_interval = HZ/10;
+
+#define LBF_ALL_PINNED	0x01
+#define LBF_NEED_BREAK	0x02
+
+struct lb_env {
+	struct sched_domain	*sd;
+
+	int			src_cpu;
+	struct rq		*src_rq;
+
+	int			dst_cpu;
+	struct rq		*dst_rq;
+
+	enum cpu_idle_type	idle;
+	long			load_move;
+	unsigned int		flags;
+
+	unsigned int		loop;
+	unsigned int		loop_break;
+	unsigned int		loop_max;
+};
+
 /*
- * pull_task - move a task from a remote runqueue to the local runqueue.
+ * move_task - move a task from one runqueue to another runqueue.
  * Both runqueues must be locked.
  */
-static void pull_task(struct rq *src_rq, struct task_struct *p,
-		      struct rq *this_rq, int this_cpu)
+static void move_task(struct task_struct *p, struct lb_env *env)
 {
-	deactivate_task(src_rq, p, 0);
-	set_task_cpu(p, this_cpu);
-	activate_task(this_rq, p, 0);
-	check_preempt_curr(this_rq, p, 0);
+	deactivate_task(env->src_rq, p, 0);
+	set_task_cpu(p, env->dst_cpu);
+	activate_task(env->dst_rq, p, 0);
+	check_preempt_curr(env->dst_rq, p, 0);
 }
 
 /*
@@ -3131,19 +3134,11 @@
 	return delta < (s64)sysctl_sched_migration_cost;
 }
 
-#define LBF_ALL_PINNED	0x01
-#define LBF_NEED_BREAK	0x02	/* clears into HAD_BREAK */
-#define LBF_HAD_BREAK	0x04
-#define LBF_HAD_BREAKS	0x0C	/* count HAD_BREAKs overflows into ABORT */
-#define LBF_ABORT	0x10
-
 /*
  * can_migrate_task - may task p from runqueue rq be migrated to this_cpu?
  */
 static
-int can_migrate_task(struct task_struct *p, struct rq *rq, int this_cpu,
-		     struct sched_domain *sd, enum cpu_idle_type idle,
-		     int *lb_flags)
+int can_migrate_task(struct task_struct *p, struct lb_env *env)
 {
 	int tsk_cache_hot = 0;
 	/*
@@ -3152,13 +3147,13 @@
 	 * 2) cannot be migrated to this CPU due to cpus_allowed, or
 	 * 3) are cache-hot on their current CPU.
 	 */
-	if (!cpumask_test_cpu(this_cpu, tsk_cpus_allowed(p))) {
+	if (!cpumask_test_cpu(env->dst_cpu, tsk_cpus_allowed(p))) {
 		schedstat_inc(p, se.statistics.nr_failed_migrations_affine);
 		return 0;
 	}
-	*lb_flags &= ~LBF_ALL_PINNED;
+	env->flags &= ~LBF_ALL_PINNED;
 
-	if (task_running(rq, p)) {
+	if (task_running(env->src_rq, p)) {
 		schedstat_inc(p, se.statistics.nr_failed_migrations_running);
 		return 0;
 	}
@@ -3169,12 +3164,12 @@
 	 * 2) too many balance attempts have failed.
 	 */
 
-	tsk_cache_hot = task_hot(p, rq->clock_task, sd);
+	tsk_cache_hot = task_hot(p, env->src_rq->clock_task, env->sd);
 	if (!tsk_cache_hot ||
-		sd->nr_balance_failed > sd->cache_nice_tries) {
+		env->sd->nr_balance_failed > env->sd->cache_nice_tries) {
 #ifdef CONFIG_SCHEDSTATS
 		if (tsk_cache_hot) {
-			schedstat_inc(sd, lb_hot_gained[idle]);
+			schedstat_inc(env->sd, lb_hot_gained[env->idle]);
 			schedstat_inc(p, se.statistics.nr_forced_migrations);
 		}
 #endif
@@ -3195,65 +3190,80 @@
  *
  * Called with both runqueues locked.
  */
-static int
-move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest,
-	      struct sched_domain *sd, enum cpu_idle_type idle)
+static int move_one_task(struct lb_env *env)
 {
 	struct task_struct *p, *n;
-	struct cfs_rq *cfs_rq;
-	int pinned = 0;
 
-	for_each_leaf_cfs_rq(busiest, cfs_rq) {
-		list_for_each_entry_safe(p, n, &cfs_rq->tasks, se.group_node) {
-			if (throttled_lb_pair(task_group(p),
-					      busiest->cpu, this_cpu))
-				break;
+	list_for_each_entry_safe(p, n, &env->src_rq->cfs_tasks, se.group_node) {
+		if (throttled_lb_pair(task_group(p), env->src_rq->cpu, env->dst_cpu))
+			continue;
 
-			if (!can_migrate_task(p, busiest, this_cpu,
-						sd, idle, &pinned))
-				continue;
+		if (!can_migrate_task(p, env))
+			continue;
 
-			pull_task(busiest, p, this_rq, this_cpu);
-			/*
-			 * Right now, this is only the second place pull_task()
-			 * is called, so we can safely collect pull_task()
-			 * stats here rather than inside pull_task().
-			 */
-			schedstat_inc(sd, lb_gained[idle]);
-			return 1;
-		}
+		move_task(p, env);
+		/*
+		 * Right now, this is only the second place move_task()
+		 * is called, so we can safely collect move_task()
+		 * stats here rather than inside move_task().
+		 */
+		schedstat_inc(env->sd, lb_gained[env->idle]);
+		return 1;
 	}
-
 	return 0;
 }
 
-static unsigned long
-balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
-	      unsigned long max_load_move, struct sched_domain *sd,
-	      enum cpu_idle_type idle, int *lb_flags,
-	      struct cfs_rq *busiest_cfs_rq)
+static unsigned long task_h_load(struct task_struct *p);
+
+/*
+ * move_tasks tries to move up to load_move weighted load from busiest to
+ * this_rq, as part of a balancing operation within domain "sd".
+ * Returns 1 if successful and 0 otherwise.
+ *
+ * Called with both runqueues locked.
+ */
+static int move_tasks(struct lb_env *env)
 {
-	int loops = 0, pulled = 0;
-	long rem_load_move = max_load_move;
-	struct task_struct *p, *n;
+	struct list_head *tasks = &env->src_rq->cfs_tasks;
+	struct task_struct *p;
+	unsigned long load;
+	int pulled = 0;
 
-	if (max_load_move == 0)
-		goto out;
+	if (env->load_move <= 0)
+		return 0;
 
-	list_for_each_entry_safe(p, n, &busiest_cfs_rq->tasks, se.group_node) {
-		if (loops++ > sysctl_sched_nr_migrate) {
-			*lb_flags |= LBF_NEED_BREAK;
+	while (!list_empty(tasks)) {
+		p = list_first_entry(tasks, struct task_struct, se.group_node);
+
+		env->loop++;
+		/* We've more or less seen every task there is, call it quits */
+		if (env->loop > env->loop_max)
+			break;
+
+		/* take a breather every nr_migrate tasks */
+		if (env->loop > env->loop_break) {
+			env->loop_break += sysctl_sched_nr_migrate;
+			env->flags |= LBF_NEED_BREAK;
 			break;
 		}
 
-		if ((p->se.load.weight >> 1) > rem_load_move ||
-		    !can_migrate_task(p, busiest, this_cpu, sd, idle,
-				      lb_flags))
-			continue;
+		if (throttled_lb_pair(task_group(p), env->src_cpu, env->dst_cpu))
+			goto next;
 
-		pull_task(busiest, p, this_rq, this_cpu);
+		load = task_h_load(p);
+
+		if (load < 16 && !env->sd->nr_balance_failed)
+			goto next;
+
+		if ((load / 2) > env->load_move)
+			goto next;
+
+		if (!can_migrate_task(p, env))
+			goto next;
+
+		move_task(p, env);
 		pulled++;
-		rem_load_move -= p->se.load.weight;
+		env->load_move -= load;
 
 #ifdef CONFIG_PREEMPT
 		/*
@@ -3261,28 +3271,30 @@
 		 * kernels will stop after the first task is pulled to minimize
 		 * the critical section.
 		 */
-		if (idle == CPU_NEWLY_IDLE) {
-			*lb_flags |= LBF_ABORT;
+		if (env->idle == CPU_NEWLY_IDLE)
 			break;
-		}
 #endif
 
 		/*
 		 * We only want to steal up to the prescribed amount of
 		 * weighted load.
 		 */
-		if (rem_load_move <= 0)
+		if (env->load_move <= 0)
 			break;
-	}
-out:
-	/*
-	 * Right now, this is one of only two places pull_task() is called,
-	 * so we can safely collect pull_task() stats here rather than
-	 * inside pull_task().
-	 */
-	schedstat_add(sd, lb_gained[idle], pulled);
 
-	return max_load_move - rem_load_move;
+		continue;
+next:
+		list_move_tail(&p->se.group_node, tasks);
+	}
+
+	/*
+	 * Right now, this is one of only two places move_task() is called,
+	 * so we can safely collect move_task() stats here rather than
+	 * inside move_task().
+	 */
+	schedstat_add(env->sd, lb_gained[env->idle], pulled);
+
+	return pulled;
 }
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
@@ -3362,114 +3374,36 @@
 
 static void update_h_load(long cpu)
 {
+	rcu_read_lock();
 	walk_tg_tree(tg_load_down, tg_nop, (void *)cpu);
+	rcu_read_unlock();
 }
 
-static unsigned long
-load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
-		  unsigned long max_load_move,
-		  struct sched_domain *sd, enum cpu_idle_type idle,
-		  int *lb_flags)
+static unsigned long task_h_load(struct task_struct *p)
 {
-	long rem_load_move = max_load_move;
-	struct cfs_rq *busiest_cfs_rq;
+	struct cfs_rq *cfs_rq = task_cfs_rq(p);
+	unsigned long load;
 
-	rcu_read_lock();
-	update_h_load(cpu_of(busiest));
+	load = p->se.load.weight;
+	load = div_u64(load * cfs_rq->h_load, cfs_rq->load.weight + 1);
 
-	for_each_leaf_cfs_rq(busiest, busiest_cfs_rq) {
-		unsigned long busiest_h_load = busiest_cfs_rq->h_load;
-		unsigned long busiest_weight = busiest_cfs_rq->load.weight;
-		u64 rem_load, moved_load;
-
-		if (*lb_flags & (LBF_NEED_BREAK|LBF_ABORT))
-			break;
-
-		/*
-		 * empty group or part of a throttled hierarchy
-		 */
-		if (!busiest_cfs_rq->task_weight ||
-		    throttled_lb_pair(busiest_cfs_rq->tg, cpu_of(busiest), this_cpu))
-			continue;
-
-		rem_load = (u64)rem_load_move * busiest_weight;
-		rem_load = div_u64(rem_load, busiest_h_load + 1);
-
-		moved_load = balance_tasks(this_rq, this_cpu, busiest,
-				rem_load, sd, idle, lb_flags,
-				busiest_cfs_rq);
-
-		if (!moved_load)
-			continue;
-
-		moved_load *= busiest_h_load;
-		moved_load = div_u64(moved_load, busiest_weight + 1);
-
-		rem_load_move -= moved_load;
-		if (rem_load_move < 0)
-			break;
-	}
-	rcu_read_unlock();
-
-	return max_load_move - rem_load_move;
+	return load;
 }
 #else
 static inline void update_shares(int cpu)
 {
 }
 
-static unsigned long
-load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
-		  unsigned long max_load_move,
-		  struct sched_domain *sd, enum cpu_idle_type idle,
-		  int *lb_flags)
+static inline void update_h_load(long cpu)
 {
-	return balance_tasks(this_rq, this_cpu, busiest,
-			max_load_move, sd, idle, lb_flags,
-			&busiest->cfs);
+}
+
+static unsigned long task_h_load(struct task_struct *p)
+{
+	return p->se.load.weight;
 }
 #endif
 
-/*
- * move_tasks tries to move up to max_load_move weighted load from busiest to
- * this_rq, as part of a balancing operation within domain "sd".
- * Returns 1 if successful and 0 otherwise.
- *
- * Called with both runqueues locked.
- */
-static int move_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
-		      unsigned long max_load_move,
-		      struct sched_domain *sd, enum cpu_idle_type idle,
-		      int *lb_flags)
-{
-	unsigned long total_load_moved = 0, load_moved;
-
-	do {
-		load_moved = load_balance_fair(this_rq, this_cpu, busiest,
-				max_load_move - total_load_moved,
-				sd, idle, lb_flags);
-
-		total_load_moved += load_moved;
-
-		if (*lb_flags & (LBF_NEED_BREAK|LBF_ABORT))
-			break;
-
-#ifdef CONFIG_PREEMPT
-		/*
-		 * NEWIDLE balancing is a source of latency, so preemptible
-		 * kernels will stop after the first task is pulled to minimize
-		 * the critical section.
-		 */
-		if (idle == CPU_NEWLY_IDLE && this_rq->nr_running) {
-			*lb_flags |= LBF_ABORT;
-			break;
-		}
-#endif
-	} while (load_moved && max_load_move > total_load_moved);
-
-	return total_load_moved > 0;
-}
-
 /********** Helpers for find_busiest_group ************************/
 /*
  * sd_lb_stats - Structure to store the statistics of a sched_domain
@@ -3778,6 +3712,11 @@
 	struct sched_domain *child = sd->child;
 	struct sched_group *group, *sdg = sd->groups;
 	unsigned long power;
+	unsigned long interval;
+
+	interval = msecs_to_jiffies(sd->balance_interval);
+	interval = clamp(interval, 1UL, max_load_balance_interval);
+	sdg->sgp->next_update = jiffies + interval;
 
 	if (!child) {
 		update_cpu_power(sd, cpu);
@@ -3885,12 +3824,15 @@
 	 * domains. In the newly idle case, we will allow all the cpu's
 	 * to do the newly idle load balance.
 	 */
-	if (idle != CPU_NEWLY_IDLE && local_group) {
-		if (balance_cpu != this_cpu) {
-			*balance = 0;
-			return;
-		}
-		update_group_power(sd, this_cpu);
+	if (local_group) {
+		if (idle != CPU_NEWLY_IDLE) {
+			if (balance_cpu != this_cpu) {
+				*balance = 0;
+				return;
+			}
+			update_group_power(sd, this_cpu);
+		} else if (time_after_eq(jiffies, group->sgp->next_update))
+			update_group_power(sd, this_cpu);
 	}
 
 	/* Adjust by relative CPU power of the group */
@@ -4453,13 +4395,21 @@
 			struct sched_domain *sd, enum cpu_idle_type idle,
 			int *balance)
 {
-	int ld_moved, lb_flags = 0, active_balance = 0;
+	int ld_moved, active_balance = 0;
 	struct sched_group *group;
 	unsigned long imbalance;
 	struct rq *busiest;
 	unsigned long flags;
 	struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask);
 
+	struct lb_env env = {
+		.sd		= sd,
+		.dst_cpu	= this_cpu,
+		.dst_rq		= this_rq,
+		.idle		= idle,
+		.loop_break	= sysctl_sched_nr_migrate,
+	};
+
 	cpumask_copy(cpus, cpu_active_mask);
 
 	schedstat_inc(sd, lb_count[idle]);
@@ -4494,32 +4444,34 @@
 		 * still unbalanced. ld_moved simply stays zero, so it is
 		 * correctly treated as an imbalance.
 		 */
-		lb_flags |= LBF_ALL_PINNED;
+		env.flags |= LBF_ALL_PINNED;
+		env.load_move = imbalance;
+		env.src_cpu = busiest->cpu;
+		env.src_rq = busiest;
+		env.loop_max = busiest->nr_running;
+
+more_balance:
 		local_irq_save(flags);
 		double_rq_lock(this_rq, busiest);
-		ld_moved = move_tasks(this_rq, this_cpu, busiest,
-				      imbalance, sd, idle, &lb_flags);
+		if (!env.loop)
+			update_h_load(env.src_cpu);
+		ld_moved += move_tasks(&env);
 		double_rq_unlock(this_rq, busiest);
 		local_irq_restore(flags);
 
+		if (env.flags & LBF_NEED_BREAK) {
+			env.flags &= ~LBF_NEED_BREAK;
+			goto more_balance;
+		}
+
 		/*
 		 * some other cpu did the load balance for us.
 		 */
 		if (ld_moved && this_cpu != smp_processor_id())
 			resched_cpu(this_cpu);
 
-		if (lb_flags & LBF_ABORT)
-			goto out_balanced;
-
-		if (lb_flags & LBF_NEED_BREAK) {
-			lb_flags += LBF_HAD_BREAK - LBF_NEED_BREAK;
-			if (lb_flags & LBF_ABORT)
-				goto out_balanced;
-			goto redo;
-		}
-
 		/* All tasks on this runqueue were pinned by CPU affinity */
-		if (unlikely(lb_flags & LBF_ALL_PINNED)) {
+		if (unlikely(env.flags & LBF_ALL_PINNED)) {
 			cpumask_clear_cpu(cpu_of(busiest), cpus);
 			if (!cpumask_empty(cpus))
 				goto redo;
@@ -4549,7 +4501,7 @@
 					tsk_cpus_allowed(busiest->curr))) {
 				raw_spin_unlock_irqrestore(&busiest->lock,
 							    flags);
-				lb_flags |= LBF_ALL_PINNED;
+				env.flags |= LBF_ALL_PINNED;
 				goto out_one_pinned;
 			}
 
@@ -4602,7 +4554,7 @@
 
 out_one_pinned:
 	/* tune up the balancing interval */
-	if (((lb_flags & LBF_ALL_PINNED) &&
+	if (((env.flags & LBF_ALL_PINNED) &&
 			sd->balance_interval < MAX_PINNED_INTERVAL) ||
 			(sd->balance_interval < sd->max_interval))
 		sd->balance_interval *= 2;
@@ -4712,10 +4664,18 @@
 	}
 
 	if (likely(sd)) {
+		struct lb_env env = {
+			.sd		= sd,
+			.dst_cpu	= target_cpu,
+			.dst_rq		= target_rq,
+			.src_cpu	= busiest_rq->cpu,
+			.src_rq		= busiest_rq,
+			.idle		= CPU_IDLE,
+		};
+
 		schedstat_inc(sd, alb_count);
 
-		if (move_one_task(target_rq, target_cpu, busiest_rq,
-				  sd, CPU_IDLE))
+		if (move_one_task(&env))
 			schedstat_inc(sd, alb_pushed);
 		else
 			schedstat_inc(sd, alb_failed);
@@ -4947,8 +4907,6 @@
 
 static DEFINE_SPINLOCK(balancing);
 
-static unsigned long __read_mostly max_load_balance_interval = HZ/10;
-
 /*
  * Scale the max load_balance interval with the number of CPUs in the system.
  * This trades load-balance latency on larger machines for less cross talk.
@@ -5342,7 +5300,6 @@
 void init_cfs_rq(struct cfs_rq *cfs_rq)
 {
 	cfs_rq->tasks_timeline = RB_ROOT;
-	INIT_LIST_HEAD(&cfs_rq->tasks);
 	cfs_rq->min_vruntime = (u64)(-(1LL << 20));
 #ifndef CONFIG_64BIT
 	cfs_rq->min_vruntime_copy = cfs_rq->min_vruntime;
@@ -5614,6 +5571,7 @@
 	open_softirq(SCHED_SOFTIRQ, run_rebalance_domains);
 
 #ifdef CONFIG_NO_HZ
+	nohz.next_balance = jiffies;
 	zalloc_cpumask_var(&nohz.idle_cpus_mask, GFP_NOWAIT);
 	cpu_notifier(sched_ilb_notifier, 0);
 #endif
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index f42ae7f..b60dad7 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -778,12 +778,9 @@
 
 static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun)
 {
-	int i, idle = 1;
+	int i, idle = 1, throttled = 0;
 	const struct cpumask *span;
 
-	if (!rt_bandwidth_enabled() || rt_b->rt_runtime == RUNTIME_INF)
-		return 1;
-
 	span = sched_rt_period_mask();
 	for_each_cpu(i, span) {
 		int enqueue = 0;
@@ -818,12 +815,17 @@
 			if (!rt_rq_throttled(rt_rq))
 				enqueue = 1;
 		}
+		if (rt_rq->rt_throttled)
+			throttled = 1;
 
 		if (enqueue)
 			sched_rt_rq_enqueue(rt_rq);
 		raw_spin_unlock(&rq->lock);
 	}
 
+	if (!throttled && (!rt_bandwidth_enabled() || rt_b->rt_runtime == RUNTIME_INF))
+		return 1;
+
 	return idle;
 }
 
@@ -855,8 +857,30 @@
 		return 0;
 
 	if (rt_rq->rt_time > runtime) {
-		rt_rq->rt_throttled = 1;
-		printk_once(KERN_WARNING "sched: RT throttling activated\n");
+		struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq);
+
+		/*
+		 * Don't actually throttle groups that have no runtime assigned
+		 * but accrue some time due to boosting.
+		 */
+		if (likely(rt_b->rt_runtime)) {
+			static bool once = false;
+
+			rt_rq->rt_throttled = 1;
+
+			if (!once) {
+				once = true;
+				printk_sched("sched: RT throttling activated\n");
+			}
+		} else {
+			/*
+			 * In case we did anyway, make it go away,
+			 * replenishment is a joke, since it will replenish us
+			 * with exactly 0 ns.
+			 */
+			rt_rq->rt_time = 0;
+		}
+
 		if (rt_rq_throttled(rt_rq)) {
 			sched_rt_rq_dequeue(rt_rq);
 			return 1;
@@ -884,7 +908,8 @@
 	if (unlikely((s64)delta_exec < 0))
 		delta_exec = 0;
 
-	schedstat_set(curr->se.statistics.exec_max, max(curr->se.statistics.exec_max, delta_exec));
+	schedstat_set(curr->se.statistics.exec_max,
+		      max(curr->se.statistics.exec_max, delta_exec));
 
 	curr->se.sum_exec_runtime += delta_exec;
 	account_group_exec_runtime(curr, delta_exec);
@@ -1972,7 +1997,7 @@
 	if (--p->rt.time_slice)
 		return;
 
-	p->rt.time_slice = DEF_TIMESLICE;
+	p->rt.time_slice = RR_TIMESLICE;
 
 	/*
 	 * Requeue to the end of queue if we are not the only element
@@ -2000,7 +2025,7 @@
 	 * Time slice is 0 for SCHED_FIFO tasks
 	 */
 	if (task->policy == SCHED_RR)
-		return DEF_TIMESLICE;
+		return RR_TIMESLICE;
 	else
 		return 0;
 }
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 98c0c26..42b1f30 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -36,11 +36,7 @@
 
 /*
  * These are the 'tuning knobs' of the scheduler:
- *
- * default timeslice is 100 msecs (used only for SCHED_RR tasks).
- * Timeslices get refilled after they expire.
  */
-#define DEF_TIMESLICE		(100 * HZ / 1000)
 
 /*
  * single value that denotes runtime == period, ie unlimited time.
@@ -216,9 +212,6 @@
 	struct rb_root tasks_timeline;
 	struct rb_node *rb_leftmost;
 
-	struct list_head tasks;
-	struct list_head *balance_iterator;
-
 	/*
 	 * 'curr' points to currently running entity on this cfs_rq.
 	 * It is set to NULL otherwise (i.e when none are currently running).
@@ -246,11 +239,6 @@
 
 #ifdef CONFIG_SMP
 	/*
-	 * the part of load.weight contributed by tasks
-	 */
-	unsigned long task_weight;
-
-	/*
 	 *   h_load = weight * f(tg)
 	 *
 	 * Where f(tg) is the recursive weight fraction assigned to
@@ -424,6 +412,8 @@
 	int cpu;
 	int online;
 
+	struct list_head cfs_tasks;
+
 	u64 rt_avg;
 	u64 age_stamp;
 	u64 idle_stamp;
@@ -462,7 +452,6 @@
 	unsigned int yld_count;
 
 	/* schedule() stats */
-	unsigned int sched_switch;
 	unsigned int sched_count;
 	unsigned int sched_goidle;
 
@@ -611,7 +600,7 @@
  * Tunables that become constants when CONFIG_SCHED_DEBUG is off:
  */
 #ifdef CONFIG_SCHED_DEBUG
-# include <linux/jump_label.h>
+# include <linux/static_key.h>
 # define const_debug __read_mostly
 #else
 # define const_debug const
@@ -630,18 +619,18 @@
 #undef SCHED_FEAT
 
 #if defined(CONFIG_SCHED_DEBUG) && defined(HAVE_JUMP_LABEL)
-static __always_inline bool static_branch__true(struct jump_label_key *key)
+static __always_inline bool static_branch__true(struct static_key *key)
 {
-	return likely(static_branch(key)); /* Not out of line branch. */
+	return static_key_true(key); /* Not out of line branch. */
 }
 
-static __always_inline bool static_branch__false(struct jump_label_key *key)
+static __always_inline bool static_branch__false(struct static_key *key)
 {
-	return unlikely(static_branch(key)); /* Out of line branch. */
+	return static_key_false(key); /* Out of line branch. */
 }
 
 #define SCHED_FEAT(name, enabled)					\
-static __always_inline bool static_branch_##name(struct jump_label_key *key) \
+static __always_inline bool static_branch_##name(struct static_key *key) \
 {									\
 	return static_branch__##enabled(key);				\
 }
@@ -650,7 +639,7 @@
 
 #undef SCHED_FEAT
 
-extern struct jump_label_key sched_feat_keys[__SCHED_FEAT_NR];
+extern struct static_key sched_feat_keys[__SCHED_FEAT_NR];
 #define sched_feat(x) (static_branch_##x(&sched_feat_keys[__SCHED_FEAT_##x]))
 #else /* !(SCHED_DEBUG && HAVE_JUMP_LABEL) */
 #define sched_feat(x) (sysctl_sched_features & (1UL << __SCHED_FEAT_##x))
diff --git a/kernel/sched/stats.c b/kernel/sched/stats.c
index 2a581ba..903ffa9e 100644
--- a/kernel/sched/stats.c
+++ b/kernel/sched/stats.c
@@ -32,9 +32,9 @@
 
 		/* runqueue-specific stats */
 		seq_printf(seq,
-		    "cpu%d %u %u %u %u %u %u %llu %llu %lu",
+		    "cpu%d %u 0 %u %u %u %u %llu %llu %lu",
 		    cpu, rq->yld_count,
-		    rq->sched_switch, rq->sched_count, rq->sched_goidle,
+		    rq->sched_count, rq->sched_goidle,
 		    rq->ttwu_count, rq->ttwu_local,
 		    rq->rq_cpu_time,
 		    rq->rq_sched_info.run_delay, rq->rq_sched_info.pcount);
diff --git a/kernel/signal.c b/kernel/signal.c
index c73c428..e76001c 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1054,13 +1054,13 @@
 	struct sigpending *pending;
 	struct sigqueue *q;
 	int override_rlimit;
-
-	trace_signal_generate(sig, info, t);
+	int ret = 0, result;
 
 	assert_spin_locked(&t->sighand->siglock);
 
+	result = TRACE_SIGNAL_IGNORED;
 	if (!prepare_signal(sig, t, from_ancestor_ns))
-		return 0;
+		goto ret;
 
 	pending = group ? &t->signal->shared_pending : &t->pending;
 	/*
@@ -1068,8 +1068,11 @@
 	 * exactly one non-rt signal, so that we can get more
 	 * detailed information about the cause of the signal.
 	 */
+	result = TRACE_SIGNAL_ALREADY_PENDING;
 	if (legacy_queue(pending, sig))
-		return 0;
+		goto ret;
+
+	result = TRACE_SIGNAL_DELIVERED;
 	/*
 	 * fast-pathed signals for kernel-internal things like SIGSTOP
 	 * or SIGKILL.
@@ -1127,14 +1130,15 @@
 			 * signal was rt and sent by user using something
 			 * other than kill().
 			 */
-			trace_signal_overflow_fail(sig, group, info);
-			return -EAGAIN;
+			result = TRACE_SIGNAL_OVERFLOW_FAIL;
+			ret = -EAGAIN;
+			goto ret;
 		} else {
 			/*
 			 * This is a silent loss of information.  We still
 			 * send the signal, but the *info bits are lost.
 			 */
-			trace_signal_lose_info(sig, group, info);
+			result = TRACE_SIGNAL_LOSE_INFO;
 		}
 	}
 
@@ -1142,7 +1146,9 @@
 	signalfd_notify(t, sig);
 	sigaddset(&pending->signal, sig);
 	complete_signal(sig, t, group);
-	return 0;
+ret:
+	trace_signal_generate(sig, info, t, group, result);
+	return ret;
 }
 
 static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
@@ -1585,7 +1591,7 @@
 	int sig = q->info.si_signo;
 	struct sigpending *pending;
 	unsigned long flags;
-	int ret;
+	int ret, result;
 
 	BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
 
@@ -1594,6 +1600,7 @@
 		goto ret;
 
 	ret = 1; /* the signal is ignored */
+	result = TRACE_SIGNAL_IGNORED;
 	if (!prepare_signal(sig, t, 0))
 		goto out;
 
@@ -1605,6 +1612,7 @@
 		 */
 		BUG_ON(q->info.si_code != SI_TIMER);
 		q->info.si_overrun++;
+		result = TRACE_SIGNAL_ALREADY_PENDING;
 		goto out;
 	}
 	q->info.si_overrun = 0;
@@ -1614,7 +1622,9 @@
 	list_add_tail(&q->list, &pending->list);
 	sigaddset(&pending->signal, sig);
 	complete_signal(sig, t, group);
+	result = TRACE_SIGNAL_DELIVERED;
 out:
+	trace_signal_generate(sig, &q->info, t, group, result);
 	unlock_task_sighand(t, &flags);
 ret:
 	return ret;
@@ -1642,6 +1652,15 @@
 	BUG_ON(!tsk->ptrace &&
 	       (tsk->group_leader != tsk || !thread_group_empty(tsk)));
 
+	if (sig != SIGCHLD) {
+		/*
+		 * This is only possible if parent == real_parent.
+		 * Check if it has changed security domain.
+		 */
+		if (tsk->parent_exec_id != tsk->parent->self_exec_id)
+			sig = SIGCHLD;
+	}
+
 	info.si_signo = sig;
 	info.si_errno = 0;
 	/*
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 4eb3a0f..671f959 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -297,7 +297,7 @@
 	int cpu = smp_processor_id();
 
 	rcu_irq_enter();
-	if (idle_cpu(cpu) && !in_interrupt()) {
+	if (is_idle_task(current) && !in_interrupt()) {
 		/*
 		 * Prevent raise_softirq from needlessly waking up ksoftirqd
 		 * here, as softirq will be serviced on return from interrupt.
@@ -310,31 +310,21 @@
 	__irq_enter();
 }
 
+static inline void invoke_softirq(void)
+{
+	if (!force_irqthreads) {
 #ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED
-static inline void invoke_softirq(void)
-{
-	if (!force_irqthreads)
 		__do_softirq();
-	else {
-		__local_bh_disable((unsigned long)__builtin_return_address(0),
-				SOFTIRQ_OFFSET);
-		wakeup_softirqd();
-		__local_bh_enable(SOFTIRQ_OFFSET);
-	}
-}
 #else
-static inline void invoke_softirq(void)
-{
-	if (!force_irqthreads)
 		do_softirq();
-	else {
+#endif
+	} else {
 		__local_bh_disable((unsigned long)__builtin_return_address(0),
 				SOFTIRQ_OFFSET);
 		wakeup_softirqd();
 		__local_bh_enable(SOFTIRQ_OFFSET);
 	}
 }
-#endif
 
 /*
  * Exit an interrupt context. Process softirqs if needed and possible:
@@ -353,7 +343,7 @@
 		tick_nohz_irq_exit();
 #endif
 	rcu_irq_exit();
-	preempt_enable_no_resched();
+	sched_preempt_enable_no_resched();
 }
 
 /*
@@ -385,6 +375,12 @@
 	local_irq_restore(flags);
 }
 
+void __raise_softirq_irqoff(unsigned int nr)
+{
+	trace_softirq_raise(nr);
+	or_softirq_pending(1UL << nr);
+}
+
 void open_softirq(int nr, void (*action)(struct softirq_action *))
 {
 	softirq_vec[nr].action = action;
@@ -744,9 +740,7 @@
 	while (!kthread_should_stop()) {
 		preempt_disable();
 		if (!local_softirq_pending()) {
-			preempt_enable_no_resched();
-			schedule();
-			preempt_disable();
+			schedule_preempt_disabled();
 		}
 
 		__set_current_state(TASK_RUNNING);
@@ -761,7 +755,7 @@
 			if (local_softirq_pending())
 				__do_softirq();
 			local_irq_enable();
-			preempt_enable_no_resched();
+			sched_preempt_enable_no_resched();
 			cond_resched();
 			preempt_disable();
 			rcu_note_context_switch((long)__bind_cpu);
diff --git a/kernel/srcu.c b/kernel/srcu.c
index 0febf61..ba35f3a 100644
--- a/kernel/srcu.c
+++ b/kernel/srcu.c
@@ -172,6 +172,12 @@
 {
 	int idx;
 
+	rcu_lockdep_assert(!lock_is_held(&sp->dep_map) &&
+			   !lock_is_held(&rcu_bh_lock_map) &&
+			   !lock_is_held(&rcu_lock_map) &&
+			   !lock_is_held(&rcu_sched_lock_map),
+			   "Illegal synchronize_srcu() in same-type SRCU (or RCU) read-side critical section");
+
 	idx = sp->completed;
 	mutex_lock(&sp->mutex);
 
@@ -280,19 +286,26 @@
 EXPORT_SYMBOL_GPL(synchronize_srcu);
 
 /**
- * synchronize_srcu_expedited - like synchronize_srcu, but less patient
+ * synchronize_srcu_expedited - Brute-force SRCU grace period
  * @sp: srcu_struct with which to synchronize.
  *
- * Flip the completed counter, and wait for the old count to drain to zero.
- * As with classic RCU, the updater must use some separate means of
- * synchronizing concurrent updates.  Can block; must be called from
- * process context.
+ * Wait for an SRCU grace period to elapse, but use a "big hammer"
+ * approach to force the grace period to end quickly.  This consumes
+ * significant time on all CPUs and is unfriendly to real-time workloads,
+ * so is thus not recommended for any sort of common-case code.  In fact,
+ * if you are using synchronize_srcu_expedited() in a loop, please
+ * restructure your code to batch your updates, and then use a single
+ * synchronize_srcu() instead.
  *
- * Note that it is illegal to call synchronize_srcu_expedited()
- * from the corresponding SRCU read-side critical section; doing so
- * will result in deadlock.  However, it is perfectly legal to call
- * synchronize_srcu_expedited() on one srcu_struct from some other
- * srcu_struct's read-side critical section.
+ * Note that it is illegal to call this function while holding any lock
+ * that is acquired by a CPU-hotplug notifier.  And yes, it is also illegal
+ * to call this function from a CPU-hotplug notifier.  Failing to observe
+ * these restriction will result in deadlock.  It is also illegal to call
+ * synchronize_srcu_expedited() from the corresponding SRCU read-side
+ * critical section; doing so will result in deadlock.  However, it is
+ * perfectly legal to call synchronize_srcu_expedited() on one srcu_struct
+ * from some other srcu_struct's read-side critical section, as long as
+ * the resulting graph of srcu_structs is acyclic.
  */
 void synchronize_srcu_expedited(struct srcu_struct *sp)
 {
diff --git a/kernel/sys.c b/kernel/sys.c
index 4070153..888d227 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1706,7 +1706,7 @@
 	if (arg4 | arg5)
 		return -EINVAL;
 
-	if (!capable(CAP_SYS_ADMIN))
+	if (!capable(CAP_SYS_RESOURCE))
 		return -EPERM;
 
 	if (addr >= TASK_SIZE)
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index f6117a4..6e039b1 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -22,13 +22,16 @@
  * NTP timekeeping variables:
  */
 
+DEFINE_SPINLOCK(ntp_lock);
+
+
 /* USER_HZ period (usecs): */
 unsigned long			tick_usec = TICK_USEC;
 
 /* ACTHZ period (nsecs): */
 unsigned long			tick_nsec;
 
-u64				tick_length;
+static u64			tick_length;
 static u64			tick_length_base;
 
 static struct hrtimer		leap_timer;
@@ -49,7 +52,7 @@
 static int			time_state = TIME_OK;
 
 /* clock status bits:							*/
-int				time_status = STA_UNSYNC;
+static int			time_status = STA_UNSYNC;
 
 /* TAI offset (secs):							*/
 static long			time_tai;
@@ -133,7 +136,7 @@
 /**
  * pps_clear - Clears the PPS state variables
  *
- * Must be called while holding a write on the xtime_lock
+ * Must be called while holding a write on the ntp_lock
  */
 static inline void pps_clear(void)
 {
@@ -149,7 +152,7 @@
  * the last PPS signal. When it reaches 0, indicate that PPS signal is
  * missing.
  *
- * Must be called while holding a write on the xtime_lock
+ * Must be called while holding a write on the ntp_lock
  */
 static inline void pps_dec_valid(void)
 {
@@ -233,6 +236,17 @@
 
 #endif /* CONFIG_NTP_PPS */
 
+
+/**
+ * ntp_synced - Returns 1 if the NTP status is not UNSYNC
+ *
+ */
+static inline int ntp_synced(void)
+{
+	return !(time_status & STA_UNSYNC);
+}
+
+
 /*
  * NTP methods:
  */
@@ -275,7 +289,7 @@
 
 	time_status |= STA_MODE;
 
-	return div_s64(offset64 << (NTP_SCALE_SHIFT - SHIFT_FLL), secs);
+	return div64_long(offset64 << (NTP_SCALE_SHIFT - SHIFT_FLL), secs);
 }
 
 static void ntp_update_offset(long offset)
@@ -330,11 +344,13 @@
 
 /**
  * ntp_clear - Clears the NTP state variables
- *
- * Must be called while holding a write on the xtime_lock
  */
 void ntp_clear(void)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&ntp_lock, flags);
+
 	time_adjust	= 0;		/* stop active adjtime() */
 	time_status	|= STA_UNSYNC;
 	time_maxerror	= NTP_PHASE_LIMIT;
@@ -347,8 +363,23 @@
 
 	/* Clear PPS state variables */
 	pps_clear();
+	spin_unlock_irqrestore(&ntp_lock, flags);
+
 }
 
+
+u64 ntp_tick_length(void)
+{
+	unsigned long flags;
+	s64 ret;
+
+	spin_lock_irqsave(&ntp_lock, flags);
+	ret = tick_length;
+	spin_unlock_irqrestore(&ntp_lock, flags);
+	return ret;
+}
+
+
 /*
  * Leap second processing. If in leap-insert state at the end of the
  * day, the system clock is set back one second; if in leap-delete
@@ -357,14 +388,15 @@
 static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer)
 {
 	enum hrtimer_restart res = HRTIMER_NORESTART;
+	unsigned long flags;
+	int leap = 0;
 
-	write_seqlock(&xtime_lock);
-
+	spin_lock_irqsave(&ntp_lock, flags);
 	switch (time_state) {
 	case TIME_OK:
 		break;
 	case TIME_INS:
-		timekeeping_leap_insert(-1);
+		leap = -1;
 		time_state = TIME_OOP;
 		printk(KERN_NOTICE
 			"Clock: inserting leap second 23:59:60 UTC\n");
@@ -372,7 +404,7 @@
 		res = HRTIMER_RESTART;
 		break;
 	case TIME_DEL:
-		timekeeping_leap_insert(1);
+		leap = 1;
 		time_tai--;
 		time_state = TIME_WAIT;
 		printk(KERN_NOTICE
@@ -387,8 +419,14 @@
 			time_state = TIME_OK;
 		break;
 	}
+	spin_unlock_irqrestore(&ntp_lock, flags);
 
-	write_sequnlock(&xtime_lock);
+	/*
+	 * We have to call this outside of the ntp_lock to keep
+	 * the proper locking hierarchy
+	 */
+	if (leap)
+		timekeeping_leap_insert(leap);
 
 	return res;
 }
@@ -404,6 +442,9 @@
 void second_overflow(void)
 {
 	s64 delta;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ntp_lock, flags);
 
 	/* Bump the maxerror field */
 	time_maxerror += MAXFREQ / NSEC_PER_USEC;
@@ -423,23 +464,25 @@
 	pps_dec_valid();
 
 	if (!time_adjust)
-		return;
+		goto out;
 
 	if (time_adjust > MAX_TICKADJ) {
 		time_adjust -= MAX_TICKADJ;
 		tick_length += MAX_TICKADJ_SCALED;
-		return;
+		goto out;
 	}
 
 	if (time_adjust < -MAX_TICKADJ) {
 		time_adjust += MAX_TICKADJ;
 		tick_length -= MAX_TICKADJ_SCALED;
-		return;
+		goto out;
 	}
 
 	tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ)
 							 << NTP_SCALE_SHIFT;
 	time_adjust = 0;
+out:
+	spin_unlock_irqrestore(&ntp_lock, flags);
 }
 
 #ifdef CONFIG_GENERIC_CMOS_UPDATE
@@ -663,7 +706,7 @@
 
 	getnstimeofday(&ts);
 
-	write_seqlock_irq(&xtime_lock);
+	spin_lock_irq(&ntp_lock);
 
 	if (txc->modes & ADJ_ADJTIME) {
 		long save_adjust = time_adjust;
@@ -705,7 +748,7 @@
 	/* fill PPS status fields */
 	pps_fill_timex(txc);
 
-	write_sequnlock_irq(&xtime_lock);
+	spin_unlock_irq(&ntp_lock);
 
 	txc->time.tv_sec = ts.tv_sec;
 	txc->time.tv_usec = ts.tv_nsec;
@@ -903,7 +946,7 @@
 
 	pts_norm = pps_normalize_ts(*phase_ts);
 
-	write_seqlock_irqsave(&xtime_lock, flags);
+	spin_lock_irqsave(&ntp_lock, flags);
 
 	/* clear the error bits, they will be set again if needed */
 	time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR);
@@ -916,7 +959,7 @@
 	 * just start the frequency interval */
 	if (unlikely(pps_fbase.tv_sec == 0)) {
 		pps_fbase = *raw_ts;
-		write_sequnlock_irqrestore(&xtime_lock, flags);
+		spin_unlock_irqrestore(&ntp_lock, flags);
 		return;
 	}
 
@@ -931,7 +974,7 @@
 		time_status |= STA_PPSJITTER;
 		/* restart the frequency calibration interval */
 		pps_fbase = *raw_ts;
-		write_sequnlock_irqrestore(&xtime_lock, flags);
+		spin_unlock_irqrestore(&ntp_lock, flags);
 		pr_err("hardpps: PPSJITTER: bad pulse\n");
 		return;
 	}
@@ -948,7 +991,7 @@
 
 	hardpps_update_phase(pts_norm.nsec);
 
-	write_sequnlock_irqrestore(&xtime_lock, flags);
+	spin_unlock_irqrestore(&ntp_lock, flags);
 }
 EXPORT_SYMBOL(hardpps);
 
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index fd4a7b1..e883f57 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -575,11 +575,15 @@
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
+	if (cpumask_empty(tick_get_broadcast_mask()))
+		goto end;
 
 	tick_broadcast_device.mode = TICKDEV_MODE_ONESHOT;
 	bc = tick_broadcast_device.evtdev;
 	if (bc)
 		tick_broadcast_setup_oneshot(bc);
+
+end:
 	raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
 }
 
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 7656642..3526038 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -182,11 +182,7 @@
 
 static ktime_t tick_nohz_start_idle(int cpu, struct tick_sched *ts)
 {
-	ktime_t now;
-
-	now = ktime_get();
-
-	update_ts_time_stats(cpu, ts, now, NULL);
+	ktime_t now = ktime_get();
 
 	ts->idle_entrytime = now;
 	ts->idle_active = 1;
@@ -562,20 +558,21 @@
 
 	local_irq_disable();
 
-	if (ts->idle_active || (ts->inidle && ts->tick_stopped))
+	WARN_ON_ONCE(!ts->inidle);
+
+	ts->inidle = 0;
+
+	if (ts->idle_active || ts->tick_stopped)
 		now = ktime_get();
 
 	if (ts->idle_active)
 		tick_nohz_stop_idle(cpu, now);
 
-	if (!ts->inidle || !ts->tick_stopped) {
-		ts->inidle = 0;
+	if (!ts->tick_stopped) {
 		local_irq_enable();
 		return;
 	}
 
-	ts->inidle = 0;
-
 	/* Update jiffies first */
 	select_nohz_load_balancer(0);
 	tick_do_update_jiffies64(now);
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 0c63581..403c2a0 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -25,6 +25,8 @@
 struct timekeeper {
 	/* Current clocksource used for timekeeping. */
 	struct clocksource *clock;
+	/* NTP adjusted clock multiplier */
+	u32	mult;
 	/* The shift value of the current clocksource. */
 	int	shift;
 
@@ -45,12 +47,47 @@
 	/* Shift conversion between clock shifted nano seconds and
 	 * ntp shifted nano seconds. */
 	int	ntp_error_shift;
-	/* NTP adjusted clock multiplier */
-	u32	mult;
+
+	/* The current time */
+	struct timespec xtime;
+	/*
+	 * wall_to_monotonic is what we need to add to xtime (or xtime corrected
+	 * for sub jiffie times) to get to monotonic time.  Monotonic is pegged
+	 * at zero at system boot time, so wall_to_monotonic will be negative,
+	 * however, we will ALWAYS keep the tv_nsec part positive so we can use
+	 * the usual normalization.
+	 *
+	 * wall_to_monotonic is moved after resume from suspend for the
+	 * monotonic time not to jump. We need to add total_sleep_time to
+	 * wall_to_monotonic to get the real boot based time offset.
+	 *
+	 * - wall_to_monotonic is no longer the boot time, getboottime must be
+	 * used instead.
+	 */
+	struct timespec wall_to_monotonic;
+	/* time spent in suspend */
+	struct timespec total_sleep_time;
+	/* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */
+	struct timespec raw_time;
+
+	/* Seqlock for all timekeeper values */
+	seqlock_t lock;
 };
 
 static struct timekeeper timekeeper;
 
+/*
+ * This read-write spinlock protects us from races in SMP while
+ * playing with xtime.
+ */
+__cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock);
+
+
+/* flag for if timekeeping is suspended */
+int __read_mostly timekeeping_suspended;
+
+
+
 /**
  * timekeeper_setup_internals - Set up internals to use clocksource clock.
  *
@@ -135,47 +172,28 @@
 	return clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift);
 }
 
-/*
- * This read-write spinlock protects us from races in SMP while
- * playing with xtime.
- */
-__cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock);
+/* must hold write on timekeeper.lock */
+static void timekeeping_update(bool clearntp)
+{
+	if (clearntp) {
+		timekeeper.ntp_error = 0;
+		ntp_clear();
+	}
+	update_vsyscall(&timekeeper.xtime, &timekeeper.wall_to_monotonic,
+			 timekeeper.clock, timekeeper.mult);
+}
 
 
-/*
- * The current time
- * wall_to_monotonic is what we need to add to xtime (or xtime corrected
- * for sub jiffie times) to get to monotonic time.  Monotonic is pegged
- * at zero at system boot time, so wall_to_monotonic will be negative,
- * however, we will ALWAYS keep the tv_nsec part positive so we can use
- * the usual normalization.
- *
- * wall_to_monotonic is moved after resume from suspend for the monotonic
- * time not to jump. We need to add total_sleep_time to wall_to_monotonic
- * to get the real boot based time offset.
- *
- * - wall_to_monotonic is no longer the boot time, getboottime must be
- * used instead.
- */
-static struct timespec xtime __attribute__ ((aligned (16)));
-static struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
-static struct timespec total_sleep_time;
-
-/*
- * The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock.
- */
-static struct timespec raw_time;
-
-/* flag for if timekeeping is suspended */
-int __read_mostly timekeeping_suspended;
-
-/* must hold xtime_lock */
 void timekeeping_leap_insert(int leapsecond)
 {
-	xtime.tv_sec += leapsecond;
-	wall_to_monotonic.tv_sec -= leapsecond;
-	update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock,
-			timekeeper.mult);
+	unsigned long flags;
+
+	write_seqlock_irqsave(&timekeeper.lock, flags);
+	timekeeper.xtime.tv_sec += leapsecond;
+	timekeeper.wall_to_monotonic.tv_sec -= leapsecond;
+	timekeeping_update(false);
+	write_sequnlock_irqrestore(&timekeeper.lock, flags);
+
 }
 
 /**
@@ -202,10 +220,10 @@
 	/* If arch requires, add in gettimeoffset() */
 	nsec += arch_gettimeoffset();
 
-	timespec_add_ns(&xtime, nsec);
+	timespec_add_ns(&timekeeper.xtime, nsec);
 
 	nsec = clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift);
-	timespec_add_ns(&raw_time, nsec);
+	timespec_add_ns(&timekeeper.raw_time, nsec);
 }
 
 /**
@@ -222,15 +240,15 @@
 	WARN_ON(timekeeping_suspended);
 
 	do {
-		seq = read_seqbegin(&xtime_lock);
+		seq = read_seqbegin(&timekeeper.lock);
 
-		*ts = xtime;
+		*ts = timekeeper.xtime;
 		nsecs = timekeeping_get_ns();
 
 		/* If arch requires, add in gettimeoffset() */
 		nsecs += arch_gettimeoffset();
 
-	} while (read_seqretry(&xtime_lock, seq));
+	} while (read_seqretry(&timekeeper.lock, seq));
 
 	timespec_add_ns(ts, nsecs);
 }
@@ -245,14 +263,16 @@
 	WARN_ON(timekeeping_suspended);
 
 	do {
-		seq = read_seqbegin(&xtime_lock);
-		secs = xtime.tv_sec + wall_to_monotonic.tv_sec;
-		nsecs = xtime.tv_nsec + wall_to_monotonic.tv_nsec;
+		seq = read_seqbegin(&timekeeper.lock);
+		secs = timekeeper.xtime.tv_sec +
+				timekeeper.wall_to_monotonic.tv_sec;
+		nsecs = timekeeper.xtime.tv_nsec +
+				timekeeper.wall_to_monotonic.tv_nsec;
 		nsecs += timekeeping_get_ns();
 		/* If arch requires, add in gettimeoffset() */
 		nsecs += arch_gettimeoffset();
 
-	} while (read_seqretry(&xtime_lock, seq));
+	} while (read_seqretry(&timekeeper.lock, seq));
 	/*
 	 * Use ktime_set/ktime_add_ns to create a proper ktime on
 	 * 32-bit architectures without CONFIG_KTIME_SCALAR.
@@ -278,14 +298,14 @@
 	WARN_ON(timekeeping_suspended);
 
 	do {
-		seq = read_seqbegin(&xtime_lock);
-		*ts = xtime;
-		tomono = wall_to_monotonic;
+		seq = read_seqbegin(&timekeeper.lock);
+		*ts = timekeeper.xtime;
+		tomono = timekeeper.wall_to_monotonic;
 		nsecs = timekeeping_get_ns();
 		/* If arch requires, add in gettimeoffset() */
 		nsecs += arch_gettimeoffset();
 
-	} while (read_seqretry(&xtime_lock, seq));
+	} while (read_seqretry(&timekeeper.lock, seq));
 
 	set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec,
 				ts->tv_nsec + tomono.tv_nsec + nsecs);
@@ -313,10 +333,10 @@
 	do {
 		u32 arch_offset;
 
-		seq = read_seqbegin(&xtime_lock);
+		seq = read_seqbegin(&timekeeper.lock);
 
-		*ts_raw = raw_time;
-		*ts_real = xtime;
+		*ts_raw = timekeeper.raw_time;
+		*ts_real = timekeeper.xtime;
 
 		nsecs_raw = timekeeping_get_ns_raw();
 		nsecs_real = timekeeping_get_ns();
@@ -326,7 +346,7 @@
 		nsecs_raw += arch_offset;
 		nsecs_real += arch_offset;
 
-	} while (read_seqretry(&xtime_lock, seq));
+	} while (read_seqretry(&timekeeper.lock, seq));
 
 	timespec_add_ns(ts_raw, nsecs_raw);
 	timespec_add_ns(ts_real, nsecs_real);
@@ -365,23 +385,19 @@
 	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
 		return -EINVAL;
 
-	write_seqlock_irqsave(&xtime_lock, flags);
+	write_seqlock_irqsave(&timekeeper.lock, flags);
 
 	timekeeping_forward_now();
 
-	ts_delta.tv_sec = tv->tv_sec - xtime.tv_sec;
-	ts_delta.tv_nsec = tv->tv_nsec - xtime.tv_nsec;
-	wall_to_monotonic = timespec_sub(wall_to_monotonic, ts_delta);
+	ts_delta.tv_sec = tv->tv_sec - timekeeper.xtime.tv_sec;
+	ts_delta.tv_nsec = tv->tv_nsec - timekeeper.xtime.tv_nsec;
+	timekeeper.wall_to_monotonic =
+			timespec_sub(timekeeper.wall_to_monotonic, ts_delta);
 
-	xtime = *tv;
+	timekeeper.xtime = *tv;
+	timekeeping_update(true);
 
-	timekeeper.ntp_error = 0;
-	ntp_clear();
-
-	update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock,
-				timekeeper.mult);
-
-	write_sequnlock_irqrestore(&xtime_lock, flags);
+	write_sequnlock_irqrestore(&timekeeper.lock, flags);
 
 	/* signal hrtimers about time change */
 	clock_was_set();
@@ -405,20 +421,17 @@
 	if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
 		return -EINVAL;
 
-	write_seqlock_irqsave(&xtime_lock, flags);
+	write_seqlock_irqsave(&timekeeper.lock, flags);
 
 	timekeeping_forward_now();
 
-	xtime = timespec_add(xtime, *ts);
-	wall_to_monotonic = timespec_sub(wall_to_monotonic, *ts);
+	timekeeper.xtime = timespec_add(timekeeper.xtime, *ts);
+	timekeeper.wall_to_monotonic =
+				timespec_sub(timekeeper.wall_to_monotonic, *ts);
 
-	timekeeper.ntp_error = 0;
-	ntp_clear();
+	timekeeping_update(true);
 
-	update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock,
-				timekeeper.mult);
-
-	write_sequnlock_irqrestore(&xtime_lock, flags);
+	write_sequnlock_irqrestore(&timekeeper.lock, flags);
 
 	/* signal hrtimers about time change */
 	clock_was_set();
@@ -490,11 +503,11 @@
 	s64 nsecs;
 
 	do {
-		seq = read_seqbegin(&xtime_lock);
+		seq = read_seqbegin(&timekeeper.lock);
 		nsecs = timekeeping_get_ns_raw();
-		*ts = raw_time;
+		*ts = timekeeper.raw_time;
 
-	} while (read_seqretry(&xtime_lock, seq));
+	} while (read_seqretry(&timekeeper.lock, seq));
 
 	timespec_add_ns(ts, nsecs);
 }
@@ -510,24 +523,30 @@
 	int ret;
 
 	do {
-		seq = read_seqbegin(&xtime_lock);
+		seq = read_seqbegin(&timekeeper.lock);
 
 		ret = timekeeper.clock->flags & CLOCK_SOURCE_VALID_FOR_HRES;
 
-	} while (read_seqretry(&xtime_lock, seq));
+	} while (read_seqretry(&timekeeper.lock, seq));
 
 	return ret;
 }
 
 /**
  * timekeeping_max_deferment - Returns max time the clocksource can be deferred
- *
- * Caller must observe xtime_lock via read_seqbegin/read_seqretry to
- * ensure that the clocksource does not change!
  */
 u64 timekeeping_max_deferment(void)
 {
-	return timekeeper.clock->max_idle_ns;
+	unsigned long seq;
+	u64 ret;
+	do {
+		seq = read_seqbegin(&timekeeper.lock);
+
+		ret = timekeeper.clock->max_idle_ns;
+
+	} while (read_seqretry(&timekeeper.lock, seq));
+
+	return ret;
 }
 
 /**
@@ -572,28 +591,29 @@
 	read_persistent_clock(&now);
 	read_boot_clock(&boot);
 
-	write_seqlock_irqsave(&xtime_lock, flags);
+	seqlock_init(&timekeeper.lock);
 
 	ntp_init();
 
+	write_seqlock_irqsave(&timekeeper.lock, flags);
 	clock = clocksource_default_clock();
 	if (clock->enable)
 		clock->enable(clock);
 	timekeeper_setup_internals(clock);
 
-	xtime.tv_sec = now.tv_sec;
-	xtime.tv_nsec = now.tv_nsec;
-	raw_time.tv_sec = 0;
-	raw_time.tv_nsec = 0;
+	timekeeper.xtime.tv_sec = now.tv_sec;
+	timekeeper.xtime.tv_nsec = now.tv_nsec;
+	timekeeper.raw_time.tv_sec = 0;
+	timekeeper.raw_time.tv_nsec = 0;
 	if (boot.tv_sec == 0 && boot.tv_nsec == 0) {
-		boot.tv_sec = xtime.tv_sec;
-		boot.tv_nsec = xtime.tv_nsec;
+		boot.tv_sec = timekeeper.xtime.tv_sec;
+		boot.tv_nsec = timekeeper.xtime.tv_nsec;
 	}
-	set_normalized_timespec(&wall_to_monotonic,
+	set_normalized_timespec(&timekeeper.wall_to_monotonic,
 				-boot.tv_sec, -boot.tv_nsec);
-	total_sleep_time.tv_sec = 0;
-	total_sleep_time.tv_nsec = 0;
-	write_sequnlock_irqrestore(&xtime_lock, flags);
+	timekeeper.total_sleep_time.tv_sec = 0;
+	timekeeper.total_sleep_time.tv_nsec = 0;
+	write_sequnlock_irqrestore(&timekeeper.lock, flags);
 }
 
 /* time in seconds when suspend began */
@@ -614,9 +634,11 @@
 		return;
 	}
 
-	xtime = timespec_add(xtime, *delta);
-	wall_to_monotonic = timespec_sub(wall_to_monotonic, *delta);
-	total_sleep_time = timespec_add(total_sleep_time, *delta);
+	timekeeper.xtime = timespec_add(timekeeper.xtime, *delta);
+	timekeeper.wall_to_monotonic =
+			timespec_sub(timekeeper.wall_to_monotonic, *delta);
+	timekeeper.total_sleep_time = timespec_add(
+					timekeeper.total_sleep_time, *delta);
 }
 
 
@@ -640,17 +662,15 @@
 	if (!(ts.tv_sec == 0 && ts.tv_nsec == 0))
 		return;
 
-	write_seqlock_irqsave(&xtime_lock, flags);
+	write_seqlock_irqsave(&timekeeper.lock, flags);
+
 	timekeeping_forward_now();
 
 	__timekeeping_inject_sleeptime(delta);
 
-	timekeeper.ntp_error = 0;
-	ntp_clear();
-	update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock,
-				timekeeper.mult);
+	timekeeping_update(true);
 
-	write_sequnlock_irqrestore(&xtime_lock, flags);
+	write_sequnlock_irqrestore(&timekeeper.lock, flags);
 
 	/* signal hrtimers about time change */
 	clock_was_set();
@@ -673,7 +693,7 @@
 
 	clocksource_resume();
 
-	write_seqlock_irqsave(&xtime_lock, flags);
+	write_seqlock_irqsave(&timekeeper.lock, flags);
 
 	if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) {
 		ts = timespec_sub(ts, timekeeping_suspend_time);
@@ -683,7 +703,7 @@
 	timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock);
 	timekeeper.ntp_error = 0;
 	timekeeping_suspended = 0;
-	write_sequnlock_irqrestore(&xtime_lock, flags);
+	write_sequnlock_irqrestore(&timekeeper.lock, flags);
 
 	touch_softlockup_watchdog();
 
@@ -701,7 +721,7 @@
 
 	read_persistent_clock(&timekeeping_suspend_time);
 
-	write_seqlock_irqsave(&xtime_lock, flags);
+	write_seqlock_irqsave(&timekeeper.lock, flags);
 	timekeeping_forward_now();
 	timekeeping_suspended = 1;
 
@@ -711,7 +731,7 @@
 	 * try to compensate so the difference in system time
 	 * and persistent_clock time stays close to constant.
 	 */
-	delta = timespec_sub(xtime, timekeeping_suspend_time);
+	delta = timespec_sub(timekeeper.xtime, timekeeping_suspend_time);
 	delta_delta = timespec_sub(delta, old_delta);
 	if (abs(delta_delta.tv_sec)  >= 2) {
 		/*
@@ -724,7 +744,7 @@
 		timekeeping_suspend_time =
 			timespec_add(timekeeping_suspend_time, delta_delta);
 	}
-	write_sequnlock_irqrestore(&xtime_lock, flags);
+	write_sequnlock_irqrestore(&timekeeper.lock, flags);
 
 	clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
 	clocksource_suspend();
@@ -775,7 +795,7 @@
 	 * Now calculate the error in (1 << look_ahead) ticks, but first
 	 * remove the single look ahead already included in the error.
 	 */
-	tick_error = tick_length >> (timekeeper.ntp_error_shift + 1);
+	tick_error = ntp_tick_length() >> (timekeeper.ntp_error_shift + 1);
 	tick_error -= timekeeper.xtime_interval >> 1;
 	error = ((error - tick_error) >> look_ahead) + tick_error;
 
@@ -943,22 +963,22 @@
 	timekeeper.xtime_nsec += timekeeper.xtime_interval << shift;
 	while (timekeeper.xtime_nsec >= nsecps) {
 		timekeeper.xtime_nsec -= nsecps;
-		xtime.tv_sec++;
+		timekeeper.xtime.tv_sec++;
 		second_overflow();
 	}
 
 	/* Accumulate raw time */
 	raw_nsecs = timekeeper.raw_interval << shift;
-	raw_nsecs += raw_time.tv_nsec;
+	raw_nsecs += timekeeper.raw_time.tv_nsec;
 	if (raw_nsecs >= NSEC_PER_SEC) {
 		u64 raw_secs = raw_nsecs;
 		raw_nsecs = do_div(raw_secs, NSEC_PER_SEC);
-		raw_time.tv_sec += raw_secs;
+		timekeeper.raw_time.tv_sec += raw_secs;
 	}
-	raw_time.tv_nsec = raw_nsecs;
+	timekeeper.raw_time.tv_nsec = raw_nsecs;
 
 	/* Accumulate error between NTP and clock interval */
-	timekeeper.ntp_error += tick_length << shift;
+	timekeeper.ntp_error += ntp_tick_length() << shift;
 	timekeeper.ntp_error -=
 	    (timekeeper.xtime_interval + timekeeper.xtime_remainder) <<
 				(timekeeper.ntp_error_shift + shift);
@@ -970,17 +990,19 @@
 /**
  * update_wall_time - Uses the current clocksource to increment the wall time
  *
- * Called from the timer interrupt, must hold a write on xtime_lock.
  */
 static void update_wall_time(void)
 {
 	struct clocksource *clock;
 	cycle_t offset;
 	int shift = 0, maxshift;
+	unsigned long flags;
+
+	write_seqlock_irqsave(&timekeeper.lock, flags);
 
 	/* Make sure we're fully resumed: */
 	if (unlikely(timekeeping_suspended))
-		return;
+		goto out;
 
 	clock = timekeeper.clock;
 
@@ -989,7 +1011,8 @@
 #else
 	offset = (clock->read(clock) - clock->cycle_last) & clock->mask;
 #endif
-	timekeeper.xtime_nsec = (s64)xtime.tv_nsec << timekeeper.shift;
+	timekeeper.xtime_nsec = (s64)timekeeper.xtime.tv_nsec <<
+						timekeeper.shift;
 
 	/*
 	 * With NO_HZ we may have to accumulate many cycle_intervals
@@ -1002,7 +1025,7 @@
 	shift = ilog2(offset) - ilog2(timekeeper.cycle_interval);
 	shift = max(0, shift);
 	/* Bound shift to one less then what overflows tick_length */
-	maxshift = (8*sizeof(tick_length) - (ilog2(tick_length)+1)) - 1;
+	maxshift = (64 - (ilog2(ntp_tick_length())+1)) - 1;
 	shift = min(shift, maxshift);
 	while (offset >= timekeeper.cycle_interval) {
 		offset = logarithmic_accumulation(offset, shift);
@@ -1040,8 +1063,10 @@
 	 * Store full nanoseconds into xtime after rounding it up and
 	 * add the remainder to the error difference.
 	 */
-	xtime.tv_nsec =	((s64) timekeeper.xtime_nsec >> timekeeper.shift) + 1;
-	timekeeper.xtime_nsec -= (s64) xtime.tv_nsec << timekeeper.shift;
+	timekeeper.xtime.tv_nsec = ((s64)timekeeper.xtime_nsec >>
+						timekeeper.shift) + 1;
+	timekeeper.xtime_nsec -= (s64)timekeeper.xtime.tv_nsec <<
+						timekeeper.shift;
 	timekeeper.ntp_error +=	timekeeper.xtime_nsec <<
 				timekeeper.ntp_error_shift;
 
@@ -1049,15 +1074,17 @@
 	 * Finally, make sure that after the rounding
 	 * xtime.tv_nsec isn't larger then NSEC_PER_SEC
 	 */
-	if (unlikely(xtime.tv_nsec >= NSEC_PER_SEC)) {
-		xtime.tv_nsec -= NSEC_PER_SEC;
-		xtime.tv_sec++;
+	if (unlikely(timekeeper.xtime.tv_nsec >= NSEC_PER_SEC)) {
+		timekeeper.xtime.tv_nsec -= NSEC_PER_SEC;
+		timekeeper.xtime.tv_sec++;
 		second_overflow();
 	}
 
-	/* check to see if there is a new clocksource to use */
-	update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock,
-				timekeeper.mult);
+	timekeeping_update(false);
+
+out:
+	write_sequnlock_irqrestore(&timekeeper.lock, flags);
+
 }
 
 /**
@@ -1074,8 +1101,10 @@
 void getboottime(struct timespec *ts)
 {
 	struct timespec boottime = {
-		.tv_sec = wall_to_monotonic.tv_sec + total_sleep_time.tv_sec,
-		.tv_nsec = wall_to_monotonic.tv_nsec + total_sleep_time.tv_nsec
+		.tv_sec = timekeeper.wall_to_monotonic.tv_sec +
+				timekeeper.total_sleep_time.tv_sec,
+		.tv_nsec = timekeeper.wall_to_monotonic.tv_nsec +
+				timekeeper.total_sleep_time.tv_nsec
 	};
 
 	set_normalized_timespec(ts, -boottime.tv_sec, -boottime.tv_nsec);
@@ -1101,13 +1130,13 @@
 	WARN_ON(timekeeping_suspended);
 
 	do {
-		seq = read_seqbegin(&xtime_lock);
-		*ts = xtime;
-		tomono = wall_to_monotonic;
-		sleep = total_sleep_time;
+		seq = read_seqbegin(&timekeeper.lock);
+		*ts = timekeeper.xtime;
+		tomono = timekeeper.wall_to_monotonic;
+		sleep = timekeeper.total_sleep_time;
 		nsecs = timekeeping_get_ns();
 
-	} while (read_seqretry(&xtime_lock, seq));
+	} while (read_seqretry(&timekeeper.lock, seq));
 
 	set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec + sleep.tv_sec,
 			ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec + nsecs);
@@ -1137,19 +1166,19 @@
  */
 void monotonic_to_bootbased(struct timespec *ts)
 {
-	*ts = timespec_add(*ts, total_sleep_time);
+	*ts = timespec_add(*ts, timekeeper.total_sleep_time);
 }
 EXPORT_SYMBOL_GPL(monotonic_to_bootbased);
 
 unsigned long get_seconds(void)
 {
-	return xtime.tv_sec;
+	return timekeeper.xtime.tv_sec;
 }
 EXPORT_SYMBOL(get_seconds);
 
 struct timespec __current_kernel_time(void)
 {
-	return xtime;
+	return timekeeper.xtime;
 }
 
 struct timespec current_kernel_time(void)
@@ -1158,10 +1187,10 @@
 	unsigned long seq;
 
 	do {
-		seq = read_seqbegin(&xtime_lock);
+		seq = read_seqbegin(&timekeeper.lock);
 
-		now = xtime;
-	} while (read_seqretry(&xtime_lock, seq));
+		now = timekeeper.xtime;
+	} while (read_seqretry(&timekeeper.lock, seq));
 
 	return now;
 }
@@ -1173,11 +1202,11 @@
 	unsigned long seq;
 
 	do {
-		seq = read_seqbegin(&xtime_lock);
+		seq = read_seqbegin(&timekeeper.lock);
 
-		now = xtime;
-		mono = wall_to_monotonic;
-	} while (read_seqretry(&xtime_lock, seq));
+		now = timekeeper.xtime;
+		mono = timekeeper.wall_to_monotonic;
+	} while (read_seqretry(&timekeeper.lock, seq));
 
 	set_normalized_timespec(&now, now.tv_sec + mono.tv_sec,
 				now.tv_nsec + mono.tv_nsec);
@@ -1209,11 +1238,11 @@
 	unsigned long seq;
 
 	do {
-		seq = read_seqbegin(&xtime_lock);
-		*xtim = xtime;
-		*wtom = wall_to_monotonic;
-		*sleep = total_sleep_time;
-	} while (read_seqretry(&xtime_lock, seq));
+		seq = read_seqbegin(&timekeeper.lock);
+		*xtim = timekeeper.xtime;
+		*wtom = timekeeper.wall_to_monotonic;
+		*sleep = timekeeper.total_sleep_time;
+	} while (read_seqretry(&timekeeper.lock, seq));
 }
 
 /**
@@ -1225,9 +1254,10 @@
 	struct timespec wtom;
 
 	do {
-		seq = read_seqbegin(&xtime_lock);
-		wtom = wall_to_monotonic;
-	} while (read_seqretry(&xtime_lock, seq));
+		seq = read_seqbegin(&timekeeper.lock);
+		wtom = timekeeper.wall_to_monotonic;
+	} while (read_seqretry(&timekeeper.lock, seq));
+
 	return timespec_to_ktime(wtom);
 }
 
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 683d559..867bd1d 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -62,6 +62,8 @@
 #define FTRACE_HASH_DEFAULT_BITS 10
 #define FTRACE_HASH_MAX_BITS 12
 
+#define FL_GLOBAL_CONTROL_MASK (FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_CONTROL)
+
 /* ftrace_enabled is a method to turn ftrace on or off */
 int ftrace_enabled __read_mostly;
 static int last_ftrace_enabled;
@@ -89,12 +91,14 @@
 };
 
 static struct ftrace_ops *ftrace_global_list __read_mostly = &ftrace_list_end;
+static struct ftrace_ops *ftrace_control_list __read_mostly = &ftrace_list_end;
 static struct ftrace_ops *ftrace_ops_list __read_mostly = &ftrace_list_end;
 ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub;
 static ftrace_func_t __ftrace_trace_function_delay __read_mostly = ftrace_stub;
 ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub;
 ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub;
 static struct ftrace_ops global_ops;
+static struct ftrace_ops control_ops;
 
 static void
 ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip);
@@ -168,6 +172,32 @@
 }
 #endif
 
+static void control_ops_disable_all(struct ftrace_ops *ops)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu)
+		*per_cpu_ptr(ops->disabled, cpu) = 1;
+}
+
+static int control_ops_alloc(struct ftrace_ops *ops)
+{
+	int __percpu *disabled;
+
+	disabled = alloc_percpu(int);
+	if (!disabled)
+		return -ENOMEM;
+
+	ops->disabled = disabled;
+	control_ops_disable_all(ops);
+	return 0;
+}
+
+static void control_ops_free(struct ftrace_ops *ops)
+{
+	free_percpu(ops->disabled);
+}
+
 static void update_global_ops(void)
 {
 	ftrace_func_t func;
@@ -259,6 +289,26 @@
 	return 0;
 }
 
+static void add_ftrace_list_ops(struct ftrace_ops **list,
+				struct ftrace_ops *main_ops,
+				struct ftrace_ops *ops)
+{
+	int first = *list == &ftrace_list_end;
+	add_ftrace_ops(list, ops);
+	if (first)
+		add_ftrace_ops(&ftrace_ops_list, main_ops);
+}
+
+static int remove_ftrace_list_ops(struct ftrace_ops **list,
+				  struct ftrace_ops *main_ops,
+				  struct ftrace_ops *ops)
+{
+	int ret = remove_ftrace_ops(list, ops);
+	if (!ret && *list == &ftrace_list_end)
+		ret = remove_ftrace_ops(&ftrace_ops_list, main_ops);
+	return ret;
+}
+
 static int __register_ftrace_function(struct ftrace_ops *ops)
 {
 	if (ftrace_disabled)
@@ -270,15 +320,20 @@
 	if (WARN_ON(ops->flags & FTRACE_OPS_FL_ENABLED))
 		return -EBUSY;
 
+	/* We don't support both control and global flags set. */
+	if ((ops->flags & FL_GLOBAL_CONTROL_MASK) == FL_GLOBAL_CONTROL_MASK)
+		return -EINVAL;
+
 	if (!core_kernel_data((unsigned long)ops))
 		ops->flags |= FTRACE_OPS_FL_DYNAMIC;
 
 	if (ops->flags & FTRACE_OPS_FL_GLOBAL) {
-		int first = ftrace_global_list == &ftrace_list_end;
-		add_ftrace_ops(&ftrace_global_list, ops);
+		add_ftrace_list_ops(&ftrace_global_list, &global_ops, ops);
 		ops->flags |= FTRACE_OPS_FL_ENABLED;
-		if (first)
-			add_ftrace_ops(&ftrace_ops_list, &global_ops);
+	} else if (ops->flags & FTRACE_OPS_FL_CONTROL) {
+		if (control_ops_alloc(ops))
+			return -ENOMEM;
+		add_ftrace_list_ops(&ftrace_control_list, &control_ops, ops);
 	} else
 		add_ftrace_ops(&ftrace_ops_list, ops);
 
@@ -302,11 +357,23 @@
 		return -EINVAL;
 
 	if (ops->flags & FTRACE_OPS_FL_GLOBAL) {
-		ret = remove_ftrace_ops(&ftrace_global_list, ops);
-		if (!ret && ftrace_global_list == &ftrace_list_end)
-			ret = remove_ftrace_ops(&ftrace_ops_list, &global_ops);
+		ret = remove_ftrace_list_ops(&ftrace_global_list,
+					     &global_ops, ops);
 		if (!ret)
 			ops->flags &= ~FTRACE_OPS_FL_ENABLED;
+	} else if (ops->flags & FTRACE_OPS_FL_CONTROL) {
+		ret = remove_ftrace_list_ops(&ftrace_control_list,
+					     &control_ops, ops);
+		if (!ret) {
+			/*
+			 * The ftrace_ops is now removed from the list,
+			 * so there'll be no new users. We must ensure
+			 * all current users are done before we free
+			 * the control data.
+			 */
+			synchronize_sched();
+			control_ops_free(ops);
+		}
 	} else
 		ret = remove_ftrace_ops(&ftrace_ops_list, ops);
 
@@ -1119,6 +1186,12 @@
 	call_rcu_sched(&hash->rcu, __free_ftrace_hash_rcu);
 }
 
+void ftrace_free_filter(struct ftrace_ops *ops)
+{
+	free_ftrace_hash(ops->filter_hash);
+	free_ftrace_hash(ops->notrace_hash);
+}
+
 static struct ftrace_hash *alloc_ftrace_hash(int size_bits)
 {
 	struct ftrace_hash *hash;
@@ -1129,7 +1202,7 @@
 		return NULL;
 
 	size = 1 << size_bits;
-	hash->buckets = kzalloc(sizeof(*hash->buckets) * size, GFP_KERNEL);
+	hash->buckets = kcalloc(size, sizeof(*hash->buckets), GFP_KERNEL);
 
 	if (!hash->buckets) {
 		kfree(hash);
@@ -3146,8 +3219,10 @@
 	mutex_lock(&ftrace_regex_lock);
 	if (reset)
 		ftrace_filter_reset(hash);
-	if (buf)
-		ftrace_match_records(hash, buf, len);
+	if (buf && !ftrace_match_records(hash, buf, len)) {
+		ret = -EINVAL;
+		goto out_regex_unlock;
+	}
 
 	mutex_lock(&ftrace_lock);
 	ret = ftrace_hash_move(ops, enable, orig_hash, hash);
@@ -3157,6 +3232,7 @@
 
 	mutex_unlock(&ftrace_lock);
 
+ out_regex_unlock:
 	mutex_unlock(&ftrace_regex_lock);
 
 	free_ftrace_hash(hash);
@@ -3173,10 +3249,10 @@
  * Filters denote which functions should be enabled when tracing is enabled.
  * If @buf is NULL and reset is set, all functions will be enabled for tracing.
  */
-void ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf,
+int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf,
 		       int len, int reset)
 {
-	ftrace_set_regex(ops, buf, len, reset, 1);
+	return ftrace_set_regex(ops, buf, len, reset, 1);
 }
 EXPORT_SYMBOL_GPL(ftrace_set_filter);
 
@@ -3191,10 +3267,10 @@
  * is enabled. If @buf is NULL and reset is set, all functions will be enabled
  * for tracing.
  */
-void ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,
+int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,
 			int len, int reset)
 {
-	ftrace_set_regex(ops, buf, len, reset, 0);
+	return ftrace_set_regex(ops, buf, len, reset, 0);
 }
 EXPORT_SYMBOL_GPL(ftrace_set_notrace);
 /**
@@ -3871,6 +3947,36 @@
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
 static void
+ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip)
+{
+	struct ftrace_ops *op;
+
+	if (unlikely(trace_recursion_test(TRACE_CONTROL_BIT)))
+		return;
+
+	/*
+	 * Some of the ops may be dynamically allocated,
+	 * they must be freed after a synchronize_sched().
+	 */
+	preempt_disable_notrace();
+	trace_recursion_set(TRACE_CONTROL_BIT);
+	op = rcu_dereference_raw(ftrace_control_list);
+	while (op != &ftrace_list_end) {
+		if (!ftrace_function_local_disabled(op) &&
+		    ftrace_ops_test(op, ip))
+			op->func(ip, parent_ip);
+
+		op = rcu_dereference_raw(op->next);
+	};
+	trace_recursion_clear(TRACE_CONTROL_BIT);
+	preempt_enable_notrace();
+}
+
+static struct ftrace_ops control_ops = {
+	.func = ftrace_ops_control_func,
+};
+
+static void
 ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip)
 {
 	struct ftrace_ops *op;
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index a3f1bc5..10d5503 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -2764,12 +2764,12 @@
 	"tracing mini-HOWTO:\n\n"
 	"# mount -t debugfs nodev /sys/kernel/debug\n\n"
 	"# cat /sys/kernel/debug/tracing/available_tracers\n"
-	"wakeup preemptirqsoff preemptoff irqsoff function sched_switch nop\n\n"
+	"wakeup wakeup_rt preemptirqsoff preemptoff irqsoff function nop\n\n"
 	"# cat /sys/kernel/debug/tracing/current_tracer\n"
 	"nop\n"
-	"# echo sched_switch > /sys/kernel/debug/tracing/current_tracer\n"
+	"# echo wakeup > /sys/kernel/debug/tracing/current_tracer\n"
 	"# cat /sys/kernel/debug/tracing/current_tracer\n"
-	"sched_switch\n"
+	"wakeup\n"
 	"# cat /sys/kernel/debug/tracing/trace_options\n"
 	"noprint-parent nosym-offset nosym-addr noverbose\n"
 	"# echo print-parent > /sys/kernel/debug/tracing/trace_options\n"
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index b93ecba..54faec7 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -56,17 +56,23 @@
 #define F_STRUCT(args...)		args
 
 #undef FTRACE_ENTRY
-#define FTRACE_ENTRY(name, struct_name, id, tstruct, print)	\
-	struct struct_name {					\
-		struct trace_entry	ent;			\
-		tstruct						\
+#define FTRACE_ENTRY(name, struct_name, id, tstruct, print, filter)	\
+	struct struct_name {						\
+		struct trace_entry	ent;				\
+		tstruct							\
 	}
 
 #undef TP_ARGS
 #define TP_ARGS(args...)	args
 
 #undef FTRACE_ENTRY_DUP
-#define FTRACE_ENTRY_DUP(name, name_struct, id, tstruct, printk)
+#define FTRACE_ENTRY_DUP(name, name_struct, id, tstruct, printk, filter)
+
+#undef FTRACE_ENTRY_REG
+#define FTRACE_ENTRY_REG(name, struct_name, id, tstruct, print,	\
+			 filter, regfn) \
+	FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print), \
+		     filter)
 
 #include "trace_entries.h"
 
@@ -288,6 +294,8 @@
 /* for function tracing recursion */
 #define TRACE_INTERNAL_BIT		(1<<11)
 #define TRACE_GLOBAL_BIT		(1<<12)
+#define TRACE_CONTROL_BIT		(1<<13)
+
 /*
  * Abuse of the trace_recursion.
  * As we need a way to maintain state if we are tracing the function
@@ -589,6 +597,8 @@
 static inline int ftrace_is_dead(void) { return 0; }
 #endif
 
+int ftrace_event_is_function(struct ftrace_event_call *call);
+
 /*
  * struct trace_parser - servers for reading the user input separated by spaces
  * @cont: set if the input is not complete - no final space char was found
@@ -766,9 +776,7 @@
 	u64 			val;
 	struct regex		regex;
 	unsigned short		*ops;
-#ifdef CONFIG_FTRACE_STARTUP_TEST
 	struct ftrace_event_field *field;
-#endif
 	int 			offset;
 	int 			not;
 	int 			op;
@@ -818,12 +826,22 @@
 extern const char *__stop___trace_bprintk_fmt[];
 
 #undef FTRACE_ENTRY
-#define FTRACE_ENTRY(call, struct_name, id, tstruct, print)		\
+#define FTRACE_ENTRY(call, struct_name, id, tstruct, print, filter)	\
 	extern struct ftrace_event_call					\
 	__attribute__((__aligned__(4))) event_##call;
 #undef FTRACE_ENTRY_DUP
-#define FTRACE_ENTRY_DUP(call, struct_name, id, tstruct, print)		\
-	FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print))
+#define FTRACE_ENTRY_DUP(call, struct_name, id, tstruct, print, filter)	\
+	FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print), \
+		     filter)
 #include "trace_entries.h"
 
+#ifdef CONFIG_PERF_EVENTS
+#ifdef CONFIG_FUNCTION_TRACER
+int perf_ftrace_event_register(struct ftrace_event_call *call,
+			       enum trace_reg type, void *data);
+#else
+#define perf_ftrace_event_register NULL
+#endif /* CONFIG_FUNCTION_TRACER */
+#endif /* CONFIG_PERF_EVENTS */
+
 #endif /* _LINUX_KERNEL_TRACE_H */
diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h
index 9336590..d91eb05 100644
--- a/kernel/trace/trace_entries.h
+++ b/kernel/trace/trace_entries.h
@@ -55,7 +55,7 @@
 /*
  * Function trace entry - function address and parent function address:
  */
-FTRACE_ENTRY(function, ftrace_entry,
+FTRACE_ENTRY_REG(function, ftrace_entry,
 
 	TRACE_FN,
 
@@ -64,7 +64,11 @@
 		__field(	unsigned long,	parent_ip	)
 	),
 
-	F_printk(" %lx <-- %lx", __entry->ip, __entry->parent_ip)
+	F_printk(" %lx <-- %lx", __entry->ip, __entry->parent_ip),
+
+	FILTER_TRACE_FN,
+
+	perf_ftrace_event_register
 );
 
 /* Function call entry */
@@ -78,7 +82,9 @@
 		__field_desc(	int,		graph_ent,	depth		)
 	),
 
-	F_printk("--> %lx (%d)", __entry->func, __entry->depth)
+	F_printk("--> %lx (%d)", __entry->func, __entry->depth),
+
+	FILTER_OTHER
 );
 
 /* Function return entry */
@@ -98,7 +104,9 @@
 	F_printk("<-- %lx (%d) (start: %llx  end: %llx) over: %d",
 		 __entry->func, __entry->depth,
 		 __entry->calltime, __entry->rettime,
-		 __entry->depth)
+		 __entry->depth),
+
+	FILTER_OTHER
 );
 
 /*
@@ -127,8 +135,9 @@
 	F_printk("%u:%u:%u  ==> %u:%u:%u [%03u]",
 		 __entry->prev_pid, __entry->prev_prio, __entry->prev_state,
 		 __entry->next_pid, __entry->next_prio, __entry->next_state,
-		 __entry->next_cpu
-		)
+		 __entry->next_cpu),
+
+	FILTER_OTHER
 );
 
 /*
@@ -146,8 +155,9 @@
 	F_printk("%u:%u:%u  ==+ %u:%u:%u [%03u]",
 		 __entry->prev_pid, __entry->prev_prio, __entry->prev_state,
 		 __entry->next_pid, __entry->next_prio, __entry->next_state,
-		 __entry->next_cpu
-		)
+		 __entry->next_cpu),
+
+	FILTER_OTHER
 );
 
 /*
@@ -169,7 +179,9 @@
 		 "\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n",
 		 __entry->caller[0], __entry->caller[1], __entry->caller[2],
 		 __entry->caller[3], __entry->caller[4], __entry->caller[5],
-		 __entry->caller[6], __entry->caller[7])
+		 __entry->caller[6], __entry->caller[7]),
+
+	FILTER_OTHER
 );
 
 FTRACE_ENTRY(user_stack, userstack_entry,
@@ -185,7 +197,9 @@
 		 "\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n",
 		 __entry->caller[0], __entry->caller[1], __entry->caller[2],
 		 __entry->caller[3], __entry->caller[4], __entry->caller[5],
-		 __entry->caller[6], __entry->caller[7])
+		 __entry->caller[6], __entry->caller[7]),
+
+	FILTER_OTHER
 );
 
 /*
@@ -202,7 +216,9 @@
 	),
 
 	F_printk("%08lx fmt:%p",
-		 __entry->ip, __entry->fmt)
+		 __entry->ip, __entry->fmt),
+
+	FILTER_OTHER
 );
 
 FTRACE_ENTRY(print, print_entry,
@@ -215,7 +231,9 @@
 	),
 
 	F_printk("%08lx %s",
-		 __entry->ip, __entry->buf)
+		 __entry->ip, __entry->buf),
+
+	FILTER_OTHER
 );
 
 FTRACE_ENTRY(mmiotrace_rw, trace_mmiotrace_rw,
@@ -234,7 +252,9 @@
 
 	F_printk("%lx %lx %lx %d %x %x",
 		 (unsigned long)__entry->phys, __entry->value, __entry->pc,
-		 __entry->map_id, __entry->opcode, __entry->width)
+		 __entry->map_id, __entry->opcode, __entry->width),
+
+	FILTER_OTHER
 );
 
 FTRACE_ENTRY(mmiotrace_map, trace_mmiotrace_map,
@@ -252,7 +272,9 @@
 
 	F_printk("%lx %lx %lx %d %x",
 		 (unsigned long)__entry->phys, __entry->virt, __entry->len,
-		 __entry->map_id, __entry->opcode)
+		 __entry->map_id, __entry->opcode),
+
+	FILTER_OTHER
 );
 
 
@@ -272,6 +294,8 @@
 
 	F_printk("%u:%s:%s (%u)",
 		 __entry->line,
-		 __entry->func, __entry->file, __entry->correct)
+		 __entry->func, __entry->file, __entry->correct),
+
+	FILTER_OTHER
 );
 
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index 19a359d..fee3752 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -24,6 +24,11 @@
 static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
 				 struct perf_event *p_event)
 {
+	/* The ftrace function trace is allowed only for root. */
+	if (ftrace_event_is_function(tp_event) &&
+	    perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
 	/* No tracing, just counting, so no obvious leak */
 	if (!(p_event->attr.sample_type & PERF_SAMPLE_RAW))
 		return 0;
@@ -44,23 +49,17 @@
 	return 0;
 }
 
-static int perf_trace_event_init(struct ftrace_event_call *tp_event,
-				 struct perf_event *p_event)
+static int perf_trace_event_reg(struct ftrace_event_call *tp_event,
+				struct perf_event *p_event)
 {
 	struct hlist_head __percpu *list;
-	int ret;
+	int ret = -ENOMEM;
 	int cpu;
 
-	ret = perf_trace_event_perm(tp_event, p_event);
-	if (ret)
-		return ret;
-
 	p_event->tp_event = tp_event;
 	if (tp_event->perf_refcount++ > 0)
 		return 0;
 
-	ret = -ENOMEM;
-
 	list = alloc_percpu(struct hlist_head);
 	if (!list)
 		goto fail;
@@ -83,7 +82,7 @@
 		}
 	}
 
-	ret = tp_event->class->reg(tp_event, TRACE_REG_PERF_REGISTER);
+	ret = tp_event->class->reg(tp_event, TRACE_REG_PERF_REGISTER, NULL);
 	if (ret)
 		goto fail;
 
@@ -108,6 +107,69 @@
 	return ret;
 }
 
+static void perf_trace_event_unreg(struct perf_event *p_event)
+{
+	struct ftrace_event_call *tp_event = p_event->tp_event;
+	int i;
+
+	if (--tp_event->perf_refcount > 0)
+		goto out;
+
+	tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER, NULL);
+
+	/*
+	 * Ensure our callback won't be called anymore. The buffers
+	 * will be freed after that.
+	 */
+	tracepoint_synchronize_unregister();
+
+	free_percpu(tp_event->perf_events);
+	tp_event->perf_events = NULL;
+
+	if (!--total_ref_count) {
+		for (i = 0; i < PERF_NR_CONTEXTS; i++) {
+			free_percpu(perf_trace_buf[i]);
+			perf_trace_buf[i] = NULL;
+		}
+	}
+out:
+	module_put(tp_event->mod);
+}
+
+static int perf_trace_event_open(struct perf_event *p_event)
+{
+	struct ftrace_event_call *tp_event = p_event->tp_event;
+	return tp_event->class->reg(tp_event, TRACE_REG_PERF_OPEN, p_event);
+}
+
+static void perf_trace_event_close(struct perf_event *p_event)
+{
+	struct ftrace_event_call *tp_event = p_event->tp_event;
+	tp_event->class->reg(tp_event, TRACE_REG_PERF_CLOSE, p_event);
+}
+
+static int perf_trace_event_init(struct ftrace_event_call *tp_event,
+				 struct perf_event *p_event)
+{
+	int ret;
+
+	ret = perf_trace_event_perm(tp_event, p_event);
+	if (ret)
+		return ret;
+
+	ret = perf_trace_event_reg(tp_event, p_event);
+	if (ret)
+		return ret;
+
+	ret = perf_trace_event_open(p_event);
+	if (ret) {
+		perf_trace_event_unreg(p_event);
+		return ret;
+	}
+
+	return 0;
+}
+
 int perf_trace_init(struct perf_event *p_event)
 {
 	struct ftrace_event_call *tp_event;
@@ -130,6 +192,14 @@
 	return ret;
 }
 
+void perf_trace_destroy(struct perf_event *p_event)
+{
+	mutex_lock(&event_mutex);
+	perf_trace_event_close(p_event);
+	perf_trace_event_unreg(p_event);
+	mutex_unlock(&event_mutex);
+}
+
 int perf_trace_add(struct perf_event *p_event, int flags)
 {
 	struct ftrace_event_call *tp_event = p_event->tp_event;
@@ -146,43 +216,14 @@
 	list = this_cpu_ptr(pcpu_list);
 	hlist_add_head_rcu(&p_event->hlist_entry, list);
 
-	return 0;
+	return tp_event->class->reg(tp_event, TRACE_REG_PERF_ADD, p_event);
 }
 
 void perf_trace_del(struct perf_event *p_event, int flags)
 {
-	hlist_del_rcu(&p_event->hlist_entry);
-}
-
-void perf_trace_destroy(struct perf_event *p_event)
-{
 	struct ftrace_event_call *tp_event = p_event->tp_event;
-	int i;
-
-	mutex_lock(&event_mutex);
-	if (--tp_event->perf_refcount > 0)
-		goto out;
-
-	tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER);
-
-	/*
-	 * Ensure our callback won't be called anymore. The buffers
-	 * will be freed after that.
-	 */
-	tracepoint_synchronize_unregister();
-
-	free_percpu(tp_event->perf_events);
-	tp_event->perf_events = NULL;
-
-	if (!--total_ref_count) {
-		for (i = 0; i < PERF_NR_CONTEXTS; i++) {
-			free_percpu(perf_trace_buf[i]);
-			perf_trace_buf[i] = NULL;
-		}
-	}
-out:
-	module_put(tp_event->mod);
-	mutex_unlock(&event_mutex);
+	hlist_del_rcu(&p_event->hlist_entry);
+	tp_event->class->reg(tp_event, TRACE_REG_PERF_DEL, p_event);
 }
 
 __kprobes void *perf_trace_buf_prepare(int size, unsigned short type,
@@ -214,3 +255,86 @@
 	return raw_data;
 }
 EXPORT_SYMBOL_GPL(perf_trace_buf_prepare);
+
+#ifdef CONFIG_FUNCTION_TRACER
+static void
+perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip)
+{
+	struct ftrace_entry *entry;
+	struct hlist_head *head;
+	struct pt_regs regs;
+	int rctx;
+
+#define ENTRY_SIZE (ALIGN(sizeof(struct ftrace_entry) + sizeof(u32), \
+		    sizeof(u64)) - sizeof(u32))
+
+	BUILD_BUG_ON(ENTRY_SIZE > PERF_MAX_TRACE_SIZE);
+
+	perf_fetch_caller_regs(&regs);
+
+	entry = perf_trace_buf_prepare(ENTRY_SIZE, TRACE_FN, NULL, &rctx);
+	if (!entry)
+		return;
+
+	entry->ip = ip;
+	entry->parent_ip = parent_ip;
+
+	head = this_cpu_ptr(event_function.perf_events);
+	perf_trace_buf_submit(entry, ENTRY_SIZE, rctx, 0,
+			      1, &regs, head);
+
+#undef ENTRY_SIZE
+}
+
+static int perf_ftrace_function_register(struct perf_event *event)
+{
+	struct ftrace_ops *ops = &event->ftrace_ops;
+
+	ops->flags |= FTRACE_OPS_FL_CONTROL;
+	ops->func = perf_ftrace_function_call;
+	return register_ftrace_function(ops);
+}
+
+static int perf_ftrace_function_unregister(struct perf_event *event)
+{
+	struct ftrace_ops *ops = &event->ftrace_ops;
+	int ret = unregister_ftrace_function(ops);
+	ftrace_free_filter(ops);
+	return ret;
+}
+
+static void perf_ftrace_function_enable(struct perf_event *event)
+{
+	ftrace_function_local_enable(&event->ftrace_ops);
+}
+
+static void perf_ftrace_function_disable(struct perf_event *event)
+{
+	ftrace_function_local_disable(&event->ftrace_ops);
+}
+
+int perf_ftrace_event_register(struct ftrace_event_call *call,
+			       enum trace_reg type, void *data)
+{
+	switch (type) {
+	case TRACE_REG_REGISTER:
+	case TRACE_REG_UNREGISTER:
+		break;
+	case TRACE_REG_PERF_REGISTER:
+	case TRACE_REG_PERF_UNREGISTER:
+		return 0;
+	case TRACE_REG_PERF_OPEN:
+		return perf_ftrace_function_register(data);
+	case TRACE_REG_PERF_CLOSE:
+		return perf_ftrace_function_unregister(data);
+	case TRACE_REG_PERF_ADD:
+		perf_ftrace_function_enable(data);
+		return 0;
+	case TRACE_REG_PERF_DEL:
+		perf_ftrace_function_disable(data);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+#endif /* CONFIG_FUNCTION_TRACER */
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index c212a7f..079a93a 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -147,7 +147,8 @@
 }
 EXPORT_SYMBOL_GPL(trace_event_raw_init);
 
-int ftrace_event_reg(struct ftrace_event_call *call, enum trace_reg type)
+int ftrace_event_reg(struct ftrace_event_call *call,
+		     enum trace_reg type, void *data)
 {
 	switch (type) {
 	case TRACE_REG_REGISTER:
@@ -170,6 +171,11 @@
 					    call->class->perf_probe,
 					    call);
 		return 0;
+	case TRACE_REG_PERF_OPEN:
+	case TRACE_REG_PERF_CLOSE:
+	case TRACE_REG_PERF_ADD:
+	case TRACE_REG_PERF_DEL:
+		return 0;
 #endif
 	}
 	return 0;
@@ -209,7 +215,7 @@
 				tracing_stop_cmdline_record();
 				call->flags &= ~TRACE_EVENT_FL_RECORDED_CMD;
 			}
-			call->class->reg(call, TRACE_REG_UNREGISTER);
+			call->class->reg(call, TRACE_REG_UNREGISTER, NULL);
 		}
 		break;
 	case 1:
@@ -218,7 +224,7 @@
 				tracing_start_cmdline_record();
 				call->flags |= TRACE_EVENT_FL_RECORDED_CMD;
 			}
-			ret = call->class->reg(call, TRACE_REG_REGISTER);
+			ret = call->class->reg(call, TRACE_REG_REGISTER, NULL);
 			if (ret) {
 				tracing_stop_cmdline_record();
 				pr_info("event trace: Could not enable event "
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 24aee71..431dba8 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -81,6 +81,7 @@
 	FILT_ERR_TOO_MANY_PREDS,
 	FILT_ERR_MISSING_FIELD,
 	FILT_ERR_INVALID_FILTER,
+	FILT_ERR_IP_FIELD_ONLY,
 };
 
 static char *err_text[] = {
@@ -96,6 +97,7 @@
 	"Too many terms in predicate expression",
 	"Missing field name and/or value",
 	"Meaningless filter expression",
+	"Only 'ip' field is supported for function trace",
 };
 
 struct opstack_op {
@@ -685,7 +687,7 @@
 
 static int __alloc_pred_stack(struct pred_stack *stack, int n_preds)
 {
-	stack->preds = kzalloc(sizeof(*stack->preds)*(n_preds + 1), GFP_KERNEL);
+	stack->preds = kcalloc(n_preds + 1, sizeof(*stack->preds), GFP_KERNEL);
 	if (!stack->preds)
 		return -ENOMEM;
 	stack->index = n_preds;
@@ -826,8 +828,7 @@
 	if (filter->preds)
 		__free_preds(filter);
 
-	filter->preds =
-		kzalloc(sizeof(*filter->preds) * n_preds, GFP_KERNEL);
+	filter->preds = kcalloc(n_preds, sizeof(*filter->preds), GFP_KERNEL);
 
 	if (!filter->preds)
 		return -ENOMEM;
@@ -900,6 +901,11 @@
 	return FILTER_OTHER;
 }
 
+static bool is_function_field(struct ftrace_event_field *field)
+{
+	return field->filter_type == FILTER_TRACE_FN;
+}
+
 static bool is_string_field(struct ftrace_event_field *field)
 {
 	return field->filter_type == FILTER_DYN_STRING ||
@@ -987,6 +993,11 @@
 			fn = filter_pred_strloc;
 		else
 			fn = filter_pred_pchar;
+	} else if (is_function_field(field)) {
+		if (strcmp(field->name, "ip")) {
+			parse_error(ps, FILT_ERR_IP_FIELD_ONLY, 0);
+			return -EINVAL;
+		}
 	} else {
 		if (field->is_signed)
 			ret = strict_strtoll(pred->regex.pattern, 0, &val);
@@ -1334,10 +1345,7 @@
 
 	strcpy(pred.regex.pattern, operand2);
 	pred.regex.len = strlen(pred.regex.pattern);
-
-#ifdef CONFIG_FTRACE_STARTUP_TEST
 	pred.field = field;
-#endif
 	return init_pred(ps, field, &pred) ? NULL : &pred;
 }
 
@@ -1486,7 +1494,7 @@
 	children = count_leafs(preds, &preds[root->left]);
 	children += count_leafs(preds, &preds[root->right]);
 
-	root->ops = kzalloc(sizeof(*root->ops) * children, GFP_KERNEL);
+	root->ops = kcalloc(children, sizeof(*root->ops), GFP_KERNEL);
 	if (!root->ops)
 		return -ENOMEM;
 
@@ -1950,6 +1958,148 @@
 	__free_filter(filter);
 }
 
+struct function_filter_data {
+	struct ftrace_ops *ops;
+	int first_filter;
+	int first_notrace;
+};
+
+#ifdef CONFIG_FUNCTION_TRACER
+static char **
+ftrace_function_filter_re(char *buf, int len, int *count)
+{
+	char *str, *sep, **re;
+
+	str = kstrndup(buf, len, GFP_KERNEL);
+	if (!str)
+		return NULL;
+
+	/*
+	 * The argv_split function takes white space
+	 * as a separator, so convert ',' into spaces.
+	 */
+	while ((sep = strchr(str, ',')))
+		*sep = ' ';
+
+	re = argv_split(GFP_KERNEL, str, count);
+	kfree(str);
+	return re;
+}
+
+static int ftrace_function_set_regexp(struct ftrace_ops *ops, int filter,
+				      int reset, char *re, int len)
+{
+	int ret;
+
+	if (filter)
+		ret = ftrace_set_filter(ops, re, len, reset);
+	else
+		ret = ftrace_set_notrace(ops, re, len, reset);
+
+	return ret;
+}
+
+static int __ftrace_function_set_filter(int filter, char *buf, int len,
+					struct function_filter_data *data)
+{
+	int i, re_cnt, ret;
+	int *reset;
+	char **re;
+
+	reset = filter ? &data->first_filter : &data->first_notrace;
+
+	/*
+	 * The 'ip' field could have multiple filters set, separated
+	 * either by space or comma. We first cut the filter and apply
+	 * all pieces separatelly.
+	 */
+	re = ftrace_function_filter_re(buf, len, &re_cnt);
+	if (!re)
+		return -EINVAL;
+
+	for (i = 0; i < re_cnt; i++) {
+		ret = ftrace_function_set_regexp(data->ops, filter, *reset,
+						 re[i], strlen(re[i]));
+		if (ret)
+			break;
+
+		if (*reset)
+			*reset = 0;
+	}
+
+	argv_free(re);
+	return ret;
+}
+
+static int ftrace_function_check_pred(struct filter_pred *pred, int leaf)
+{
+	struct ftrace_event_field *field = pred->field;
+
+	if (leaf) {
+		/*
+		 * Check the leaf predicate for function trace, verify:
+		 *  - only '==' and '!=' is used
+		 *  - the 'ip' field is used
+		 */
+		if ((pred->op != OP_EQ) && (pred->op != OP_NE))
+			return -EINVAL;
+
+		if (strcmp(field->name, "ip"))
+			return -EINVAL;
+	} else {
+		/*
+		 * Check the non leaf predicate for function trace, verify:
+		 *  - only '||' is used
+		*/
+		if (pred->op != OP_OR)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ftrace_function_set_filter_cb(enum move_type move,
+					 struct filter_pred *pred,
+					 int *err, void *data)
+{
+	/* Checking the node is valid for function trace. */
+	if ((move != MOVE_DOWN) ||
+	    (pred->left != FILTER_PRED_INVALID)) {
+		*err = ftrace_function_check_pred(pred, 0);
+	} else {
+		*err = ftrace_function_check_pred(pred, 1);
+		if (*err)
+			return WALK_PRED_ABORT;
+
+		*err = __ftrace_function_set_filter(pred->op == OP_EQ,
+						    pred->regex.pattern,
+						    pred->regex.len,
+						    data);
+	}
+
+	return (*err) ? WALK_PRED_ABORT : WALK_PRED_DEFAULT;
+}
+
+static int ftrace_function_set_filter(struct perf_event *event,
+				      struct event_filter *filter)
+{
+	struct function_filter_data data = {
+		.first_filter  = 1,
+		.first_notrace = 1,
+		.ops           = &event->ftrace_ops,
+	};
+
+	return walk_pred_tree(filter->preds, filter->root,
+			      ftrace_function_set_filter_cb, &data);
+}
+#else
+static int ftrace_function_set_filter(struct perf_event *event,
+				      struct event_filter *filter)
+{
+	return -ENODEV;
+}
+#endif /* CONFIG_FUNCTION_TRACER */
+
 int ftrace_profile_set_filter(struct perf_event *event, int event_id,
 			      char *filter_str)
 {
@@ -1970,9 +2120,16 @@
 		goto out_unlock;
 
 	err = create_filter(call, filter_str, false, &filter);
-	if (!err)
-		event->filter = filter;
+	if (err)
+		goto free_filter;
+
+	if (ftrace_event_is_function(call))
+		err = ftrace_function_set_filter(event, filter);
 	else
+		event->filter = filter;
+
+free_filter:
+	if (err || ftrace_event_is_function(call))
 		__free_filter(filter);
 
 out_unlock:
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c
index bbeec31..7b46c9b 100644
--- a/kernel/trace/trace_export.c
+++ b/kernel/trace/trace_export.c
@@ -18,6 +18,16 @@
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM	ftrace
 
+/*
+ * The FTRACE_ENTRY_REG macro allows ftrace entry to define register
+ * function and thus become accesible via perf.
+ */
+#undef FTRACE_ENTRY_REG
+#define FTRACE_ENTRY_REG(name, struct_name, id, tstruct, print, \
+			 filter, regfn) \
+	FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print), \
+		     filter)
+
 /* not needed for this file */
 #undef __field_struct
 #define __field_struct(type, item)
@@ -44,21 +54,22 @@
 #define F_printk(fmt, args...) fmt, args
 
 #undef FTRACE_ENTRY
-#define FTRACE_ENTRY(name, struct_name, id, tstruct, print)	\
-struct ____ftrace_##name {					\
-	tstruct							\
-};								\
-static void __always_unused ____ftrace_check_##name(void)	\
-{								\
-	struct ____ftrace_##name *__entry = NULL;		\
-								\
-	/* force compile-time check on F_printk() */		\
-	printk(print);						\
+#define FTRACE_ENTRY(name, struct_name, id, tstruct, print, filter)	\
+struct ____ftrace_##name {						\
+	tstruct								\
+};									\
+static void __always_unused ____ftrace_check_##name(void)		\
+{									\
+	struct ____ftrace_##name *__entry = NULL;			\
+									\
+	/* force compile-time check on F_printk() */			\
+	printk(print);							\
 }
 
 #undef FTRACE_ENTRY_DUP
-#define FTRACE_ENTRY_DUP(name, struct_name, id, tstruct, print)	\
-	FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print))
+#define FTRACE_ENTRY_DUP(name, struct_name, id, tstruct, print, filter)	\
+	FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print), \
+		     filter)
 
 #include "trace_entries.h"
 
@@ -67,7 +78,7 @@
 	ret = trace_define_field(event_call, #type, #item,		\
 				 offsetof(typeof(field), item),		\
 				 sizeof(field.item),			\
-				 is_signed_type(type), FILTER_OTHER);	\
+				 is_signed_type(type), filter_type);	\
 	if (ret)							\
 		return ret;
 
@@ -77,7 +88,7 @@
 				 offsetof(typeof(field),		\
 					  container.item),		\
 				 sizeof(field.container.item),		\
-				 is_signed_type(type), FILTER_OTHER);	\
+				 is_signed_type(type), filter_type);	\
 	if (ret)							\
 		return ret;
 
@@ -91,7 +102,7 @@
 		ret = trace_define_field(event_call, event_storage, #item, \
 				 offsetof(typeof(field), item),		\
 				 sizeof(field.item),			\
-				 is_signed_type(type), FILTER_OTHER);	\
+				 is_signed_type(type), filter_type);	\
 		mutex_unlock(&event_storage_mutex);			\
 		if (ret)						\
 			return ret;					\
@@ -104,7 +115,7 @@
 				 offsetof(typeof(field),		\
 					  container.item),		\
 				 sizeof(field.container.item),		\
-				 is_signed_type(type), FILTER_OTHER);	\
+				 is_signed_type(type), filter_type);	\
 	if (ret)							\
 		return ret;
 
@@ -112,17 +123,18 @@
 #define __dynamic_array(type, item)					\
 	ret = trace_define_field(event_call, #type, #item,		\
 				 offsetof(typeof(field), item),		\
-				 0, is_signed_type(type), FILTER_OTHER);\
+				 0, is_signed_type(type), filter_type);\
 	if (ret)							\
 		return ret;
 
 #undef FTRACE_ENTRY
-#define FTRACE_ENTRY(name, struct_name, id, tstruct, print)		\
+#define FTRACE_ENTRY(name, struct_name, id, tstruct, print, filter)	\
 int									\
 ftrace_define_fields_##name(struct ftrace_event_call *event_call)	\
 {									\
 	struct struct_name field;					\
 	int ret;							\
+	int filter_type = filter;					\
 									\
 	tstruct;							\
 									\
@@ -152,13 +164,15 @@
 #undef F_printk
 #define F_printk(fmt, args...) #fmt ", "  __stringify(args)
 
-#undef FTRACE_ENTRY
-#define FTRACE_ENTRY(call, struct_name, etype, tstruct, print)		\
+#undef FTRACE_ENTRY_REG
+#define FTRACE_ENTRY_REG(call, struct_name, etype, tstruct, print, filter,\
+			 regfn)						\
 									\
 struct ftrace_event_class event_class_ftrace_##call = {			\
 	.system			= __stringify(TRACE_SYSTEM),		\
 	.define_fields		= ftrace_define_fields_##call,		\
 	.fields			= LIST_HEAD_INIT(event_class_ftrace_##call.fields),\
+	.reg			= regfn,				\
 };									\
 									\
 struct ftrace_event_call __used event_##call = {			\
@@ -170,4 +184,14 @@
 struct ftrace_event_call __used						\
 __attribute__((section("_ftrace_events"))) *__event_##call = &event_##call;
 
+#undef FTRACE_ENTRY
+#define FTRACE_ENTRY(call, struct_name, etype, tstruct, print, filter)	\
+	FTRACE_ENTRY_REG(call, struct_name, etype,			\
+			 PARAMS(tstruct), PARAMS(print), filter, NULL)
+
+int ftrace_event_is_function(struct ftrace_event_call *call)
+{
+	return call == &event_function;
+}
+
 #include "trace_entries.h"
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 00d527c..580a05e 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -1892,7 +1892,8 @@
 #endif	/* CONFIG_PERF_EVENTS */
 
 static __kprobes
-int kprobe_register(struct ftrace_event_call *event, enum trace_reg type)
+int kprobe_register(struct ftrace_event_call *event,
+		    enum trace_reg type, void *data)
 {
 	struct trace_probe *tp = (struct trace_probe *)event->data;
 
@@ -1909,6 +1910,11 @@
 	case TRACE_REG_PERF_UNREGISTER:
 		disable_trace_probe(tp, TP_FLAG_PROFILE);
 		return 0;
+	case TRACE_REG_PERF_OPEN:
+	case TRACE_REG_PERF_CLOSE:
+	case TRACE_REG_PERF_ADD:
+	case TRACE_REG_PERF_DEL:
+		return 0;
 #endif
 	}
 	return 0;
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index 0d6ff35..c5a0187 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -300,7 +300,7 @@
 	unsigned long mask;
 	const char *str;
 	const char *ret = p->buffer + p->len;
-	int i;
+	int i, first = 1;
 
 	for (i = 0;  flag_array[i].name && flags; i++) {
 
@@ -310,14 +310,16 @@
 
 		str = flag_array[i].name;
 		flags &= ~mask;
-		if (p->len && delim)
+		if (!first && delim)
 			trace_seq_puts(p, delim);
+		else
+			first = 0;
 		trace_seq_puts(p, str);
 	}
 
 	/* check for left over flags */
 	if (flags) {
-		if (p->len && delim)
+		if (!first && delim)
 			trace_seq_puts(p, delim);
 		trace_seq_printf(p, "0x%lx", flags);
 	}
@@ -344,7 +346,7 @@
 		break;
 	}
 
-	if (!p->len)
+	if (ret == (const char *)(p->buffer + p->len))
 		trace_seq_printf(p, "0x%lx", val);
 		
 	trace_seq_putc(p, 0);
@@ -370,7 +372,7 @@
 		break;
 	}
 
-	if (!p->len)
+	if (ret == (const char *)(p->buffer + p->len))
 		trace_seq_printf(p, "0x%llx", val);
 
 	trace_seq_putc(p, 0);
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index cb65454..96fc733 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -17,9 +17,9 @@
 static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
 
 static int syscall_enter_register(struct ftrace_event_call *event,
-				 enum trace_reg type);
+				 enum trace_reg type, void *data);
 static int syscall_exit_register(struct ftrace_event_call *event,
-				 enum trace_reg type);
+				 enum trace_reg type, void *data);
 
 static int syscall_enter_define_fields(struct ftrace_event_call *call);
 static int syscall_exit_define_fields(struct ftrace_event_call *call);
@@ -468,8 +468,8 @@
 	unsigned long addr;
 	int i;
 
-	syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) *
-					NR_syscalls, GFP_KERNEL);
+	syscalls_metadata = kcalloc(NR_syscalls, sizeof(*syscalls_metadata),
+				    GFP_KERNEL);
 	if (!syscalls_metadata) {
 		WARN_ON(1);
 		return -ENOMEM;
@@ -649,7 +649,7 @@
 #endif /* CONFIG_PERF_EVENTS */
 
 static int syscall_enter_register(struct ftrace_event_call *event,
-				 enum trace_reg type)
+				 enum trace_reg type, void *data)
 {
 	switch (type) {
 	case TRACE_REG_REGISTER:
@@ -664,13 +664,18 @@
 	case TRACE_REG_PERF_UNREGISTER:
 		perf_sysenter_disable(event);
 		return 0;
+	case TRACE_REG_PERF_OPEN:
+	case TRACE_REG_PERF_CLOSE:
+	case TRACE_REG_PERF_ADD:
+	case TRACE_REG_PERF_DEL:
+		return 0;
 #endif
 	}
 	return 0;
 }
 
 static int syscall_exit_register(struct ftrace_event_call *event,
-				 enum trace_reg type)
+				 enum trace_reg type, void *data)
 {
 	switch (type) {
 	case TRACE_REG_REGISTER:
@@ -685,6 +690,11 @@
 	case TRACE_REG_PERF_UNREGISTER:
 		perf_sysexit_disable(event);
 		return 0;
+	case TRACE_REG_PERF_OPEN:
+	case TRACE_REG_PERF_CLOSE:
+	case TRACE_REG_PERF_ADD:
+	case TRACE_REG_PERF_DEL:
+		return 0;
 #endif
 	}
 	return 0;
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c
index f1539de..d96ba22 100644
--- a/kernel/tracepoint.c
+++ b/kernel/tracepoint.c
@@ -25,7 +25,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
-#include <linux/jump_label.h>
+#include <linux/static_key.h>
 
 extern struct tracepoint * const __start___tracepoints_ptrs[];
 extern struct tracepoint * const __stop___tracepoints_ptrs[];
@@ -256,9 +256,9 @@
 {
 	WARN_ON(strcmp((*entry)->name, elem->name) != 0);
 
-	if (elem->regfunc && !jump_label_enabled(&elem->key) && active)
+	if (elem->regfunc && !static_key_enabled(&elem->key) && active)
 		elem->regfunc();
-	else if (elem->unregfunc && jump_label_enabled(&elem->key) && !active)
+	else if (elem->unregfunc && static_key_enabled(&elem->key) && !active)
 		elem->unregfunc();
 
 	/*
@@ -269,10 +269,10 @@
 	 * is used.
 	 */
 	rcu_assign_pointer(elem->funcs, (*entry)->funcs);
-	if (active && !jump_label_enabled(&elem->key))
-		jump_label_inc(&elem->key);
-	else if (!active && jump_label_enabled(&elem->key))
-		jump_label_dec(&elem->key);
+	if (active && !static_key_enabled(&elem->key))
+		static_key_slow_inc(&elem->key);
+	else if (!active && static_key_enabled(&elem->key))
+		static_key_slow_dec(&elem->key);
 }
 
 /*
@@ -283,11 +283,11 @@
  */
 static void disable_tracepoint(struct tracepoint *elem)
 {
-	if (elem->unregfunc && jump_label_enabled(&elem->key))
+	if (elem->unregfunc && static_key_enabled(&elem->key))
 		elem->unregfunc();
 
-	if (jump_label_enabled(&elem->key))
-		jump_label_dec(&elem->key);
+	if (static_key_enabled(&elem->key))
+		static_key_slow_dec(&elem->key);
 	rcu_assign_pointer(elem->funcs, NULL);
 }
 
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index d117262..14bc092 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -3,12 +3,9 @@
  *
  * started by Don Zickus, Copyright (C) 2010 Red Hat, Inc.
  *
- * this code detects hard lockups: incidents in where on a CPU
- * the kernel does not respond to anything except NMI.
- *
- * Note: Most of this code is borrowed heavily from softlockup.c,
- * so thanks to Ingo for the initial implementation.
- * Some chunks also taken from arch/x86/kernel/apic/nmi.c, thanks
+ * Note: Most of this code is borrowed heavily from the original softlockup
+ * detector, so thanks to Ingo for the initial implementation.
+ * Some chunks also taken from the old x86-specific nmi watchdog code, thanks
  * to those contributors as well.
  */
 
@@ -117,9 +114,10 @@
 {
 	/*
 	 * convert watchdog_thresh from seconds to ns
-	 * the divide by 5 is to give hrtimer 5 chances to
-	 * increment before the hardlockup detector generates
-	 * a warning
+	 * the divide by 5 is to give hrtimer several chances (two
+	 * or three with the current relation between the soft
+	 * and hard thresholds) to increment before the
+	 * hardlockup detector generates a warning
 	 */
 	return get_softlockup_thresh() * (NSEC_PER_SEC / 5);
 }
@@ -336,9 +334,11 @@
 
 	set_current_state(TASK_INTERRUPTIBLE);
 	/*
-	 * Run briefly once per second to reset the softlockup timestamp.
-	 * If this gets delayed for more than 60 seconds then the
-	 * debug-printout triggers in watchdog_timer_fn().
+	 * Run briefly (kicked by the hrtimer callback function) once every
+	 * get_sample_period() seconds (4 seconds by default) to reset the
+	 * softlockup timestamp. If this gets delayed for more than
+	 * 2*watchdog_thresh seconds then the debug-printout triggers in
+	 * watchdog_timer_fn().
 	 */
 	while (!kthread_should_stop()) {
 		__touch_watchdog();
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 5bbba09..5abf42f 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -253,11 +253,13 @@
 struct workqueue_struct *system_nrt_wq __read_mostly;
 struct workqueue_struct *system_unbound_wq __read_mostly;
 struct workqueue_struct *system_freezable_wq __read_mostly;
+struct workqueue_struct *system_nrt_freezable_wq __read_mostly;
 EXPORT_SYMBOL_GPL(system_wq);
 EXPORT_SYMBOL_GPL(system_long_wq);
 EXPORT_SYMBOL_GPL(system_nrt_wq);
 EXPORT_SYMBOL_GPL(system_unbound_wq);
 EXPORT_SYMBOL_GPL(system_freezable_wq);
+EXPORT_SYMBOL_GPL(system_nrt_freezable_wq);
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/workqueue.h>
@@ -3817,8 +3819,11 @@
 					    WQ_UNBOUND_MAX_ACTIVE);
 	system_freezable_wq = alloc_workqueue("events_freezable",
 					      WQ_FREEZABLE, 0);
+	system_nrt_freezable_wq = alloc_workqueue("events_nrt_freezable",
+			WQ_NON_REENTRANT | WQ_FREEZABLE, 0);
 	BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq ||
-	       !system_unbound_wq || !system_freezable_wq);
+	       !system_unbound_wq || !system_freezable_wq ||
+		!system_nrt_freezable_wq);
 	return 0;
 }
 early_initcall(init_workqueues);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 8745ac7..05037dc 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -166,18 +166,21 @@
 	  hard and soft lockups.
 
 	  Softlockups are bugs that cause the kernel to loop in kernel
-	  mode for more than 60 seconds, without giving other tasks a
+	  mode for more than 20 seconds, without giving other tasks a
 	  chance to run.  The current stack trace is displayed upon
 	  detection and the system will stay locked up.
 
 	  Hardlockups are bugs that cause the CPU to loop in kernel mode
-	  for more than 60 seconds, without letting other interrupts have a
+	  for more than 10 seconds, without letting other interrupts have a
 	  chance to run.  The current stack trace is displayed upon detection
 	  and the system will stay locked up.
 
 	  The overhead should be minimal.  A periodic hrtimer runs to
-	  generate interrupts and kick the watchdog task every 10-12 seconds.
-	  An NMI is generated every 60 seconds or so to check for hardlockups.
+	  generate interrupts and kick the watchdog task every 4 seconds.
+	  An NMI is generated every 10 seconds or so to check for hardlockups.
+
+	  The frequency of hrtimer and NMI events and the soft and hard lockup
+	  thresholds can be controlled through the sysctl watchdog_thresh.
 
 config HARDLOCKUP_DETECTOR
 	def_bool LOCKUP_DETECTOR && PERF_EVENTS && HAVE_PERF_EVENTS_NMI && \
@@ -189,7 +192,8 @@
 	help
 	  Say Y here to enable the kernel to panic on "hard lockups",
 	  which are bugs that cause the kernel to loop in kernel
-	  mode with interrupts disabled for more than 60 seconds.
+	  mode with interrupts disabled for more than 10 seconds (configurable
+	  using the watchdog_thresh sysctl).
 
 	  Say N if unsure.
 
@@ -206,8 +210,8 @@
 	help
 	  Say Y here to enable the kernel to panic on "soft lockups",
 	  which are bugs that cause the kernel to loop in kernel
-	  mode for more than 60 seconds, without giving other tasks a
-	  chance to run.
+	  mode for more than 20 seconds (configurable using the watchdog_thresh
+	  sysctl), without giving other tasks a chance to run.
 
 	  The panic can be used in combination with panic_timeout,
 	  to cause the system to reboot automatically after a
@@ -927,6 +931,30 @@
 
 	  Say Y if you want to enable such checks.
 
+config RCU_CPU_STALL_INFO
+	bool "Print additional diagnostics on RCU CPU stall"
+	depends on (TREE_RCU || TREE_PREEMPT_RCU) && DEBUG_KERNEL
+	default n
+	help
+	  For each stalled CPU that is aware of the current RCU grace
+	  period, print out additional per-CPU diagnostic information
+	  regarding scheduling-clock ticks, idle state, and,
+	  for RCU_FAST_NO_HZ kernels, idle-entry state.
+
+	  Say N if you are unsure.
+
+	  Say Y if you want to enable such diagnostics.
+
+config RCU_TRACE
+	bool "Enable tracing for RCU"
+	depends on DEBUG_KERNEL
+	help
+	  This option provides tracing in RCU which presents stats
+	  in debugfs for debugging RCU implementation.
+
+	  Say Y here if you want to enable RCU tracing
+	  Say N if you are unsure.
+
 config KPROBES_SANITY_TEST
 	bool "Kprobes sanity tests"
 	depends on DEBUG_KERNEL
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index fea790a..13ef233 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -170,7 +170,7 @@
 		return false;
 
 	/* driver filter on but not yet initialized */
-	drv = get_driver(dev->driver);
+	drv = dev->driver;
 	if (!drv)
 		return false;
 
@@ -185,7 +185,6 @@
 	}
 
 	read_unlock_irqrestore(&driver_name_lock, flags);
-	put_driver(drv);
 
 	return ret;
 }
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index dcdade3..310c753 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -60,6 +60,7 @@
 static DEFINE_MUTEX(ddebug_lock);
 static LIST_HEAD(ddebug_tables);
 static int verbose = 0;
+module_param(verbose, int, 0644);
 
 /* Return the last part of a pathname */
 static inline const char *basename(const char *path)
@@ -68,12 +69,24 @@
 	return tail ? tail+1 : path;
 }
 
+/* Return the path relative to source root */
+static inline const char *trim_prefix(const char *path)
+{
+	int skip = strlen(__FILE__) - strlen("lib/dynamic_debug.c");
+
+	if (strncmp(path, __FILE__, skip))
+		skip = 0; /* prefix mismatch, don't skip */
+
+	return path + skip;
+}
+
 static struct { unsigned flag:8; char opt_char; } opt_array[] = {
 	{ _DPRINTK_FLAGS_PRINT, 'p' },
 	{ _DPRINTK_FLAGS_INCL_MODNAME, 'm' },
 	{ _DPRINTK_FLAGS_INCL_FUNCNAME, 'f' },
 	{ _DPRINTK_FLAGS_INCL_LINENO, 'l' },
 	{ _DPRINTK_FLAGS_INCL_TID, 't' },
+	{ _DPRINTK_FLAGS_NONE, '_' },
 };
 
 /* format a string into buf[] which describes the _ddebug's flags */
@@ -83,58 +96,74 @@
 	char *p = buf;
 	int i;
 
-	BUG_ON(maxlen < 4);
+	BUG_ON(maxlen < 6);
 	for (i = 0; i < ARRAY_SIZE(opt_array); ++i)
 		if (dp->flags & opt_array[i].flag)
 			*p++ = opt_array[i].opt_char;
 	if (p == buf)
-		*p++ = '-';
+		*p++ = '_';
 	*p = '\0';
 
 	return buf;
 }
 
+#define vpr_info_dq(q, msg)						\
+do {									\
+	if (verbose)							\
+		/* trim last char off format print */			\
+		pr_info("%s: func=\"%s\" file=\"%s\" "			\
+			"module=\"%s\" format=\"%.*s\" "		\
+			"lineno=%u-%u",					\
+			msg,						\
+			q->function ? q->function : "",			\
+			q->filename ? q->filename : "",			\
+			q->module ? q->module : "",			\
+			(int)(q->format ? strlen(q->format) - 1 : 0),	\
+			q->format ? q->format : "",			\
+			q->first_lineno, q->last_lineno);		\
+} while (0)
+
 /*
- * Search the tables for _ddebug's which match the given
- * `query' and apply the `flags' and `mask' to them.  Tells
- * the user which ddebug's were changed, or whether none
- * were matched.
+ * Search the tables for _ddebug's which match the given `query' and
+ * apply the `flags' and `mask' to them.  Returns number of matching
+ * callsites, normally the same as number of changes.  If verbose,
+ * logs the changes.  Takes ddebug_lock.
  */
-static void ddebug_change(const struct ddebug_query *query,
-			   unsigned int flags, unsigned int mask)
+static int ddebug_change(const struct ddebug_query *query,
+			unsigned int flags, unsigned int mask)
 {
 	int i;
 	struct ddebug_table *dt;
 	unsigned int newflags;
 	unsigned int nfound = 0;
-	char flagbuf[8];
+	char flagbuf[10];
 
 	/* search for matching ddebugs */
 	mutex_lock(&ddebug_lock);
 	list_for_each_entry(dt, &ddebug_tables, link) {
 
 		/* match against the module name */
-		if (query->module != NULL &&
-		    strcmp(query->module, dt->mod_name))
+		if (query->module && strcmp(query->module, dt->mod_name))
 			continue;
 
 		for (i = 0 ; i < dt->num_ddebugs ; i++) {
 			struct _ddebug *dp = &dt->ddebugs[i];
 
 			/* match against the source filename */
-			if (query->filename != NULL &&
+			if (query->filename &&
 			    strcmp(query->filename, dp->filename) &&
-			    strcmp(query->filename, basename(dp->filename)))
+			    strcmp(query->filename, basename(dp->filename)) &&
+			    strcmp(query->filename, trim_prefix(dp->filename)))
 				continue;
 
 			/* match against the function */
-			if (query->function != NULL &&
+			if (query->function &&
 			    strcmp(query->function, dp->function))
 				continue;
 
 			/* match against the format */
-			if (query->format != NULL &&
-			    strstr(dp->format, query->format) == NULL)
+			if (query->format &&
+			    !strstr(dp->format, query->format))
 				continue;
 
 			/* match against the line number range */
@@ -151,13 +180,9 @@
 			if (newflags == dp->flags)
 				continue;
 			dp->flags = newflags;
-			if (newflags)
-				dp->enabled = 1;
-			else
-				dp->enabled = 0;
 			if (verbose)
-				pr_info("changed %s:%d [%s]%s %s\n",
-					dp->filename, dp->lineno,
+				pr_info("changed %s:%d [%s]%s =%s\n",
+					trim_prefix(dp->filename), dp->lineno,
 					dt->mod_name, dp->function,
 					ddebug_describe_flags(dp, flagbuf,
 							sizeof(flagbuf)));
@@ -167,6 +192,8 @@
 
 	if (!nfound && verbose)
 		pr_info("no matches for query\n");
+
+	return nfound;
 }
 
 /*
@@ -186,8 +213,10 @@
 		buf = skip_spaces(buf);
 		if (!*buf)
 			break;	/* oh, it was trailing whitespace */
+		if (*buf == '#')
+			break;	/* token starts comment, skip rest of line */
 
-		/* Run `end' over a word, either whitespace separated or quoted */
+		/* find `end' of word, whitespace separated or quoted */
 		if (*buf == '"' || *buf == '\'') {
 			int quote = *buf++;
 			for (end = buf ; *end && *end != quote ; end++)
@@ -199,8 +228,8 @@
 				;
 			BUG_ON(end == buf);
 		}
-		/* Here `buf' is the start of the word, `end' is one past the end */
 
+		/* `buf' is start of word, `end' is one past its end */
 		if (nwords == maxwords)
 			return -EINVAL;	/* ran out of words[] before bytes */
 		if (*end)
@@ -279,6 +308,19 @@
 	return str;
 }
 
+static int check_set(const char **dest, char *src, char *name)
+{
+	int rc = 0;
+
+	if (*dest) {
+		rc = -EINVAL;
+		pr_err("match-spec:%s val:%s overridden by %s",
+			name, *dest, src);
+	}
+	*dest = src;
+	return rc;
+}
+
 /*
  * Parse words[] as a ddebug query specification, which is a series
  * of (keyword, value) pairs chosen from these possibilities:
@@ -290,11 +332,15 @@
  * format <escaped-string-to-find-in-format>
  * line <lineno>
  * line <first-lineno>-<last-lineno> // where either may be empty
+ *
+ * Only 1 of each type is allowed.
+ * Returns 0 on success, <0 on error.
  */
 static int ddebug_parse_query(char *words[], int nwords,
 			       struct ddebug_query *query)
 {
 	unsigned int i;
+	int rc;
 
 	/* check we have an even number of words */
 	if (nwords % 2 != 0)
@@ -303,41 +349,43 @@
 
 	for (i = 0 ; i < nwords ; i += 2) {
 		if (!strcmp(words[i], "func"))
-			query->function = words[i+1];
+			rc = check_set(&query->function, words[i+1], "func");
 		else if (!strcmp(words[i], "file"))
-			query->filename = words[i+1];
+			rc = check_set(&query->filename, words[i+1], "file");
 		else if (!strcmp(words[i], "module"))
-			query->module = words[i+1];
+			rc = check_set(&query->module, words[i+1], "module");
 		else if (!strcmp(words[i], "format"))
-			query->format = unescape(words[i+1]);
+			rc = check_set(&query->format, unescape(words[i+1]),
+				"format");
 		else if (!strcmp(words[i], "line")) {
 			char *first = words[i+1];
 			char *last = strchr(first, '-');
+			if (query->first_lineno || query->last_lineno) {
+				pr_err("match-spec:line given 2 times\n");
+				return -EINVAL;
+			}
 			if (last)
 				*last++ = '\0';
 			if (parse_lineno(first, &query->first_lineno) < 0)
 				return -EINVAL;
-			if (last != NULL) {
+			if (last) {
 				/* range <first>-<last> */
-				if (parse_lineno(last, &query->last_lineno) < 0)
+				if (parse_lineno(last, &query->last_lineno)
+				    < query->first_lineno) {
+					pr_err("last-line < 1st-line\n");
 					return -EINVAL;
+				}
 			} else {
 				query->last_lineno = query->first_lineno;
 			}
 		} else {
-			if (verbose)
-				pr_err("unknown keyword \"%s\"\n", words[i]);
+			pr_err("unknown keyword \"%s\"\n", words[i]);
 			return -EINVAL;
 		}
+		if (rc)
+			return rc;
 	}
-
-	if (verbose)
-		pr_info("q->function=\"%s\" q->filename=\"%s\" "
-			"q->module=\"%s\" q->format=\"%s\" q->lineno=%u-%u\n",
-			query->function, query->filename,
-			query->module, query->format, query->first_lineno,
-			query->last_lineno);
-
+	vpr_info_dq(query, "parsed");
 	return 0;
 }
 
@@ -375,8 +423,6 @@
 		if (i < 0)
 			return -EINVAL;
 	}
-	if (flags == 0)
-		return -EINVAL;
 	if (verbose)
 		pr_info("flags=0x%x\n", flags);
 
@@ -405,7 +451,7 @@
 	unsigned int flags = 0, mask = 0;
 	struct ddebug_query query;
 #define MAXWORDS 9
-	int nwords;
+	int nwords, nfound;
 	char *words[MAXWORDS];
 
 	nwords = ddebug_tokenize(query_string, words, MAXWORDS);
@@ -417,8 +463,47 @@
 		return -EINVAL;
 
 	/* actually go and implement the change */
-	ddebug_change(&query, flags, mask);
-	return 0;
+	nfound = ddebug_change(&query, flags, mask);
+	vpr_info_dq((&query), (nfound) ? "applied" : "no-match");
+
+	return nfound;
+}
+
+/* handle multiple queries in query string, continue on error, return
+   last error or number of matching callsites.  Module name is either
+   in param (for boot arg) or perhaps in query string.
+*/
+static int ddebug_exec_queries(char *query)
+{
+	char *split;
+	int i, errs = 0, exitcode = 0, rc, nfound = 0;
+
+	for (i = 0; query; query = split) {
+		split = strpbrk(query, ";\n");
+		if (split)
+			*split++ = '\0';
+
+		query = skip_spaces(query);
+		if (!query || !*query || *query == '#')
+			continue;
+
+		if (verbose)
+			pr_info("query %d: \"%s\"\n", i, query);
+
+		rc = ddebug_exec_query(query);
+		if (rc < 0) {
+			errs++;
+			exitcode = rc;
+		} else
+			nfound += rc;
+		i++;
+	}
+	pr_info("processed %d queries, with %d matches, %d errs\n",
+		 i, nfound, errs);
+
+	if (exitcode)
+		return exitcode;
+	return nfound;
 }
 
 #define PREFIX_SIZE 64
@@ -452,7 +537,8 @@
 		pos += snprintf(buf + pos, remaining(pos), "%s:",
 					desc->function);
 	if (desc->flags & _DPRINTK_FLAGS_INCL_LINENO)
-		pos += snprintf(buf + pos, remaining(pos), "%d:", desc->lineno);
+		pos += snprintf(buf + pos, remaining(pos), "%d:",
+					desc->lineno);
 	if (pos - pos_after_tid)
 		pos += snprintf(buf + pos, remaining(pos), " ");
 	if (pos >= PREFIX_SIZE)
@@ -527,14 +613,16 @@
 
 #endif
 
-static __initdata char ddebug_setup_string[1024];
+#define DDEBUG_STRING_SIZE 1024
+static __initdata char ddebug_setup_string[DDEBUG_STRING_SIZE];
+
 static __init int ddebug_setup_query(char *str)
 {
-	if (strlen(str) >= 1024) {
+	if (strlen(str) >= DDEBUG_STRING_SIZE) {
 		pr_warn("ddebug boot param string too large\n");
 		return 0;
 	}
-	strcpy(ddebug_setup_string, str);
+	strlcpy(ddebug_setup_string, str, DDEBUG_STRING_SIZE);
 	return 1;
 }
 
@@ -544,25 +632,33 @@
  * File_ops->write method for <debugfs>/dynamic_debug/conrol.  Gathers the
  * command text from userspace, parses and executes it.
  */
+#define USER_BUF_PAGE 4096
 static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
 				  size_t len, loff_t *offp)
 {
-	char tmpbuf[256];
+	char *tmpbuf;
 	int ret;
 
 	if (len == 0)
 		return 0;
-	/* we don't check *offp -- multiple writes() are allowed */
-	if (len > sizeof(tmpbuf)-1)
+	if (len > USER_BUF_PAGE - 1) {
+		pr_warn("expected <%d bytes into control\n", USER_BUF_PAGE);
 		return -E2BIG;
-	if (copy_from_user(tmpbuf, ubuf, len))
+	}
+	tmpbuf = kmalloc(len + 1, GFP_KERNEL);
+	if (!tmpbuf)
+		return -ENOMEM;
+	if (copy_from_user(tmpbuf, ubuf, len)) {
+		kfree(tmpbuf);
 		return -EFAULT;
+	}
 	tmpbuf[len] = '\0';
 	if (verbose)
 		pr_info("read %d bytes from userspace\n", (int)len);
 
-	ret = ddebug_exec_query(tmpbuf);
-	if (ret)
+	ret = ddebug_exec_queries(tmpbuf);
+	kfree(tmpbuf);
+	if (ret < 0)
 		return ret;
 
 	*offp += len;
@@ -668,7 +764,7 @@
 {
 	struct ddebug_iter *iter = m->private;
 	struct _ddebug *dp = p;
-	char flagsbuf[8];
+	char flagsbuf[10];
 
 	if (verbose)
 		pr_info("called m=%p p=%p\n", m, p);
@@ -679,10 +775,10 @@
 		return 0;
 	}
 
-	seq_printf(m, "%s:%u [%s]%s %s \"",
-		   dp->filename, dp->lineno,
-		   iter->table->mod_name, dp->function,
-		   ddebug_describe_flags(dp, flagsbuf, sizeof(flagsbuf)));
+	seq_printf(m, "%s:%u [%s]%s =%s \"",
+		trim_prefix(dp->filename), dp->lineno,
+		iter->table->mod_name, dp->function,
+		ddebug_describe_flags(dp, flagsbuf, sizeof(flagsbuf)));
 	seq_escape(m, dp->format, "\t\r\n\"");
 	seq_puts(m, "\"\n");
 
@@ -708,10 +804,11 @@
 };
 
 /*
- * File_ops->open method for <debugfs>/dynamic_debug/control.  Does the seq_file
- * setup dance, and also creates an iterator to walk the _ddebugs.
- * Note that we create a seq_file always, even for O_WRONLY files
- * where it's not needed, as doing so simplifies the ->release method.
+ * File_ops->open method for <debugfs>/dynamic_debug/control.  Does
+ * the seq_file setup dance, and also creates an iterator to walk the
+ * _ddebugs.  Note that we create a seq_file always, even for O_WRONLY
+ * files where it's not needed, as doing so simplifies the ->release
+ * method.
  */
 static int ddebug_proc_open(struct inode *inode, struct file *file)
 {
@@ -846,33 +943,40 @@
 	int ret = 0;
 	int n = 0;
 
-	if (__start___verbose != __stop___verbose) {
-		iter = __start___verbose;
-		modname = iter->modname;
-		iter_start = iter;
-		for (; iter < __stop___verbose; iter++) {
-			if (strcmp(modname, iter->modname)) {
-				ret = ddebug_add_module(iter_start, n, modname);
-				if (ret)
-					goto out_free;
-				n = 0;
-				modname = iter->modname;
-				iter_start = iter;
-			}
-			n++;
-		}
-		ret = ddebug_add_module(iter_start, n, modname);
+	if (__start___verbose == __stop___verbose) {
+		pr_warn("_ddebug table is empty in a "
+			"CONFIG_DYNAMIC_DEBUG build");
+		return 1;
 	}
+	iter = __start___verbose;
+	modname = iter->modname;
+	iter_start = iter;
+	for (; iter < __stop___verbose; iter++) {
+		if (strcmp(modname, iter->modname)) {
+			ret = ddebug_add_module(iter_start, n, modname);
+			if (ret)
+				goto out_free;
+			n = 0;
+			modname = iter->modname;
+			iter_start = iter;
+		}
+		n++;
+	}
+	ret = ddebug_add_module(iter_start, n, modname);
+	if (ret)
+		goto out_free;
 
 	/* ddebug_query boot param got passed -> set it up */
 	if (ddebug_setup_string[0] != '\0') {
-		ret = ddebug_exec_query(ddebug_setup_string);
-		if (ret)
+		ret = ddebug_exec_queries(ddebug_setup_string);
+		if (ret < 0)
 			pr_warn("Invalid ddebug boot param %s",
 				ddebug_setup_string);
 		else
-			pr_info("ddebug initialized with string %s",
-				ddebug_setup_string);
+			pr_info("%d changes by ddebug_query\n", ret);
+
+		/* keep tables even on ddebug_query parse error */
+		ret = 0;
 	}
 
 out_free:
diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c
index 3d1bdcd..6ab4587 100644
--- a/lib/dynamic_queue_limits.c
+++ b/lib/dynamic_queue_limits.c
@@ -7,6 +7,7 @@
 #include <linux/types.h>
 #include <linux/ctype.h>
 #include <linux/kernel.h>
+#include <linux/jiffies.h>
 #include <linux/dynamic_queue_limits.h>
 
 #define POSDIFF(A, B) ((A) > (B) ? (A) - (B) : 0)
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index e66e9b6..75cbdb5 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -29,16 +29,17 @@
 
 u64 uevent_seqnum;
 char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
-static DEFINE_SPINLOCK(sequence_lock);
 #ifdef CONFIG_NET
 struct uevent_sock {
 	struct list_head list;
 	struct sock *sk;
 };
 static LIST_HEAD(uevent_sock_list);
-static DEFINE_MUTEX(uevent_sock_mutex);
 #endif
 
+/* This lock protects uevent_seqnum and uevent_sock_list */
+static DEFINE_MUTEX(uevent_sock_mutex);
+
 /* the strings here must match the enum in include/linux/kobject.h */
 static const char *kobject_actions[] = {
 	[KOBJ_ADD] =		"add",
@@ -136,7 +137,6 @@
 	struct kobject *top_kobj;
 	struct kset *kset;
 	const struct kset_uevent_ops *uevent_ops;
-	u64 seq;
 	int i = 0;
 	int retval = 0;
 #ifdef CONFIG_NET
@@ -243,17 +243,16 @@
 	else if (action == KOBJ_REMOVE)
 		kobj->state_remove_uevent_sent = 1;
 
+	mutex_lock(&uevent_sock_mutex);
 	/* we will send an event, so request a new sequence number */
-	spin_lock(&sequence_lock);
-	seq = ++uevent_seqnum;
-	spin_unlock(&sequence_lock);
-	retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);
-	if (retval)
+	retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum);
+	if (retval) {
+		mutex_unlock(&uevent_sock_mutex);
 		goto exit;
+	}
 
 #if defined(CONFIG_NET)
 	/* send netlink message */
-	mutex_lock(&uevent_sock_mutex);
 	list_for_each_entry(ue_sk, &uevent_sock_list, list) {
 		struct sock *uevent_sock = ue_sk->sk;
 		struct sk_buff *skb;
@@ -290,8 +289,8 @@
 		} else
 			retval = -ENOMEM;
 	}
-	mutex_unlock(&uevent_sock_mutex);
 #endif
+	mutex_unlock(&uevent_sock_mutex);
 
 	/* call uevent_helper, usually only enabled during early boot */
 	if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index d0e57a3..26c6f4e 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -230,10 +230,30 @@
 	 * the counter to account for memory usage
 	 */
 	struct res_counter res;
-	/*
-	 * the counter to account for mem+swap usage.
-	 */
-	struct res_counter memsw;
+
+	union {
+		/*
+		 * the counter to account for mem+swap usage.
+		 */
+		struct res_counter memsw;
+
+		/*
+		 * rcu_freeing is used only when freeing struct mem_cgroup,
+		 * so put it into a union to avoid wasting more memory.
+		 * It must be disjoint from the css field.  It could be
+		 * in a union with the res field, but res plays a much
+		 * larger part in mem_cgroup life than memsw, and might
+		 * be of interest, even at time of free, when debugging.
+		 * So share rcu_head with the less interesting memsw.
+		 */
+		struct rcu_head rcu_freeing;
+		/*
+		 * But when using vfree(), that cannot be done at
+		 * interrupt time, so we must then queue the work.
+		 */
+		struct work_struct work_freeing;
+	};
+
 	/*
 	 * Per cgroup active and inactive list, similar to the
 	 * per zone LRU lists.
@@ -4582,10 +4602,9 @@
 	return mem_cgroup_sockets_init(cont, ss);
 };
 
-static void kmem_cgroup_destroy(struct cgroup_subsys *ss,
-				struct cgroup *cont)
+static void kmem_cgroup_destroy(struct cgroup *cont)
 {
-	mem_cgroup_sockets_destroy(cont, ss);
+	mem_cgroup_sockets_destroy(cont);
 }
 #else
 static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss)
@@ -4593,8 +4612,7 @@
 	return 0;
 }
 
-static void kmem_cgroup_destroy(struct cgroup_subsys *ss,
-				struct cgroup *cont)
+static void kmem_cgroup_destroy(struct cgroup *cont)
 {
 }
 #endif
@@ -4780,6 +4798,27 @@
 }
 
 /*
+ * Helpers for freeing a vzalloc()ed mem_cgroup by RCU,
+ * but in process context.  The work_freeing structure is overlaid
+ * on the rcu_freeing structure, which itself is overlaid on memsw.
+ */
+static void vfree_work(struct work_struct *work)
+{
+	struct mem_cgroup *memcg;
+
+	memcg = container_of(work, struct mem_cgroup, work_freeing);
+	vfree(memcg);
+}
+static void vfree_rcu(struct rcu_head *rcu_head)
+{
+	struct mem_cgroup *memcg;
+
+	memcg = container_of(rcu_head, struct mem_cgroup, rcu_freeing);
+	INIT_WORK(&memcg->work_freeing, vfree_work);
+	schedule_work(&memcg->work_freeing);
+}
+
+/*
  * At destroying mem_cgroup, references from swap_cgroup can remain.
  * (scanning all at force_empty is too costly...)
  *
@@ -4802,9 +4841,9 @@
 
 	free_percpu(memcg->stat);
 	if (sizeof(struct mem_cgroup) < PAGE_SIZE)
-		kfree(memcg);
+		kfree_rcu(memcg, rcu_freeing);
 	else
-		vfree(memcg);
+		call_rcu(&memcg->rcu_freeing, vfree_rcu);
 }
 
 static void mem_cgroup_get(struct mem_cgroup *memcg)
@@ -4886,7 +4925,7 @@
 }
 
 static struct cgroup_subsys_state * __ref
-mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
+mem_cgroup_create(struct cgroup *cont)
 {
 	struct mem_cgroup *memcg, *parent;
 	long error = -ENOMEM;
@@ -4948,20 +4987,18 @@
 	return ERR_PTR(error);
 }
 
-static int mem_cgroup_pre_destroy(struct cgroup_subsys *ss,
-					struct cgroup *cont)
+static int mem_cgroup_pre_destroy(struct cgroup *cont)
 {
 	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
 
 	return mem_cgroup_force_empty(memcg, false);
 }
 
-static void mem_cgroup_destroy(struct cgroup_subsys *ss,
-				struct cgroup *cont)
+static void mem_cgroup_destroy(struct cgroup *cont)
 {
 	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
 
-	kmem_cgroup_destroy(ss, cont);
+	kmem_cgroup_destroy(cont);
 
 	mem_cgroup_put(memcg);
 }
@@ -5298,9 +5335,8 @@
 	mem_cgroup_end_move(from);
 }
 
-static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
-				struct cgroup *cgroup,
-				struct cgroup_taskset *tset)
+static int mem_cgroup_can_attach(struct cgroup *cgroup,
+				 struct cgroup_taskset *tset)
 {
 	struct task_struct *p = cgroup_taskset_first(tset);
 	int ret = 0;
@@ -5338,9 +5374,8 @@
 	return ret;
 }
 
-static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss,
-				struct cgroup *cgroup,
-				struct cgroup_taskset *tset)
+static void mem_cgroup_cancel_attach(struct cgroup *cgroup,
+				     struct cgroup_taskset *tset)
 {
 	mem_cgroup_clear_mc();
 }
@@ -5455,9 +5490,8 @@
 	up_read(&mm->mmap_sem);
 }
 
-static void mem_cgroup_move_task(struct cgroup_subsys *ss,
-				struct cgroup *cont,
-				struct cgroup_taskset *tset)
+static void mem_cgroup_move_task(struct cgroup *cont,
+				 struct cgroup_taskset *tset)
 {
 	struct task_struct *p = cgroup_taskset_first(tset);
 	struct mm_struct *mm = get_task_mm(p);
@@ -5472,20 +5506,17 @@
 		mem_cgroup_clear_mc();
 }
 #else	/* !CONFIG_MMU */
-static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
-				struct cgroup *cgroup,
-				struct cgroup_taskset *tset)
+static int mem_cgroup_can_attach(struct cgroup *cgroup,
+				 struct cgroup_taskset *tset)
 {
 	return 0;
 }
-static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss,
-				struct cgroup *cgroup,
-				struct cgroup_taskset *tset)
+static void mem_cgroup_cancel_attach(struct cgroup *cgroup,
+				     struct cgroup_taskset *tset)
 {
 }
-static void mem_cgroup_move_task(struct cgroup_subsys *ss,
-				struct cgroup *cont,
-				struct cgroup_taskset *tset)
+static void mem_cgroup_move_task(struct cgroup *cont,
+				 struct cgroup_taskset *tset)
 {
 }
 #endif
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index a2d4f51..7adb03c 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -1157,7 +1157,6 @@
 	if (!rfcomm_tty_driver)
 		return -ENOMEM;
 
-	rfcomm_tty_driver->owner	= THIS_MODULE;
 	rfcomm_tty_driver->driver_name	= "rfcomm";
 	rfcomm_tty_driver->name		= "rfcomm";
 	rfcomm_tty_driver->major	= RFCOMM_TTY_MAJOR;
diff --git a/net/core/dev.c b/net/core/dev.c
index 6ca32f6..6982bfd 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -134,7 +134,7 @@
 #include <linux/inetdevice.h>
 #include <linux/cpu_rmap.h>
 #include <linux/net_tstamp.h>
-#include <linux/jump_label.h>
+#include <linux/static_key.h>
 #include <net/flow_keys.h>
 
 #include "net-sysfs.h"
@@ -1441,11 +1441,11 @@
 }
 EXPORT_SYMBOL(call_netdevice_notifiers);
 
-static struct jump_label_key netstamp_needed __read_mostly;
+static struct static_key netstamp_needed __read_mostly;
 #ifdef HAVE_JUMP_LABEL
-/* We are not allowed to call jump_label_dec() from irq context
+/* We are not allowed to call static_key_slow_dec() from irq context
  * If net_disable_timestamp() is called from irq context, defer the
- * jump_label_dec() calls.
+ * static_key_slow_dec() calls.
  */
 static atomic_t netstamp_needed_deferred;
 #endif
@@ -1457,12 +1457,12 @@
 
 	if (deferred) {
 		while (--deferred)
-			jump_label_dec(&netstamp_needed);
+			static_key_slow_dec(&netstamp_needed);
 		return;
 	}
 #endif
 	WARN_ON(in_interrupt());
-	jump_label_inc(&netstamp_needed);
+	static_key_slow_inc(&netstamp_needed);
 }
 EXPORT_SYMBOL(net_enable_timestamp);
 
@@ -1474,19 +1474,19 @@
 		return;
 	}
 #endif
-	jump_label_dec(&netstamp_needed);
+	static_key_slow_dec(&netstamp_needed);
 }
 EXPORT_SYMBOL(net_disable_timestamp);
 
 static inline void net_timestamp_set(struct sk_buff *skb)
 {
 	skb->tstamp.tv64 = 0;
-	if (static_branch(&netstamp_needed))
+	if (static_key_false(&netstamp_needed))
 		__net_timestamp(skb);
 }
 
 #define net_timestamp_check(COND, SKB)			\
-	if (static_branch(&netstamp_needed)) {		\
+	if (static_key_false(&netstamp_needed)) {		\
 		if ((COND) && !(SKB)->tstamp.tv64)	\
 			__net_timestamp(SKB);		\
 	}						\
@@ -2660,7 +2660,7 @@
 struct rps_sock_flow_table __rcu *rps_sock_flow_table __read_mostly;
 EXPORT_SYMBOL(rps_sock_flow_table);
 
-struct jump_label_key rps_needed __read_mostly;
+struct static_key rps_needed __read_mostly;
 
 static struct rps_dev_flow *
 set_rps_cpu(struct net_device *dev, struct sk_buff *skb,
@@ -2945,7 +2945,7 @@
 
 	trace_netif_rx(skb);
 #ifdef CONFIG_RPS
-	if (static_branch(&rps_needed))	{
+	if (static_key_false(&rps_needed)) {
 		struct rps_dev_flow voidflow, *rflow = &voidflow;
 		int cpu;
 
@@ -3309,7 +3309,7 @@
 		return NET_RX_SUCCESS;
 
 #ifdef CONFIG_RPS
-	if (static_branch(&rps_needed)) {
+	if (static_key_false(&rps_needed)) {
 		struct rps_dev_flow voidflow, *rflow = &voidflow;
 		int cpu, ret;
 
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index a1727cd..4955862 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -608,10 +608,10 @@
 	spin_unlock(&rps_map_lock);
 
 	if (map)
-		jump_label_inc(&rps_needed);
+		static_key_slow_inc(&rps_needed);
 	if (old_map) {
 		kfree_rcu(old_map, rcu);
-		jump_label_dec(&rps_needed);
+		static_key_slow_dec(&rps_needed);
 	}
 	free_cpumask_var(mask);
 	return len;
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c
index 4dacc44..ba6900f 100644
--- a/net/core/netprio_cgroup.c
+++ b/net/core/netprio_cgroup.c
@@ -23,9 +23,8 @@
 #include <net/sock.h>
 #include <net/netprio_cgroup.h>
 
-static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss,
-					       struct cgroup *cgrp);
-static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp);
+static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp);
+static void cgrp_destroy(struct cgroup *cgrp);
 static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp);
 
 struct cgroup_subsys net_prio_subsys = {
@@ -121,8 +120,7 @@
 	rtnl_unlock();
 }
 
-static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss,
-						 struct cgroup *cgrp)
+static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp)
 {
 	struct cgroup_netprio_state *cs;
 	int ret;
@@ -146,7 +144,7 @@
 	return &cs->css;
 }
 
-static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp)
+static void cgrp_destroy(struct cgroup *cgrp)
 {
 	struct cgroup_netprio_state *cs;
 	struct net_device *dev;
diff --git a/net/core/sock.c b/net/core/sock.c
index 02f8dfe..1fb21b5 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -111,7 +111,7 @@
 #include <linux/init.h>
 #include <linux/highmem.h>
 #include <linux/user_namespace.h>
-#include <linux/jump_label.h>
+#include <linux/static_key.h>
 #include <linux/memcontrol.h>
 
 #include <asm/uaccess.h>
@@ -160,19 +160,19 @@
 out:
 	list_for_each_entry_continue_reverse(proto, &proto_list, node)
 		if (proto->destroy_cgroup)
-			proto->destroy_cgroup(cgrp, ss);
+			proto->destroy_cgroup(cgrp);
 	mutex_unlock(&proto_list_mutex);
 	return ret;
 }
 
-void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss)
+void mem_cgroup_sockets_destroy(struct cgroup *cgrp)
 {
 	struct proto *proto;
 
 	mutex_lock(&proto_list_mutex);
 	list_for_each_entry_reverse(proto, &proto_list, node)
 		if (proto->destroy_cgroup)
-			proto->destroy_cgroup(cgrp, ss);
+			proto->destroy_cgroup(cgrp);
 	mutex_unlock(&proto_list_mutex);
 }
 #endif
@@ -184,7 +184,7 @@
 static struct lock_class_key af_family_keys[AF_MAX];
 static struct lock_class_key af_family_slock_keys[AF_MAX];
 
-struct jump_label_key memcg_socket_limit_enabled;
+struct static_key memcg_socket_limit_enabled;
 EXPORT_SYMBOL(memcg_socket_limit_enabled);
 
 /*
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index d05559d..0c28508 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -69,9 +69,9 @@
 		if (sock_table != orig_sock_table) {
 			rcu_assign_pointer(rps_sock_flow_table, sock_table);
 			if (sock_table)
-				jump_label_inc(&rps_needed);
+				static_key_slow_inc(&rps_needed);
 			if (orig_sock_table) {
-				jump_label_dec(&rps_needed);
+				static_key_slow_dec(&rps_needed);
 				synchronize_rcu();
 				vfree(orig_sock_table);
 			}
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 86f3b88..c48adc5 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -1857,11 +1857,6 @@
 	return CIPSO_V4_HDR_LEN + ret_val;
 }
 
-static void opt_kfree_rcu(struct rcu_head *head)
-{
-	kfree(container_of(head, struct ip_options_rcu, rcu));
-}
-
 /**
  * cipso_v4_sock_setattr - Add a CIPSO option to a socket
  * @sk: the socket
@@ -1938,7 +1933,7 @@
 	}
 	rcu_assign_pointer(sk_inet->inet_opt, opt);
 	if (old)
-		call_rcu(&old->rcu, opt_kfree_rcu);
+		kfree_rcu(old, rcu);
 
 	return 0;
 
@@ -2005,7 +2000,7 @@
 	req_inet = inet_rsk(req);
 	opt = xchg(&req_inet->opt, opt);
 	if (opt)
-		call_rcu(&opt->rcu, opt_kfree_rcu);
+		kfree_rcu(opt, rcu);
 
 	return 0;
 
@@ -2075,7 +2070,7 @@
 		 * remove the entire option struct */
 		*opt_ptr = NULL;
 		hdr_delta = opt->opt.optlen;
-		call_rcu(&opt->rcu, opt_kfree_rcu);
+		kfree_rcu(opt, rcu);
 	}
 
 	return hdr_delta;
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 8aa87c1..5343d9a 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -445,11 +445,6 @@
 }
 
 
-static void opt_kfree_rcu(struct rcu_head *head)
-{
-	kfree(container_of(head, struct ip_options_rcu, rcu));
-}
-
 /*
  *	Socket option code for IP. This is the end of the line after any
  *	TCP,UDP etc options on an IP socket.
@@ -525,7 +520,7 @@
 		}
 		rcu_assign_pointer(inet->inet_opt, opt);
 		if (old)
-			call_rcu(&old->rcu, opt_kfree_rcu);
+			kfree_rcu(old, rcu);
 		break;
 	}
 	case IP_PKTINFO:
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 51fdbb4..eab2a7f 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -278,6 +278,7 @@
 	struct rtable *rt;
 	__u8 rcv_wscale;
 	bool ecn_ok = false;
+	struct flowi4 fl4;
 
 	if (!sysctl_tcp_syncookies || !th->ack || th->rst)
 		goto out;
@@ -346,20 +347,16 @@
 	 * hasn't changed since we received the original syn, but I see
 	 * no easy way to do this.
 	 */
-	{
-		struct flowi4 fl4;
-
-		flowi4_init_output(&fl4, 0, sk->sk_mark, RT_CONN_FLAGS(sk),
-				   RT_SCOPE_UNIVERSE, IPPROTO_TCP,
-				   inet_sk_flowi_flags(sk),
-				   (opt && opt->srr) ? opt->faddr : ireq->rmt_addr,
-				   ireq->loc_addr, th->source, th->dest);
-		security_req_classify_flow(req, flowi4_to_flowi(&fl4));
-		rt = ip_route_output_key(sock_net(sk), &fl4);
-		if (IS_ERR(rt)) {
-			reqsk_free(req);
-			goto out;
-		}
+	flowi4_init_output(&fl4, 0, sk->sk_mark, RT_CONN_FLAGS(sk),
+			   RT_SCOPE_UNIVERSE, IPPROTO_TCP,
+			   inet_sk_flowi_flags(sk),
+			   (opt && opt->srr) ? opt->faddr : ireq->rmt_addr,
+			   ireq->loc_addr, th->source, th->dest);
+	security_req_classify_flow(req, flowi4_to_flowi(&fl4));
+	rt = ip_route_output_key(sock_net(sk), &fl4);
+	if (IS_ERR(rt)) {
+		reqsk_free(req);
+		goto out;
 	}
 
 	/* Try to redo what tcp_v4_send_synack did. */
@@ -373,5 +370,10 @@
 	ireq->rcv_wscale  = rcv_wscale;
 
 	ret = get_cookie_sock(sk, skb, req, &rt->dst);
+	/* ip_queue_xmit() depends on our flow being setup
+	 * Normal sockets get it right from inet_csk_route_child_sock()
+	 */
+	if (ret)
+		inet_sk(ret)->cork.fl.u.ip4 = fl4;
 out:	return ret;
 }
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 94d683a..fd54c5f 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1466,9 +1466,13 @@
 		inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen;
 	newinet->inet_id = newtp->write_seq ^ jiffies;
 
-	if (!dst && (dst = inet_csk_route_child_sock(sk, newsk, req)) == NULL)
-		goto put_and_exit;
-
+	if (!dst) {
+		dst = inet_csk_route_child_sock(sk, newsk, req);
+		if (!dst)
+			goto put_and_exit;
+	} else {
+		/* syncookie case : see end of cookie_v4_check() */
+	}
 	sk_setup_caps(newsk, dst);
 
 	tcp_mtup_init(newsk);
diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c
index 4997878..e795272 100644
--- a/net/ipv4/tcp_memcontrol.c
+++ b/net/ipv4/tcp_memcontrol.c
@@ -94,7 +94,7 @@
 }
 EXPORT_SYMBOL(tcp_init_cgroup);
 
-void tcp_destroy_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss)
+void tcp_destroy_cgroup(struct cgroup *cgrp)
 {
 	struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
 	struct cg_proto *cg_proto;
@@ -111,7 +111,7 @@
 	val = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT);
 
 	if (val != RESOURCE_MAX)
-		jump_label_dec(&memcg_socket_limit_enabled);
+		static_key_slow_dec(&memcg_socket_limit_enabled);
 }
 EXPORT_SYMBOL(tcp_destroy_cgroup);
 
@@ -143,9 +143,9 @@
 					     net->ipv4.sysctl_tcp_mem[i]);
 
 	if (val == RESOURCE_MAX && old_lim != RESOURCE_MAX)
-		jump_label_dec(&memcg_socket_limit_enabled);
+		static_key_slow_dec(&memcg_socket_limit_enabled);
 	else if (old_lim == RESOURCE_MAX && val != RESOURCE_MAX)
-		jump_label_inc(&memcg_socket_limit_enabled);
+		static_key_slow_inc(&memcg_socket_limit_enabled);
 
 	return 0;
 }
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index b853f06..16c33e3 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -257,7 +257,6 @@
 
 		if (rt) {
 			dev = rt->dst.dev;
-			dev_hold(dev);
 			dst_release(&rt->dst);
 		}
 	} else
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 8c2e3ab..22b7664 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1077,7 +1077,7 @@
 	struct net *net = dev_net(dev);
 
 	if (unlikely(!idev))
-		return NULL;
+		return ERR_PTR(-ENODEV);
 
 	rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev, 0);
 	if (unlikely(!rt)) {
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index 253695d..6b9d5a0 100644
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -122,7 +122,6 @@
 		return -ENOMEM;
 	}
 
-	driver->owner		= THIS_MODULE;
 	driver->driver_name     = "ircomm";
 	driver->name            = "ircomm";
 	driver->major           = IRCOMM_TTY_MAJOR;
@@ -366,16 +365,12 @@
 static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
 {
 	struct ircomm_tty_cb *self;
-	unsigned int line;
+	unsigned int line = tty->index;
 	unsigned long	flags;
 	int ret;
 
 	IRDA_DEBUG(2, "%s()\n", __func__ );
 
-	line = tty->index;
-	if (line >= IRCOMM_TTY_PORTS)
-		return -ENODEV;
-
 	/* Check if instance already exists */
 	self = hashbin_lock_find(ircomm_tty, line, NULL);
 	if (!self) {
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index edf167e..30420bc 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -413,12 +413,6 @@
 	return NULL;
 }
 
-static void mesh_gate_node_reclaim(struct rcu_head *rp)
-{
-	struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
-	kfree(node);
-}
-
 /**
  * mesh_path_add_gate - add the given mpath to a mesh gate to our path table
  * @mpath: gate path to add to table
@@ -479,7 +473,7 @@
 		if (gate->mpath == mpath) {
 			spin_lock_bh(&tbl->gates_lock);
 			hlist_del_rcu(&gate->list);
-			call_rcu(&gate->rcu, mesh_gate_node_reclaim);
+			kfree_rcu(gate, rcu);
 			spin_unlock_bh(&tbl->gates_lock);
 			mpath->sdata->u.mesh.num_gates--;
 			mpath->is_gate = false;
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index b4e8ff0..e1b7e05 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -56,7 +56,7 @@
 EXPORT_SYMBOL(nf_hooks);
 
 #if defined(CONFIG_JUMP_LABEL)
-struct jump_label_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
+struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
 EXPORT_SYMBOL(nf_hooks_needed);
 #endif
 
@@ -77,7 +77,7 @@
 	list_add_rcu(&reg->list, elem->list.prev);
 	mutex_unlock(&nf_hook_mutex);
 #if defined(CONFIG_JUMP_LABEL)
-	jump_label_inc(&nf_hooks_needed[reg->pf][reg->hooknum]);
+	static_key_slow_inc(&nf_hooks_needed[reg->pf][reg->hooknum]);
 #endif
 	return 0;
 }
@@ -89,7 +89,7 @@
 	list_del_rcu(&reg->list);
 	mutex_unlock(&nf_hook_mutex);
 #if defined(CONFIG_JUMP_LABEL)
-	jump_label_dec(&nf_hooks_needed[reg->pf][reg->hooknum]);
+	static_key_slow_dec(&nf_hooks_needed[reg->pf][reg->hooknum]);
 #endif
 	synchronize_net();
 }
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 1068769..b49da6c 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -943,20 +943,21 @@
 		}
 	}
 
-	if (nf_conntrack_event_report(IPCT_DESTROY, ct,
-				      NETLINK_CB(skb).pid,
-				      nlmsg_report(nlh)) < 0) {
+	if (del_timer(&ct->timeout)) {
+		if (nf_conntrack_event_report(IPCT_DESTROY, ct,
+					      NETLINK_CB(skb).pid,
+					      nlmsg_report(nlh)) < 0) {
+			nf_ct_delete_from_lists(ct);
+			/* we failed to report the event, try later */
+			nf_ct_insert_dying_list(ct);
+			nf_ct_put(ct);
+			return 0;
+		}
+		/* death_by_timeout would report the event again */
+		set_bit(IPS_DYING_BIT, &ct->status);
 		nf_ct_delete_from_lists(ct);
-		/* we failed to report the event, try later */
-		nf_ct_insert_dying_list(ct);
 		nf_ct_put(ct);
-		return 0;
 	}
-
-	/* death_by_timeout would report the event again */
-	set_bit(IPS_DYING_BIT, &ct->status);
-
-	nf_ct_kill(ct);
 	nf_ct_put(ct);
 
 	return 0;
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c
index f84fdc3..1afaa28 100644
--- a/net/sched/cls_cgroup.c
+++ b/net/sched/cls_cgroup.c
@@ -22,9 +22,8 @@
 #include <net/sock.h>
 #include <net/cls_cgroup.h>
 
-static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss,
-					       struct cgroup *cgrp);
-static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp);
+static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp);
+static void cgrp_destroy(struct cgroup *cgrp);
 static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp);
 
 struct cgroup_subsys net_cls_subsys = {
@@ -51,8 +50,7 @@
 			    struct cgroup_cls_state, css);
 }
 
-static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss,
-						 struct cgroup *cgrp)
+static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp)
 {
 	struct cgroup_cls_state *cs;
 
@@ -66,7 +64,7 @@
 	return &cs->css;
 }
 
-static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp)
+static void cgrp_destroy(struct cgroup *cgrp)
 {
 	kfree(cgrp_cls_state(cgrp));
 }
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 60d4718..02a21ab 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -469,11 +469,15 @@
 	if (slot->qlen == 1) {		/* The flow is new */
 		if (q->tail == NULL) {	/* It is the first flow */
 			slot->next = x;
-			q->tail = slot;
 		} else {
 			slot->next = q->tail->next;
 			q->tail->next = x;
 		}
+		/* We put this flow at the end of our flow list.
+		 * This might sound unfair for a new flow to wait after old ones,
+		 * but we could endup servicing new flows only, and freeze old ones.
+		 */
+		q->tail = slot;
 		/* We could use a bigger initial quantum for new flows */
 		slot->allot = q->scaled_quantum;
 	}
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index b89efe6..8e730cc 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -1029,6 +1029,31 @@
 }
 ADD_TO_DEVTABLE("amba", struct amba_id, do_amba_entry);
 
+/* LOOKS like x86cpu:vendor:VVVV:family:FFFF:model:MMMM:feature:*,FEAT,*
+ * All fields are numbers. It would be nicer to use strings for vendor
+ * and feature, but getting those out of the build system here is too
+ * complicated.
+ */
+
+static int do_x86cpu_entry(const char *filename, struct x86_cpu_id *id,
+			   char *alias)
+{
+	id->feature = TO_NATIVE(id->feature);
+	id->family = TO_NATIVE(id->family);
+	id->model = TO_NATIVE(id->model);
+	id->vendor = TO_NATIVE(id->vendor);
+
+	strcpy(alias, "x86cpu:");
+	ADD(alias, "vendor:",  id->vendor != X86_VENDOR_ANY, id->vendor);
+	ADD(alias, ":family:", id->family != X86_FAMILY_ANY, id->family);
+	ADD(alias, ":model:",  id->model  != X86_MODEL_ANY,  id->model);
+	strcat(alias, ":feature:*");
+	if (id->feature != X86_FEATURE_ANY)
+		sprintf(alias + strlen(alias), "%04X*", id->feature);
+	return 1;
+}
+ADD_TO_DEVTABLE("x86cpu", struct x86_cpu_id, do_x86cpu_entry);
+
 /* Does namelen bytes of name exactly match the symbol? */
 static bool sym_is(const char *name, unsigned namelen, const char *symbol)
 {
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index 8b5b5d8..c43a332 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -61,8 +61,8 @@
 
 struct cgroup_subsys devices_subsys;
 
-static int devcgroup_can_attach(struct cgroup_subsys *ss,
-			struct cgroup *new_cgrp, struct cgroup_taskset *set)
+static int devcgroup_can_attach(struct cgroup *new_cgrp,
+				struct cgroup_taskset *set)
 {
 	struct task_struct *task = cgroup_taskset_first(set);
 
@@ -156,8 +156,7 @@
 /*
  * called from kernel/cgroup.c with cgroup_lock() held.
  */
-static struct cgroup_subsys_state *devcgroup_create(struct cgroup_subsys *ss,
-						struct cgroup *cgroup)
+static struct cgroup_subsys_state *devcgroup_create(struct cgroup *cgroup)
 {
 	struct dev_cgroup *dev_cgroup, *parent_dev_cgroup;
 	struct cgroup *parent_cgroup;
@@ -195,8 +194,7 @@
 	return &dev_cgroup->css;
 }
 
-static void devcgroup_destroy(struct cgroup_subsys *ss,
-			struct cgroup *cgroup)
+static void devcgroup_destroy(struct cgroup *cgroup)
 {
 	struct dev_cgroup *dev_cgroup;
 	struct dev_whitelist_item *wh, *tmp;
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 11224ed..146fd61 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -34,21 +34,13 @@
 #include <errno.h>
 #include <arpa/inet.h>
 #include <linux/connector.h>
+#include <linux/hyperv.h>
 #include <linux/netlink.h>
 #include <ifaddrs.h>
 #include <netdb.h>
 #include <syslog.h>
-
-/*
- * KYS: TODO. Need to register these in the kernel.
- *
- * The following definitions are shared with the in-kernel component; do not
- * change any of this without making the corresponding changes in
- * the KVP kernel component.
- */
-#define CN_KVP_IDX		0x9     /* MSFT KVP functionality */
-#define CN_KVP_VAL		0x1 /* This supports queries from the kernel */
-#define CN_KVP_USER_VAL		0x2 /* This supports queries from the user  */
+#include <sys/stat.h>
+#include <fcntl.h>
 
 /*
  * KVP protocol: The user mode component first registers with the
@@ -60,25 +52,8 @@
  * We use this infrastructure for also supporting queries from user mode
  * application for state that may be maintained in the KVP kernel component.
  *
- * XXXKYS: Have a shared header file between the user and kernel (TODO)
  */
 
-enum kvp_op {
-	KVP_REGISTER = 0, /* Register the user mode component*/
-	KVP_KERNEL_GET, /*Kernel is requesting the value for the specified key*/
-	KVP_KERNEL_SET, /*Kernel is providing the value for the specified key*/
-	KVP_USER_GET, /*User is requesting the value for the specified key*/
-	KVP_USER_SET /*User is providing the value for the specified key*/
-};
-
-#define HV_KVP_EXCHANGE_MAX_KEY_SIZE	512
-#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE	2048
-
-struct hv_ku_msg {
-	__u32	kvp_index;
-	__u8  kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */
-	__u8  kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key  value */
-};
 
 enum key_index {
 	FullyQualifiedDomainName = 0,
@@ -93,10 +68,6 @@
 	ProcessorArchitecture
 };
 
-/*
- * End of shared definitions.
- */
-
 static char kvp_send_buffer[4096];
 static char kvp_recv_buffer[4096];
 static struct sockaddr_nl addr;
@@ -109,6 +80,345 @@
 static char *lic_version;
 static struct utsname uts_buf;
 
+
+#define MAX_FILE_NAME 100
+#define ENTRIES_PER_BLOCK 50
+
+struct kvp_record {
+	__u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+	__u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
+};
+
+struct kvp_file_state {
+	int fd;
+	int num_blocks;
+	struct kvp_record *records;
+	int num_records;
+	__u8 fname[MAX_FILE_NAME];
+};
+
+static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
+
+static void kvp_acquire_lock(int pool)
+{
+	struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
+	fl.l_pid = getpid();
+
+	if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
+		syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
+		exit(-1);
+	}
+}
+
+static void kvp_release_lock(int pool)
+{
+	struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
+	fl.l_pid = getpid();
+
+	if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
+		perror("fcntl");
+		syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
+		exit(-1);
+	}
+}
+
+static void kvp_update_file(int pool)
+{
+	FILE *filep;
+	size_t bytes_written;
+
+	/*
+	 * We are going to write our in-memory registry out to
+	 * disk; acquire the lock first.
+	 */
+	kvp_acquire_lock(pool);
+
+	filep = fopen(kvp_file_info[pool].fname, "w");
+	if (!filep) {
+		kvp_release_lock(pool);
+		syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
+		exit(-1);
+	}
+
+	bytes_written = fwrite(kvp_file_info[pool].records,
+				sizeof(struct kvp_record),
+				kvp_file_info[pool].num_records, filep);
+
+	fflush(filep);
+	kvp_release_lock(pool);
+}
+
+static void kvp_update_mem_state(int pool)
+{
+	FILE *filep;
+	size_t records_read = 0;
+	struct kvp_record *record = kvp_file_info[pool].records;
+	struct kvp_record *readp;
+	int num_blocks = kvp_file_info[pool].num_blocks;
+	int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
+
+	kvp_acquire_lock(pool);
+
+	filep = fopen(kvp_file_info[pool].fname, "r");
+	if (!filep) {
+		kvp_release_lock(pool);
+		syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
+		exit(-1);
+	}
+	while (!feof(filep)) {
+		readp = &record[records_read];
+		records_read += fread(readp, sizeof(struct kvp_record),
+					ENTRIES_PER_BLOCK * num_blocks,
+					filep);
+
+		if (!feof(filep)) {
+			/*
+			 * We have more data to read.
+			 */
+			num_blocks++;
+			record = realloc(record, alloc_unit * num_blocks);
+
+			if (record == NULL) {
+				syslog(LOG_ERR, "malloc failed");
+				exit(-1);
+			}
+			continue;
+		}
+		break;
+	}
+
+	kvp_file_info[pool].num_blocks = num_blocks;
+	kvp_file_info[pool].records = record;
+	kvp_file_info[pool].num_records = records_read;
+
+	kvp_release_lock(pool);
+}
+static int kvp_file_init(void)
+{
+	int ret, fd;
+	FILE *filep;
+	size_t records_read;
+	__u8 *fname;
+	struct kvp_record *record;
+	struct kvp_record *readp;
+	int num_blocks;
+	int i;
+	int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
+
+	if (access("/var/opt/hyperv", F_OK)) {
+		if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
+			syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
+			exit(-1);
+		}
+	}
+
+	for (i = 0; i < KVP_POOL_COUNT; i++) {
+		fname = kvp_file_info[i].fname;
+		records_read = 0;
+		num_blocks = 1;
+		sprintf(fname, "/var/opt/hyperv/.kvp_pool_%d", i);
+		fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
+
+		if (fd == -1)
+			return 1;
+
+
+		filep = fopen(fname, "r");
+		if (!filep)
+			return 1;
+
+		record = malloc(alloc_unit * num_blocks);
+		if (record == NULL) {
+			fclose(filep);
+			return 1;
+		}
+		while (!feof(filep)) {
+			readp = &record[records_read];
+			records_read += fread(readp, sizeof(struct kvp_record),
+					ENTRIES_PER_BLOCK,
+					filep);
+
+			if (!feof(filep)) {
+				/*
+				 * We have more data to read.
+				 */
+				num_blocks++;
+				record = realloc(record, alloc_unit *
+						num_blocks);
+				if (record == NULL) {
+					fclose(filep);
+					return 1;
+				}
+				continue;
+			}
+			break;
+		}
+		kvp_file_info[i].fd = fd;
+		kvp_file_info[i].num_blocks = num_blocks;
+		kvp_file_info[i].records = record;
+		kvp_file_info[i].num_records = records_read;
+		fclose(filep);
+
+	}
+
+	return 0;
+}
+
+static int kvp_key_delete(int pool, __u8 *key, int key_size)
+{
+	int i;
+	int j, k;
+	int num_records;
+	struct kvp_record *record;
+
+	/*
+	 * First update the in-memory state.
+	 */
+	kvp_update_mem_state(pool);
+
+	num_records = kvp_file_info[pool].num_records;
+	record = kvp_file_info[pool].records;
+
+	for (i = 0; i < num_records; i++) {
+		if (memcmp(key, record[i].key, key_size))
+			continue;
+		/*
+		 * Found a match; just move the remaining
+		 * entries up.
+		 */
+		if (i == num_records) {
+			kvp_file_info[pool].num_records--;
+			kvp_update_file(pool);
+			return 0;
+		}
+
+		j = i;
+		k = j + 1;
+		for (; k < num_records; k++) {
+			strcpy(record[j].key, record[k].key);
+			strcpy(record[j].value, record[k].value);
+			j++;
+		}
+
+		kvp_file_info[pool].num_records--;
+		kvp_update_file(pool);
+		return 0;
+	}
+	return 1;
+}
+
+static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
+			int value_size)
+{
+	int i;
+	int j, k;
+	int num_records;
+	struct kvp_record *record;
+	int num_blocks;
+
+	if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
+		(value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
+		return 1;
+
+	/*
+	 * First update the in-memory state.
+	 */
+	kvp_update_mem_state(pool);
+
+	num_records = kvp_file_info[pool].num_records;
+	record = kvp_file_info[pool].records;
+	num_blocks = kvp_file_info[pool].num_blocks;
+
+	for (i = 0; i < num_records; i++) {
+		if (memcmp(key, record[i].key, key_size))
+			continue;
+		/*
+		 * Found a match; just update the value -
+		 * this is the modify case.
+		 */
+		memcpy(record[i].value, value, value_size);
+		kvp_update_file(pool);
+		return 0;
+	}
+
+	/*
+	 * Need to add a new entry;
+	 */
+	if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
+		/* Need to allocate a larger array for reg entries. */
+		record = realloc(record, sizeof(struct kvp_record) *
+			 ENTRIES_PER_BLOCK * (num_blocks + 1));
+
+		if (record == NULL)
+			return 1;
+		kvp_file_info[pool].num_blocks++;
+
+	}
+	memcpy(record[i].value, value, value_size);
+	memcpy(record[i].key, key, key_size);
+	kvp_file_info[pool].records = record;
+	kvp_file_info[pool].num_records++;
+	kvp_update_file(pool);
+	return 0;
+}
+
+static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
+			int value_size)
+{
+	int i;
+	int num_records;
+	struct kvp_record *record;
+
+	if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
+		(value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
+		return 1;
+
+	/*
+	 * First update the in-memory state.
+	 */
+	kvp_update_mem_state(pool);
+
+	num_records = kvp_file_info[pool].num_records;
+	record = kvp_file_info[pool].records;
+
+	for (i = 0; i < num_records; i++) {
+		if (memcmp(key, record[i].key, key_size))
+			continue;
+		/*
+		 * Found a match; just copy the value out.
+		 */
+		memcpy(value, record[i].value, value_size);
+		return 0;
+	}
+
+	return 1;
+}
+
+static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
+				__u8 *value, int value_size)
+{
+	struct kvp_record *record;
+
+	/*
+	 * First update our in-memory database.
+	 */
+	kvp_update_mem_state(pool);
+	record = kvp_file_info[pool].records;
+
+	if (index >= kvp_file_info[pool].num_records) {
+		/*
+		 * This is an invalid index; terminate enumeration;
+		 * - a NULL value will do the trick.
+		 */
+		strcpy(value, "");
+		return;
+	}
+
+	memcpy(key, record[index].key, key_size);
+	memcpy(value, record[index].value, value_size);
+}
+
+
 void kvp_get_os_info(void)
 {
 	FILE	*file;
@@ -332,7 +642,7 @@
 	struct pollfd pfd;
 	struct nlmsghdr *incoming_msg;
 	struct cn_msg	*incoming_cn_msg;
-	struct hv_ku_msg *hv_msg;
+	struct hv_kvp_msg *hv_msg;
 	char	*p;
 	char	*key_value;
 	char	*key_name;
@@ -345,6 +655,11 @@
 	 */
 	kvp_get_os_info();
 
+	if (kvp_file_init()) {
+		syslog(LOG_ERR, "Failed to initialize the pools");
+		exit(-1);
+	}
+
 	fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
 	if (fd < 0) {
 		syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
@@ -370,9 +685,11 @@
 	message = (struct cn_msg *)kvp_send_buffer;
 	message->id.idx = CN_KVP_IDX;
 	message->id.val = CN_KVP_VAL;
-	message->seq = KVP_REGISTER;
+
+	hv_msg = (struct hv_kvp_msg *)message->data;
+	hv_msg->kvp_hdr.operation = KVP_OP_REGISTER;
 	message->ack = 0;
-	message->len = 0;
+	message->len = sizeof(struct hv_kvp_msg);
 
 	len = netlink_send(fd, message);
 	if (len < 0) {
@@ -398,14 +715,15 @@
 
 		incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
 		incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
+		hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
 
-		switch (incoming_cn_msg->seq) {
-		case KVP_REGISTER:
+		switch (hv_msg->kvp_hdr.operation) {
+		case KVP_OP_REGISTER:
 			/*
 			 * Driver is registering with us; stash away the version
 			 * information.
 			 */
-			p = (char *)incoming_cn_msg->data;
+			p = (char *)hv_msg->body.kvp_register.version;
 			lic_version = malloc(strlen(p) + 1);
 			if (lic_version) {
 				strcpy(lic_version, p);
@@ -416,17 +734,65 @@
 			}
 			continue;
 
-		case KVP_KERNEL_GET:
+		/*
+		 * The current protocol with the kernel component uses a
+		 * NULL key name to pass an error condition.
+		 * For the SET, GET and DELETE operations,
+		 * use the existing protocol to pass back error.
+		 */
+
+		case KVP_OP_SET:
+			if (kvp_key_add_or_modify(hv_msg->kvp_hdr.pool,
+					hv_msg->body.kvp_set.data.key,
+					hv_msg->body.kvp_set.data.key_size,
+					hv_msg->body.kvp_set.data.value,
+					hv_msg->body.kvp_set.data.value_size))
+				strcpy(hv_msg->body.kvp_set.data.key, "");
 			break;
+
+		case KVP_OP_GET:
+			if (kvp_get_value(hv_msg->kvp_hdr.pool,
+					hv_msg->body.kvp_set.data.key,
+					hv_msg->body.kvp_set.data.key_size,
+					hv_msg->body.kvp_set.data.value,
+					hv_msg->body.kvp_set.data.value_size))
+				strcpy(hv_msg->body.kvp_set.data.key, "");
+			break;
+
+		case KVP_OP_DELETE:
+			if (kvp_key_delete(hv_msg->kvp_hdr.pool,
+					hv_msg->body.kvp_delete.key,
+					hv_msg->body.kvp_delete.key_size))
+				strcpy(hv_msg->body.kvp_delete.key, "");
+			break;
+
 		default:
-			continue;
+			break;
 		}
 
-		hv_msg = (struct hv_ku_msg *)incoming_cn_msg->data;
-		key_name = (char *)hv_msg->kvp_key;
-		key_value = (char *)hv_msg->kvp_value;
+		if (hv_msg->kvp_hdr.operation != KVP_OP_ENUMERATE)
+			goto kvp_done;
 
-		switch (hv_msg->kvp_index) {
+		/*
+		 * If the pool is KVP_POOL_AUTO, dynamically generate
+		 * both the key and the value; if not read from the
+		 * appropriate pool.
+		 */
+		if (hv_msg->kvp_hdr.pool != KVP_POOL_AUTO) {
+			kvp_pool_enumerate(hv_msg->kvp_hdr.pool,
+					hv_msg->body.kvp_enum_data.index,
+					hv_msg->body.kvp_enum_data.data.key,
+					HV_KVP_EXCHANGE_MAX_KEY_SIZE,
+					hv_msg->body.kvp_enum_data.data.value,
+					HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
+			goto kvp_done;
+		}
+
+		hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
+		key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
+		key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
+
+		switch (hv_msg->body.kvp_enum_data.index) {
 		case FullyQualifiedDomainName:
 			kvp_get_domain_name(key_value,
 					HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
@@ -483,12 +849,12 @@
 		 * already in the receive buffer. Update the cn_msg header to
 		 * reflect the key value that has been added to the message
 		 */
+kvp_done:
 
 		incoming_cn_msg->id.idx = CN_KVP_IDX;
 		incoming_cn_msg->id.val = CN_KVP_VAL;
-		incoming_cn_msg->seq = KVP_USER_SET;
 		incoming_cn_msg->ack = 0;
-		incoming_cn_msg->len = sizeof(struct hv_ku_msg);
+		incoming_cn_msg->len = sizeof(struct hv_kvp_msg);
 
 		len = netlink_send(fd, incoming_cn_msg);
 		if (len < 0) {
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
index 4626a39..ca600e0 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -1,3 +1,10 @@
+OUTPUT := ./
+ifeq ("$(origin O)", "command line")
+  ifneq ($(O),)
+	OUTPUT := $(O)/
+  endif
+endif
+
 MAN1_TXT= \
 	$(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
 		$(wildcard perf-*.txt)) \
@@ -6,10 +13,11 @@
 MAN7_TXT=
 
 MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT)
-MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
-MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT))
+_MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
+_MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT))
 
-DOC_HTML=$(MAN_HTML)
+MAN_XML=$(addprefix $(OUTPUT),$(_MAN_XML))
+MAN_HTML=$(addprefix $(OUTPUT),$(_MAN_HTML))
 
 ARTICLES =
 # with their own formatting rules.
@@ -18,11 +26,17 @@
 SP_ARTICLES += $(API_DOCS)
 SP_ARTICLES += technical/api-index
 
-DOC_HTML += $(patsubst %,%.html,$(ARTICLES) $(SP_ARTICLES))
+_DOC_HTML = $(_MAN_HTML)
+_DOC_HTML+=$(patsubst %,%.html,$(ARTICLES) $(SP_ARTICLES))
+DOC_HTML=$(addprefix $(OUTPUT),$(_DOC_HTML))
 
-DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT))
-DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT))
-DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
+_DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT))
+_DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT))
+_DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
+
+DOC_MAN1=$(addprefix $(OUTPUT),$(_DOC_MAN1))
+DOC_MAN5=$(addprefix $(OUTPUT),$(_DOC_MAN5))
+DOC_MAN7=$(addprefix $(OUTPUT),$(_DOC_MAN7))
 
 # Make the path relative to DESTDIR, not prefix
 ifndef DESTDIR
@@ -150,9 +164,9 @@
 man5: $(DOC_MAN5)
 man7: $(DOC_MAN7)
 
-info: perf.info perfman.info
+info: $(OUTPUT)perf.info $(OUTPUT)perfman.info
 
-pdf: user-manual.pdf
+pdf: $(OUTPUT)user-manual.pdf
 
 install: install-man
 
@@ -166,7 +180,7 @@
 
 install-info: info
 	$(INSTALL) -d -m 755 $(DESTDIR)$(infodir)
-	$(INSTALL) -m 644 perf.info perfman.info $(DESTDIR)$(infodir)
+	$(INSTALL) -m 644 $(OUTPUT)perf.info $(OUTPUT)perfman.info $(DESTDIR)$(infodir)
 	if test -r $(DESTDIR)$(infodir)/dir; then \
 	  $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perf.info ;\
 	  $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perfman.info ;\
@@ -176,7 +190,7 @@
 
 install-pdf: pdf
 	$(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir)
-	$(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir)
+	$(INSTALL) -m 644 $(OUTPUT)user-manual.pdf $(DESTDIR)$(pdfdir)
 
 #install-html: html
 #	'$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
@@ -189,14 +203,14 @@
 #
 # Determine "include::" file references in asciidoc files.
 #
-doc.dep : $(wildcard *.txt) build-docdep.perl
+$(OUTPUT)doc.dep : $(wildcard *.txt) build-docdep.perl
 	$(QUIET_GEN)$(RM) $@+ $@ && \
 	$(PERL_PATH) ./build-docdep.perl >$@+ $(QUIET_STDERR) && \
 	mv $@+ $@
 
--include doc.dep
+-include $(OUPTUT)doc.dep
 
-cmds_txt = cmds-ancillaryinterrogators.txt \
+_cmds_txt = cmds-ancillaryinterrogators.txt \
 	cmds-ancillarymanipulators.txt \
 	cmds-mainporcelain.txt \
 	cmds-plumbinginterrogators.txt \
@@ -205,32 +219,36 @@
 	cmds-synchelpers.txt \
 	cmds-purehelpers.txt \
 	cmds-foreignscminterface.txt
+cmds_txt=$(addprefix $(OUTPUT),$(_cmds_txt))
 
-$(cmds_txt): cmd-list.made
+$(cmds_txt): $(OUTPUT)cmd-list.made
 
-cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
+$(OUTPUT)cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
 	$(QUIET_GEN)$(RM) $@ && \
 	$(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \
 	date >$@
 
 clean:
-	$(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7
-	$(RM) *.texi *.texi+ *.texi++ perf.info perfman.info
-	$(RM) howto-index.txt howto/*.html doc.dep
-	$(RM) technical/api-*.html technical/api-index.txt
-	$(RM) $(cmds_txt) *.made
+	$(RM) $(MAN_XML) $(addsuffix +,$(MAN_XML))
+	$(RM) $(MAN_HTML) $(addsuffix +,$(MAN_HTML))
+	$(RM) $(DOC_HTML) $(DOC_MAN1) $(DOC_MAN5) $(DOC_MAN7)
+	$(RM) $(OUTPUT)*.texi $(OUTPUT)*.texi+ $(OUTPUT)*.texi++
+	$(RM) $(OUTPUT)perf.info $(OUTPUT)perfman.info
+	$(RM) $(OUTPUT)howto-index.txt $(OUTPUT)howto/*.html $(OUTPUT)doc.dep
+	$(RM) $(OUTPUT)technical/api-*.html $(OUTPUT)technical/api-index.txt
+	$(RM) $(cmds_txt) $(OUTPUT)*.made
 
-$(MAN_HTML): %.html : %.txt
+$(MAN_HTML): $(OUTPUT)%.html : %.txt
 	$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
 	$(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \
 		$(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \
 	mv $@+ $@
 
-%.1 %.5 %.7 : %.xml
+$(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : $(OUTPUT)%.xml
 	$(QUIET_XMLTO)$(RM) $@ && \
-	xmlto -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
+	xmlto -o $(OUTPUT) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
 
-%.xml : %.txt
+$(OUTPUT)%.xml : %.txt
 	$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
 	$(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
 		$(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \
@@ -239,25 +257,25 @@
 XSLT = docbook.xsl
 XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css
 
-user-manual.html: user-manual.xml
+$(OUTPUT)user-manual.html: $(OUTPUT)user-manual.xml
 	$(QUIET_XSLTPROC)xsltproc $(XSLTOPTS) -o $@ $(XSLT) $<
 
-perf.info: user-manual.texi
-	$(QUIET_MAKEINFO)$(MAKEINFO) --no-split -o $@ user-manual.texi
+$(OUTPUT)perf.info: $(OUTPUT)user-manual.texi
+	$(QUIET_MAKEINFO)$(MAKEINFO) --no-split -o $@ $(OUTPUT)user-manual.texi
 
-user-manual.texi: user-manual.xml
+$(OUTPUT)user-manual.texi: $(OUTPUT)user-manual.xml
 	$(QUIET_DB2TEXI)$(RM) $@+ $@ && \
-	$(DOCBOOK2X_TEXI) user-manual.xml --encoding=UTF-8 --to-stdout >$@++ && \
+	$(DOCBOOK2X_TEXI) $(OUTPUT)user-manual.xml --encoding=UTF-8 --to-stdout >$@++ && \
 	$(PERL_PATH) fix-texi.perl <$@++ >$@+ && \
 	rm $@++ && \
 	mv $@+ $@
 
-user-manual.pdf: user-manual.xml
+$(OUTPUT)user-manual.pdf: $(OUTPUT)user-manual.xml
 	$(QUIET_DBLATEX)$(RM) $@+ $@ && \
 	$(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $< && \
 	mv $@+ $@
 
-perfman.texi: $(MAN_XML) cat-texi.perl
+$(OUTPUT)perfman.texi: $(MAN_XML) cat-texi.perl
 	$(QUIET_DB2TEXI)$(RM) $@+ $@ && \
 	($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --encoding=UTF-8 \
 		--to-stdout $(xml) &&) true) > $@++ && \
@@ -265,7 +283,7 @@
 	rm $@++ && \
 	mv $@+ $@
 
-perfman.info: perfman.texi
+$(OUTPUT)perfman.info: $(OUTPUT)perfman.texi
 	$(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $*.texi
 
 $(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml
diff --git a/tools/perf/Documentation/perf-lock.txt b/tools/perf/Documentation/perf-lock.txt
index d6b2a4f..c7f5f55 100644
--- a/tools/perf/Documentation/perf-lock.txt
+++ b/tools/perf/Documentation/perf-lock.txt
@@ -8,7 +8,7 @@
 SYNOPSIS
 --------
 [verse]
-'perf lock' {record|report|trace}
+'perf lock' {record|report|script|info}
 
 DESCRIPTION
 -----------
@@ -20,10 +20,13 @@
   produces the file "perf.data" which contains tracing
   results of lock events.
 
-  'perf lock trace' shows raw lock events.
-
   'perf lock report' reports statistical data.
 
+  'perf lock script' shows raw lock events.
+
+  'perf lock info' shows metadata like threads or addresses
+  of lock instances.
+
 COMMON OPTIONS
 --------------
 
@@ -47,6 +50,17 @@
         Sorting key. Possible values: acquired (default), contended,
         wait_total, wait_max, wait_min.
 
+INFO OPTIONS
+------------
+
+-t::
+--threads::
+	dump thread list in perf.data
+
+-m::
+--map::
+	dump map of lock instances (address:name table)
+
 SEE ALSO
 --------
 linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 2937f7e..a1386b2 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -52,11 +52,15 @@
 
 -p::
 --pid=::
-	Record events on existing process ID.
+	Record events on existing process ID (comma separated list).
 
 -t::
 --tid=::
-        Record events on existing thread ID.
+        Record events on existing thread ID (comma separated list).
+
+-u::
+--uid=::
+        Record events in threads owned by uid. Name or number.
 
 -r::
 --realtime=::
@@ -148,6 +152,36 @@
 corresponding events, i.e., they always refer to events defined earlier on the command
 line.
 
+-b::
+--branch-any::
+Enable taken branch stack sampling. Any type of taken branch may be sampled.
+This is a shortcut for --branch-filter any. See --branch-filter for more infos.
+
+-j::
+--branch-filter::
+Enable taken branch stack sampling. Each sample captures a series of consecutive
+taken branches. The number of branches captured with each sample depends on the
+underlying hardware, the type of branches of interest, and the executed code.
+It is possible to select the types of branches captured by enabling filters. The
+following filters are defined:
+
+        - any:  any type of branches
+        - any_call: any function call or system call
+        - any_ret: any function return or system call return
+        - any_ind: any indirect branch
+        - u:  only when the branch target is at the user level
+        - k: only when the branch target is in the kernel
+        - hv: only when the target is at the hypervisor level
+
++
+The option requires at least one branch type among any, any_call, any_ret, ind_call.
+The privilege levels may be ommitted, in which case, the privilege levels of the associated
+event are applied to the branch filter. Both kernel (k) and hypervisor (hv) privilege
+levels are subject to permissions.  When sampling on multiple events, branch stack sampling
+is enabled for all the sampling events. The sampled branch type is the same for all events.
+The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k
+Note that this feature may not be available on all processors.
+
 SEE ALSO
 --------
 linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 9b430e9..87feeee 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -153,6 +153,16 @@
 	information which may be very large and thus may clutter the display.
 	It currently includes: cpu and numa topology of the host system.
 
+-b::
+--branch-stack::
+	Use the addresses of sampled taken branches instead of the instruction
+	address to build the histograms. To generate meaningful output, the
+	perf.data file must have been obtained using perf record -b or
+	perf record --branch-filter xxx where xxx is a branch filter option.
+	perf report is able to auto-detect whether a perf.data file contains
+	branch stacks and it will automatically switch to the branch view mode,
+	unless --no-branch-stack is used.
+
 SEE ALSO
 --------
 linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 2f6cef4..e9cbfcd 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -115,7 +115,7 @@
 -f::
 --fields::
         Comma separated list of fields to print. Options are:
-        comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr.
+        comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff.
         Field list can be prepended with the type, trace, sw or hw,
         to indicate to which event type the field list applies.
         e.g., -f sw:comm,tid,time,ip,sym  and -f trace:time,cpu,trace
@@ -200,6 +200,9 @@
 	It currently includes: cpu and numa topology of the host system.
 	It can only be used with the perf script report mode.
 
+--show-kernel-path::
+	Try to resolve the path of [kernel.kallsyms]
+
 SEE ALSO
 --------
 linkperf:perf-record[1], linkperf:perf-script-perl[1],
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 8966b9a..2fa173b 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -35,11 +35,11 @@
         child tasks do not inherit counters
 -p::
 --pid=<pid>::
-        stat events on existing process id
+        stat events on existing process id (comma separated list)
 
 -t::
 --tid=<tid>::
-        stat events on existing thread id
+        stat events on existing thread id (comma separated list)
 
 
 -a::
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index b1a5bbb..4a5680c 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -72,11 +72,15 @@
 
 -p <pid>::
 --pid=<pid>::
-	Profile events on existing Process ID.
+	Profile events on existing Process ID (comma separated list).
 
 -t <tid>::
 --tid=<tid>::
-        Profile events on existing thread ID.
+        Profile events on existing thread ID (comma separated list).
+
+-u::
+--uid=::
+        Record events in threads owned by uid. Name or number.
 
 -r <priority>::
 --realtime=<priority>::
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 1078c5f..5476bc0 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -9,6 +9,7 @@
 include/linux/swab.h
 arch/*/include/asm/unistd*.h
 arch/*/lib/memcpy*.S
+arch/*/lib/memset*.S
 include/linux/poison.h
 include/linux/magic.h
 include/linux/hw_breakpoint.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 7c12650..74fd7f8 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -15,6 +15,16 @@
 
 # Define V to have a more verbose compile.
 #
+# Define O to save output files in a separate directory.
+#
+# Define ARCH as name of target architecture if you want cross-builds.
+#
+# Define CROSS_COMPILE as prefix name of compiler if you want cross-builds.
+#
+# Define NO_LIBPERL to disable perl script extension.
+#
+# Define NO_LIBPYTHON to disable python script extension.
+#
 # Define PYTHON to point to the python binary if the default
 # `python' is not correct; for example: PYTHON=python2
 #
@@ -32,6 +42,10 @@
 # Define NO_DWARF if you do not want debug-info analysis feature at all.
 #
 # Define WERROR=0 to disable treating any warnings as errors.
+#
+# Define NO_NEWT if you do not want TUI support.
+#
+# Define NO_DEMANGLE if you do not want C++ symbol demangling.
 
 $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
 	@$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
@@ -61,7 +75,7 @@
 	ifeq (${IS_X86_64}, 1)
 		RAW_ARCH := x86_64
 		ARCH_CFLAGS := -DARCH_X86_64
-		ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S
+		ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
 	endif
 endif
 
@@ -183,7 +197,10 @@
 grep-libs = $(filter -l%,$(1))
 strip-libs = $(filter-out -l%,$(1))
 
-$(OUTPUT)python/perf.so: $(PYRF_OBJS)
+PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
+PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py
+
+$(OUTPUT)python/perf.so: $(PYRF_OBJS) $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
 	$(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \
 	  --quiet build_ext; \
 	mkdir -p $(OUTPUT)python && \
@@ -249,6 +266,8 @@
 LIB_H += util/include/dwarf-regs.h
 LIB_H += util/include/asm/dwarf2.h
 LIB_H += util/include/asm/cpufeature.h
+LIB_H += util/include/asm/unistd_32.h
+LIB_H += util/include/asm/unistd_64.h
 LIB_H += perf.h
 LIB_H += util/annotate.h
 LIB_H += util/cache.h
@@ -256,6 +275,7 @@
 LIB_H += util/build-id.h
 LIB_H += util/debug.h
 LIB_H += util/debugfs.h
+LIB_H += util/sysfs.h
 LIB_H += util/event.h
 LIB_H += util/evsel.h
 LIB_H += util/evlist.h
@@ -302,6 +322,7 @@
 LIB_OBJS += $(OUTPUT)util/config.o
 LIB_OBJS += $(OUTPUT)util/ctype.o
 LIB_OBJS += $(OUTPUT)util/debugfs.o
+LIB_OBJS += $(OUTPUT)util/sysfs.o
 LIB_OBJS += $(OUTPUT)util/environment.o
 LIB_OBJS += $(OUTPUT)util/event.o
 LIB_OBJS += $(OUTPUT)util/evlist.o
@@ -359,8 +380,10 @@
 BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
 ifeq ($(RAW_ARCH),x86_64)
 BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
+BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o
 endif
 BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
+BUILTIN_OBJS += $(OUTPUT)bench/mem-memset.o
 
 BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
 BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
@@ -792,7 +815,6 @@
 	@echo '  quick-install-html	- install the html documentation quickly'
 	@echo ''
 	@echo 'Perf maintainer targets:'
-	@echo '  distclean		- alias to clean'
 	@echo '  clean			- clean all binary objects and build output'
 
 doc:
diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
index eba80c2..2f7073d 100644
--- a/tools/perf/arch/powerpc/util/header.c
+++ b/tools/perf/arch/powerpc/util/header.c
@@ -25,7 +25,7 @@
 
 	pvr = mfspr(SPRN_PVR);
 
-	nb = snprintf(buffer, sz, "%lu,%lu$", PVR_VER(pvr), PVR_REV(pvr));
+	nb = scnprintf(buffer, sz, "%lu,%lu$", PVR_VER(pvr), PVR_REV(pvr));
 
 	/* look for end marker to ensure the entire data fit */
 	if (strchr(buffer, '$')) {
diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c
index f940060..146d12a 100644
--- a/tools/perf/arch/x86/util/header.c
+++ b/tools/perf/arch/x86/util/header.c
@@ -48,7 +48,7 @@
 		if (family >= 0x6)
 			model += ((a >> 16) & 0xf) << 4;
 	}
-	nb = snprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step);
+	nb = scnprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step);
 
 	/* look for end marker to ensure the entire data fit */
 	if (strchr(buffer, '$')) {
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
index f7781c6..a09bece 100644
--- a/tools/perf/bench/bench.h
+++ b/tools/perf/bench/bench.h
@@ -4,6 +4,7 @@
 extern int bench_sched_messaging(int argc, const char **argv, const char *prefix);
 extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
 extern int bench_mem_memcpy(int argc, const char **argv, const char *prefix __used);
+extern int bench_mem_memset(int argc, const char **argv, const char *prefix);
 
 #define BENCH_FORMAT_DEFAULT_STR	"default"
 #define BENCH_FORMAT_DEFAULT		0
diff --git a/tools/perf/bench/mem-memcpy-x86-64-asm-def.h b/tools/perf/bench/mem-memcpy-x86-64-asm-def.h
index d588b87..d66ab79 100644
--- a/tools/perf/bench/mem-memcpy-x86-64-asm-def.h
+++ b/tools/perf/bench/mem-memcpy-x86-64-asm-def.h
@@ -2,3 +2,11 @@
 MEMCPY_FN(__memcpy,
 	"x86-64-unrolled",
 	"unrolled memcpy() in arch/x86/lib/memcpy_64.S")
+
+MEMCPY_FN(memcpy_c,
+	"x86-64-movsq",
+	"movsq-based memcpy() in arch/x86/lib/memcpy_64.S")
+
+MEMCPY_FN(memcpy_c_e,
+	"x86-64-movsb",
+	"movsb-based memcpy() in arch/x86/lib/memcpy_64.S")
diff --git a/tools/perf/bench/mem-memcpy-x86-64-asm.S b/tools/perf/bench/mem-memcpy-x86-64-asm.S
index 185a96d..fcd9cf0 100644
--- a/tools/perf/bench/mem-memcpy-x86-64-asm.S
+++ b/tools/perf/bench/mem-memcpy-x86-64-asm.S
@@ -1,4 +1,8 @@
-
+#define memcpy MEMCPY /* don't hide glibc's memcpy() */
+#define altinstr_replacement text
+#define globl p2align 4; .globl
+#define Lmemcpy_c globl memcpy_c; memcpy_c
+#define Lmemcpy_c_e globl memcpy_c_e; memcpy_c_e
 #include "../../../arch/x86/lib/memcpy_64.S"
 /*
  * We need to provide note.GNU-stack section, saying that we want
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
index db82021..7155722 100644
--- a/tools/perf/bench/mem-memcpy.c
+++ b/tools/perf/bench/mem-memcpy.c
@@ -5,7 +5,6 @@
  *
  * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
  */
-#include <ctype.h>
 
 #include "../perf.h"
 #include "../util/util.h"
@@ -24,6 +23,7 @@
 
 static const char	*length_str	= "1MB";
 static const char	*routine	= "default";
+static int		iterations	= 1;
 static bool		use_clock;
 static int		clock_fd;
 static bool		only_prefault;
@@ -35,6 +35,8 @@
 		    "available unit: B, MB, GB (upper and lower)"),
 	OPT_STRING('r', "routine", &routine, "default",
 		    "Specify routine to copy"),
+	OPT_INTEGER('i', "iterations", &iterations,
+		    "repeat memcpy() invocation this number of times"),
 	OPT_BOOLEAN('c', "clock", &use_clock,
 		    "Use CPU clock for measuring"),
 	OPT_BOOLEAN('o', "only-prefault", &only_prefault,
@@ -121,6 +123,7 @@
 {
 	u64 clock_start = 0ULL, clock_end = 0ULL;
 	void *src = NULL, *dst = NULL;
+	int i;
 
 	alloc_mem(&src, &dst, len);
 
@@ -128,7 +131,8 @@
 		fn(dst, src, len);
 
 	clock_start = get_clock();
-	fn(dst, src, len);
+	for (i = 0; i < iterations; ++i)
+		fn(dst, src, len);
 	clock_end = get_clock();
 
 	free(src);
@@ -140,6 +144,7 @@
 {
 	struct timeval tv_start, tv_end, tv_diff;
 	void *src = NULL, *dst = NULL;
+	int i;
 
 	alloc_mem(&src, &dst, len);
 
@@ -147,7 +152,8 @@
 		fn(dst, src, len);
 
 	BUG_ON(gettimeofday(&tv_start, NULL));
-	fn(dst, src, len);
+	for (i = 0; i < iterations; ++i)
+		fn(dst, src, len);
 	BUG_ON(gettimeofday(&tv_end, NULL));
 
 	timersub(&tv_end, &tv_start, &tv_diff);
diff --git a/tools/perf/bench/mem-memset-arch.h b/tools/perf/bench/mem-memset-arch.h
new file mode 100644
index 0000000..a040fa7
--- /dev/null
+++ b/tools/perf/bench/mem-memset-arch.h
@@ -0,0 +1,12 @@
+
+#ifdef ARCH_X86_64
+
+#define MEMSET_FN(fn, name, desc)		\
+	extern void *fn(void *, int, size_t);
+
+#include "mem-memset-x86-64-asm-def.h"
+
+#undef MEMSET_FN
+
+#endif
+
diff --git a/tools/perf/bench/mem-memset-x86-64-asm-def.h b/tools/perf/bench/mem-memset-x86-64-asm-def.h
new file mode 100644
index 0000000..a71dff97
--- /dev/null
+++ b/tools/perf/bench/mem-memset-x86-64-asm-def.h
@@ -0,0 +1,12 @@
+
+MEMSET_FN(__memset,
+	"x86-64-unrolled",
+	"unrolled memset() in arch/x86/lib/memset_64.S")
+
+MEMSET_FN(memset_c,
+	"x86-64-stosq",
+	"movsq-based memset() in arch/x86/lib/memset_64.S")
+
+MEMSET_FN(memset_c_e,
+	"x86-64-stosb",
+	"movsb-based memset() in arch/x86/lib/memset_64.S")
diff --git a/tools/perf/bench/mem-memset-x86-64-asm.S b/tools/perf/bench/mem-memset-x86-64-asm.S
new file mode 100644
index 0000000..9e5af89
--- /dev/null
+++ b/tools/perf/bench/mem-memset-x86-64-asm.S
@@ -0,0 +1,13 @@
+#define memset MEMSET /* don't hide glibc's memset() */
+#define altinstr_replacement text
+#define globl p2align 4; .globl
+#define Lmemset_c globl memset_c; memset_c
+#define Lmemset_c_e globl memset_c_e; memset_c_e
+#include "../../../arch/x86/lib/memset_64.S"
+
+/*
+ * We need to provide note.GNU-stack section, saying that we want
+ * NOT executable stack. Otherwise the final linking will assume that
+ * the ELF stack should not be restricted at all and set it RWX.
+ */
+.section .note.GNU-stack,"",@progbits
diff --git a/tools/perf/bench/mem-memset.c b/tools/perf/bench/mem-memset.c
new file mode 100644
index 0000000..e907918
--- /dev/null
+++ b/tools/perf/bench/mem-memset.c
@@ -0,0 +1,297 @@
+/*
+ * mem-memset.c
+ *
+ * memset: Simple memory set in various ways
+ *
+ * Trivial clone of mem-memcpy.c.
+ */
+
+#include "../perf.h"
+#include "../util/util.h"
+#include "../util/parse-options.h"
+#include "../util/header.h"
+#include "bench.h"
+#include "mem-memset-arch.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#define K 1024
+
+static const char	*length_str	= "1MB";
+static const char	*routine	= "default";
+static int		iterations	= 1;
+static bool		use_clock;
+static int		clock_fd;
+static bool		only_prefault;
+static bool		no_prefault;
+
+static const struct option options[] = {
+	OPT_STRING('l', "length", &length_str, "1MB",
+		    "Specify length of memory to copy. "
+		    "available unit: B, MB, GB (upper and lower)"),
+	OPT_STRING('r', "routine", &routine, "default",
+		    "Specify routine to copy"),
+	OPT_INTEGER('i', "iterations", &iterations,
+		    "repeat memset() invocation this number of times"),
+	OPT_BOOLEAN('c', "clock", &use_clock,
+		    "Use CPU clock for measuring"),
+	OPT_BOOLEAN('o', "only-prefault", &only_prefault,
+		    "Show only the result with page faults before memset()"),
+	OPT_BOOLEAN('n', "no-prefault", &no_prefault,
+		    "Show only the result without page faults before memset()"),
+	OPT_END()
+};
+
+typedef void *(*memset_t)(void *, int, size_t);
+
+struct routine {
+	const char *name;
+	const char *desc;
+	memset_t fn;
+};
+
+static const struct routine routines[] = {
+	{ "default",
+	  "Default memset() provided by glibc",
+	  memset },
+#ifdef ARCH_X86_64
+
+#define MEMSET_FN(fn, name, desc) { name, desc, fn },
+#include "mem-memset-x86-64-asm-def.h"
+#undef MEMSET_FN
+
+#endif
+
+	{ NULL,
+	  NULL,
+	  NULL   }
+};
+
+static const char * const bench_mem_memset_usage[] = {
+	"perf bench mem memset <options>",
+	NULL
+};
+
+static struct perf_event_attr clock_attr = {
+	.type		= PERF_TYPE_HARDWARE,
+	.config		= PERF_COUNT_HW_CPU_CYCLES
+};
+
+static void init_clock(void)
+{
+	clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0);
+
+	if (clock_fd < 0 && errno == ENOSYS)
+		die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
+	else
+		BUG_ON(clock_fd < 0);
+}
+
+static u64 get_clock(void)
+{
+	int ret;
+	u64 clk;
+
+	ret = read(clock_fd, &clk, sizeof(u64));
+	BUG_ON(ret != sizeof(u64));
+
+	return clk;
+}
+
+static double timeval2double(struct timeval *ts)
+{
+	return (double)ts->tv_sec +
+		(double)ts->tv_usec / (double)1000000;
+}
+
+static void alloc_mem(void **dst, size_t length)
+{
+	*dst = zalloc(length);
+	if (!dst)
+		die("memory allocation failed - maybe length is too large?\n");
+}
+
+static u64 do_memset_clock(memset_t fn, size_t len, bool prefault)
+{
+	u64 clock_start = 0ULL, clock_end = 0ULL;
+	void *dst = NULL;
+	int i;
+
+	alloc_mem(&dst, len);
+
+	if (prefault)
+		fn(dst, -1, len);
+
+	clock_start = get_clock();
+	for (i = 0; i < iterations; ++i)
+		fn(dst, i, len);
+	clock_end = get_clock();
+
+	free(dst);
+	return clock_end - clock_start;
+}
+
+static double do_memset_gettimeofday(memset_t fn, size_t len, bool prefault)
+{
+	struct timeval tv_start, tv_end, tv_diff;
+	void *dst = NULL;
+	int i;
+
+	alloc_mem(&dst, len);
+
+	if (prefault)
+		fn(dst, -1, len);
+
+	BUG_ON(gettimeofday(&tv_start, NULL));
+	for (i = 0; i < iterations; ++i)
+		fn(dst, i, len);
+	BUG_ON(gettimeofday(&tv_end, NULL));
+
+	timersub(&tv_end, &tv_start, &tv_diff);
+
+	free(dst);
+	return (double)((double)len / timeval2double(&tv_diff));
+}
+
+#define pf (no_prefault ? 0 : 1)
+
+#define print_bps(x) do {					\
+		if (x < K)					\
+			printf(" %14lf B/Sec", x);		\
+		else if (x < K * K)				\
+			printf(" %14lfd KB/Sec", x / K);	\
+		else if (x < K * K * K)				\
+			printf(" %14lf MB/Sec", x / K / K);	\
+		else						\
+			printf(" %14lf GB/Sec", x / K / K / K); \
+	} while (0)
+
+int bench_mem_memset(int argc, const char **argv,
+		     const char *prefix __used)
+{
+	int i;
+	size_t len;
+	double result_bps[2];
+	u64 result_clock[2];
+
+	argc = parse_options(argc, argv, options,
+			     bench_mem_memset_usage, 0);
+
+	if (use_clock)
+		init_clock();
+
+	len = (size_t)perf_atoll((char *)length_str);
+
+	result_clock[0] = result_clock[1] = 0ULL;
+	result_bps[0] = result_bps[1] = 0.0;
+
+	if ((s64)len <= 0) {
+		fprintf(stderr, "Invalid length:%s\n", length_str);
+		return 1;
+	}
+
+	/* same to without specifying either of prefault and no-prefault */
+	if (only_prefault && no_prefault)
+		only_prefault = no_prefault = false;
+
+	for (i = 0; routines[i].name; i++) {
+		if (!strcmp(routines[i].name, routine))
+			break;
+	}
+	if (!routines[i].name) {
+		printf("Unknown routine:%s\n", routine);
+		printf("Available routines...\n");
+		for (i = 0; routines[i].name; i++) {
+			printf("\t%s ... %s\n",
+			       routines[i].name, routines[i].desc);
+		}
+		return 1;
+	}
+
+	if (bench_format == BENCH_FORMAT_DEFAULT)
+		printf("# Copying %s Bytes ...\n\n", length_str);
+
+	if (!only_prefault && !no_prefault) {
+		/* show both of results */
+		if (use_clock) {
+			result_clock[0] =
+				do_memset_clock(routines[i].fn, len, false);
+			result_clock[1] =
+				do_memset_clock(routines[i].fn, len, true);
+		} else {
+			result_bps[0] =
+				do_memset_gettimeofday(routines[i].fn,
+						len, false);
+			result_bps[1] =
+				do_memset_gettimeofday(routines[i].fn,
+						len, true);
+		}
+	} else {
+		if (use_clock) {
+			result_clock[pf] =
+				do_memset_clock(routines[i].fn,
+						len, only_prefault);
+		} else {
+			result_bps[pf] =
+				do_memset_gettimeofday(routines[i].fn,
+						len, only_prefault);
+		}
+	}
+
+	switch (bench_format) {
+	case BENCH_FORMAT_DEFAULT:
+		if (!only_prefault && !no_prefault) {
+			if (use_clock) {
+				printf(" %14lf Clock/Byte\n",
+					(double)result_clock[0]
+					/ (double)len);
+				printf(" %14lf Clock/Byte (with prefault)\n ",
+					(double)result_clock[1]
+					/ (double)len);
+			} else {
+				print_bps(result_bps[0]);
+				printf("\n");
+				print_bps(result_bps[1]);
+				printf(" (with prefault)\n");
+			}
+		} else {
+			if (use_clock) {
+				printf(" %14lf Clock/Byte",
+					(double)result_clock[pf]
+					/ (double)len);
+			} else
+				print_bps(result_bps[pf]);
+
+			printf("%s\n", only_prefault ? " (with prefault)" : "");
+		}
+		break;
+	case BENCH_FORMAT_SIMPLE:
+		if (!only_prefault && !no_prefault) {
+			if (use_clock) {
+				printf("%lf %lf\n",
+					(double)result_clock[0] / (double)len,
+					(double)result_clock[1] / (double)len);
+			} else {
+				printf("%lf %lf\n",
+					result_bps[0], result_bps[1]);
+			}
+		} else {
+			if (use_clock) {
+				printf("%lf\n", (double)result_clock[pf]
+					/ (double)len);
+			} else
+				printf("%lf\n", result_bps[pf]);
+		}
+		break;
+	default:
+		/* reaching this means there's some disaster: */
+		die("unknown format: %d\n", bench_format);
+		break;
+	}
+
+	return 0;
+}
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index fcb9626..b0e74ab 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -52,6 +52,9 @@
 	{ "memcpy",
 	  "Simple memory copy in various ways",
 	  bench_mem_memcpy },
+	{ "memset",
+	  "Simple memory set in various ways",
+	  bench_mem_memset },
 	suite_all,
 	{ NULL,
 	  NULL,
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 2296c39..12c8148 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -922,12 +922,12 @@
 	OPT_BOOLEAN('t', "threads", &info_threads,
 		    "dump thread list in perf.data"),
 	OPT_BOOLEAN('m', "map", &info_map,
-		    "map of lock instances (name:address table)"),
+		    "map of lock instances (address:name table)"),
 	OPT_END()
 };
 
 static const char * const lock_usage[] = {
-	"perf lock [<options>] {record|trace|report}",
+	"perf lock [<options>] {record|report|script|info}",
 	NULL
 };
 
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index fb85661..4935c09 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -58,7 +58,7 @@
 	struct perf_probe_event events[MAX_PROBES];
 	struct strlist *dellist;
 	struct line_range line_range;
-	const char *target_module;
+	const char *target;
 	int max_probe_points;
 	struct strfilter *filter;
 } params;
@@ -246,7 +246,7 @@
 		   "file", "vmlinux pathname"),
 	OPT_STRING('s', "source", &symbol_conf.source_prefix,
 		   "directory", "path to kernel source"),
-	OPT_STRING('m', "module", &params.target_module,
+	OPT_STRING('m', "module", &params.target,
 		   "modname|path",
 		   "target module name (for online) or path (for offline)"),
 #endif
@@ -333,7 +333,7 @@
 		if (!params.filter)
 			params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
 						       NULL);
-		ret = show_available_funcs(params.target_module,
+		ret = show_available_funcs(params.target,
 					   params.filter);
 		strfilter__delete(params.filter);
 		if (ret < 0)
@@ -354,7 +354,7 @@
 			usage_with_options(probe_usage, options);
 		}
 
-		ret = show_line_range(&params.line_range, params.target_module);
+		ret = show_line_range(&params.line_range, params.target);
 		if (ret < 0)
 			pr_err("  Error: Failed to show lines. (%d)\n", ret);
 		return ret;
@@ -371,7 +371,7 @@
 
 		ret = show_available_vars(params.events, params.nevents,
 					  params.max_probe_points,
-					  params.target_module,
+					  params.target,
 					  params.filter,
 					  params.show_ext_vars);
 		strfilter__delete(params.filter);
@@ -393,7 +393,7 @@
 	if (params.nevents) {
 		ret = add_perf_probe_events(params.events, params.nevents,
 					    params.max_probe_points,
-					    params.target_module,
+					    params.target,
 					    params.force_add);
 		if (ret < 0) {
 			pr_err("  Error: Failed to add events. (%d)\n", ret);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 227b6ae..be4e1ee 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -44,6 +44,7 @@
 	struct perf_evlist	*evlist;
 	struct perf_session	*session;
 	const char		*progname;
+	const char		*uid_str;
 	int			output;
 	unsigned int		page_size;
 	int			realtime_prio;
@@ -208,7 +209,7 @@
 		if (opts->exclude_guest_missing)
 			attr->exclude_guest = attr->exclude_host = 0;
 retry_sample_id:
-		attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
+		attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
 try_again:
 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
 				     opts->group, group_fd) < 0) {
@@ -227,11 +228,11 @@
 						 "guest or host samples.\n");
 					opts->exclude_guest_missing = true;
 					goto fallback_missing_features;
-				} else if (opts->sample_id_all_avail) {
+				} else if (!opts->sample_id_all_missing) {
 					/*
 					 * Old kernel, no attr->sample_id_type_all field
 					 */
-					opts->sample_id_all_avail = false;
+					opts->sample_id_all_missing = true;
 					if (!opts->sample_time && !opts->raw_samples && !time_needed)
 						attr->sample_type &= ~PERF_SAMPLE_TIME;
 
@@ -396,7 +397,7 @@
 {
 	struct stat st;
 	int flags;
-	int err, output;
+	int err, output, feat;
 	unsigned long waking = 0;
 	const bool forks = argc > 0;
 	struct machine *machine;
@@ -463,8 +464,17 @@
 
 	rec->session = session;
 
-	if (!rec->no_buildid)
-		perf_header__set_feat(&session->header, HEADER_BUILD_ID);
+	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
+		perf_header__set_feat(&session->header, feat);
+
+	if (rec->no_buildid)
+		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
+
+	if (!have_tracepoints(&evsel_list->entries))
+		perf_header__clear_feat(&session->header, HEADER_TRACE_INFO);
+
+	if (!rec->opts.branch_stack)
+		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
 
 	if (!rec->file_new) {
 		err = perf_session__read_header(session, output);
@@ -472,22 +482,6 @@
 			goto out_delete_session;
 	}
 
-	if (have_tracepoints(&evsel_list->entries))
-		perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
-
-	perf_header__set_feat(&session->header, HEADER_HOSTNAME);
-	perf_header__set_feat(&session->header, HEADER_OSRELEASE);
-	perf_header__set_feat(&session->header, HEADER_ARCH);
-	perf_header__set_feat(&session->header, HEADER_CPUDESC);
-	perf_header__set_feat(&session->header, HEADER_NRCPUS);
-	perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
-	perf_header__set_feat(&session->header, HEADER_CMDLINE);
-	perf_header__set_feat(&session->header, HEADER_VERSION);
-	perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
-	perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
-	perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
-	perf_header__set_feat(&session->header, HEADER_CPUID);
-
 	if (forks) {
 		err = perf_evlist__prepare_workload(evsel_list, opts, argv);
 		if (err < 0) {
@@ -647,6 +641,90 @@
 	return err;
 }
 
+#define BRANCH_OPT(n, m) \
+	{ .name = n, .mode = (m) }
+
+#define BRANCH_END { .name = NULL }
+
+struct branch_mode {
+	const char *name;
+	int mode;
+};
+
+static const struct branch_mode branch_modes[] = {
+	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
+	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
+	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
+	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
+	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
+	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
+	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
+	BRANCH_END
+};
+
+static int
+parse_branch_stack(const struct option *opt, const char *str, int unset)
+{
+#define ONLY_PLM \
+	(PERF_SAMPLE_BRANCH_USER	|\
+	 PERF_SAMPLE_BRANCH_KERNEL	|\
+	 PERF_SAMPLE_BRANCH_HV)
+
+	uint64_t *mode = (uint64_t *)opt->value;
+	const struct branch_mode *br;
+	char *s, *os = NULL, *p;
+	int ret = -1;
+
+	if (unset)
+		return 0;
+
+	/*
+	 * cannot set it twice, -b + --branch-filter for instance
+	 */
+	if (*mode)
+		return -1;
+
+	/* str may be NULL in case no arg is passed to -b */
+	if (str) {
+		/* because str is read-only */
+		s = os = strdup(str);
+		if (!s)
+			return -1;
+
+		for (;;) {
+			p = strchr(s, ',');
+			if (p)
+				*p = '\0';
+
+			for (br = branch_modes; br->name; br++) {
+				if (!strcasecmp(s, br->name))
+					break;
+			}
+			if (!br->name) {
+				ui__warning("unknown branch filter %s,"
+					    " check man page\n", s);
+				goto error;
+			}
+
+			*mode |= br->mode;
+
+			if (!p)
+				break;
+
+			s = p + 1;
+		}
+	}
+	ret = 0;
+
+	/* default to any branch */
+	if ((*mode & ~ONLY_PLM) == 0) {
+		*mode = PERF_SAMPLE_BRANCH_ANY;
+	}
+error:
+	free(os);
+	return ret;
+}
+
 static const char * const record_usage[] = {
 	"perf record [<options>] [<command>]",
 	"perf record [<options>] -- <command> [<options>]",
@@ -665,13 +743,10 @@
  */
 static struct perf_record record = {
 	.opts = {
-		.target_pid	     = -1,
-		.target_tid	     = -1,
 		.mmap_pages	     = UINT_MAX,
 		.user_freq	     = UINT_MAX,
 		.user_interval	     = ULLONG_MAX,
 		.freq		     = 1000,
-		.sample_id_all_avail = true,
 	},
 	.write_mode = WRITE_FORCE,
 	.file_new   = true,
@@ -690,9 +765,9 @@
 		     parse_events_option),
 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
 		     "event filter", parse_filter),
-	OPT_INTEGER('p', "pid", &record.opts.target_pid,
+	OPT_STRING('p', "pid", &record.opts.target_pid, "pid",
 		    "record events on existing process id"),
-	OPT_INTEGER('t', "tid", &record.opts.target_tid,
+	OPT_STRING('t', "tid", &record.opts.target_tid, "tid",
 		    "record events on existing thread id"),
 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
 		    "collect data with this RT SCHED_FIFO priority"),
@@ -738,6 +813,15 @@
 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
 		     "monitor event in cgroup name only",
 		     parse_cgroups),
+	OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"),
+
+	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
+		     "branch any", "sample any taken branches",
+		     parse_branch_stack),
+
+	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
+		     "branch filter mask", "branch stack filter modes",
+		     parse_branch_stack),
 	OPT_END()
 };
 
@@ -758,8 +842,8 @@
 
 	argc = parse_options(argc, argv, record_options, record_usage,
 			    PARSE_OPT_STOP_AT_NON_OPTION);
-	if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
-		!rec->opts.system_wide && !rec->opts.cpu_list)
+	if (!argc && !rec->opts.target_pid && !rec->opts.target_tid &&
+		!rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
 		usage_with_options(record_usage, record_options);
 
 	if (rec->force && rec->append_file) {
@@ -799,11 +883,17 @@
 		goto out_symbol_exit;
 	}
 
-	if (rec->opts.target_pid != -1)
+	rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid,
+					 rec->opts.target_pid);
+	if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1)
+		goto out_free_fd;
+
+	if (rec->opts.target_pid)
 		rec->opts.target_tid = rec->opts.target_pid;
 
 	if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
-				     rec->opts.target_tid, rec->opts.cpu_list) < 0)
+				     rec->opts.target_tid, rec->opts.uid,
+				     rec->opts.cpu_list) < 0)
 		usage_with_options(record_usage, record_options);
 
 	list_for_each_entry(pos, &evsel_list->entries, node) {
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 25d34d4..8e91c6e 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -53,6 +53,82 @@
 	DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
 };
 
+static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
+					struct addr_location *al,
+					struct perf_sample *sample,
+					struct perf_evsel *evsel,
+				      struct machine *machine)
+{
+	struct perf_report *rep = container_of(tool, struct perf_report, tool);
+	struct symbol *parent = NULL;
+	int err = 0;
+	unsigned i;
+	struct hist_entry *he;
+	struct branch_info *bi, *bx;
+
+	if ((sort__has_parent || symbol_conf.use_callchain)
+	    && sample->callchain) {
+		err = machine__resolve_callchain(machine, evsel, al->thread,
+						 sample->callchain, &parent);
+		if (err)
+			return err;
+	}
+
+	bi = machine__resolve_bstack(machine, al->thread,
+				     sample->branch_stack);
+	if (!bi)
+		return -ENOMEM;
+
+	for (i = 0; i < sample->branch_stack->nr; i++) {
+		if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
+			continue;
+		/*
+		 * The report shows the percentage of total branches captured
+		 * and not events sampled. Thus we use a pseudo period of 1.
+		 */
+		he = __hists__add_branch_entry(&evsel->hists, al, parent,
+				&bi[i], 1);
+		if (he) {
+			struct annotation *notes;
+			err = -ENOMEM;
+			bx = he->branch_info;
+			if (bx->from.sym && use_browser > 0) {
+				notes = symbol__annotation(bx->from.sym);
+				if (!notes->src
+				    && symbol__alloc_hist(bx->from.sym) < 0)
+					goto out;
+
+				err = symbol__inc_addr_samples(bx->from.sym,
+							       bx->from.map,
+							       evsel->idx,
+							       bx->from.al_addr);
+				if (err)
+					goto out;
+			}
+
+			if (bx->to.sym && use_browser > 0) {
+				notes = symbol__annotation(bx->to.sym);
+				if (!notes->src
+				    && symbol__alloc_hist(bx->to.sym) < 0)
+					goto out;
+
+				err = symbol__inc_addr_samples(bx->to.sym,
+							       bx->to.map,
+							       evsel->idx,
+							       bx->to.al_addr);
+				if (err)
+					goto out;
+			}
+			evsel->hists.stats.total_period += 1;
+			hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
+			err = 0;
+		} else
+			return -ENOMEM;
+	}
+out:
+	return err;
+}
+
 static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
 				      struct addr_location *al,
 				      struct perf_sample *sample,
@@ -126,14 +202,21 @@
 	if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
 		return 0;
 
-	if (al.map != NULL)
-		al.map->dso->hit = 1;
+	if (sort__branch_mode == 1) {
+		if (perf_report__add_branch_hist_entry(tool, &al, sample,
+						       evsel, machine)) {
+			pr_debug("problem adding lbr entry, skipping event\n");
+			return -1;
+		}
+	} else {
+		if (al.map != NULL)
+			al.map->dso->hit = 1;
 
-	if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) {
-		pr_debug("problem incrementing symbol period, skipping event\n");
-		return -1;
+		if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) {
+			pr_debug("problem incrementing symbol period, skipping event\n");
+			return -1;
+		}
 	}
-
 	return 0;
 }
 
@@ -188,6 +271,15 @@
 			}
 	}
 
+	if (sort__branch_mode == 1) {
+		if (!(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) {
+			fprintf(stderr, "selected -b but no branch data."
+					" Did you call perf record without"
+					" -b?\n");
+			return -1;
+		}
+	}
+
 	return 0;
 }
 
@@ -246,7 +338,7 @@
 {
 	int ret = -EINVAL;
 	u64 nr_samples;
-	struct perf_session *session;
+	struct perf_session *session = rep->session;
 	struct perf_evsel *pos;
 	struct map *kernel_map;
 	struct kmap *kernel_kmap;
@@ -254,13 +346,6 @@
 
 	signal(SIGINT, sig_handler);
 
-	session = perf_session__new(rep->input_name, O_RDONLY,
-				    rep->force, false, &rep->tool);
-	if (session == NULL)
-		return -ENOMEM;
-
-	rep->session = session;
-
 	if (rep->cpu_list) {
 		ret = perf_session__cpu_bitmap(session, rep->cpu_list,
 					       rep->cpu_bitmap);
@@ -427,9 +512,19 @@
 	return 0;
 }
 
+static int
+parse_branch_mode(const struct option *opt __used, const char *str __used, int unset)
+{
+	sort__branch_mode = !unset;
+	return 0;
+}
+
 int cmd_report(int argc, const char **argv, const char *prefix __used)
 {
+	struct perf_session *session;
 	struct stat st;
+	bool has_br_stack = false;
+	int ret = -1;
 	char callchain_default_opt[] = "fractal,0.5,callee";
 	const char * const report_usage[] = {
 		"perf report [<options>]",
@@ -477,7 +572,8 @@
 	OPT_BOOLEAN(0, "stdio", &report.use_stdio,
 		    "Use the stdio interface"),
 	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
-		   "sort by key(s): pid, comm, dso, symbol, parent"),
+		   "sort by key(s): pid, comm, dso, symbol, parent, dso_to,"
+		   " dso_from, symbol_to, symbol_from, mispredict"),
 	OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
 		    "Show sample percentage for different cpu modes"),
 	OPT_STRING('p', "parent", &parent_pattern, "regex",
@@ -517,6 +613,8 @@
 		   "Specify disassembler style (e.g. -M intel for intel syntax)"),
 	OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
 		    "Show a column with the sum of periods"),
+	OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "",
+		    "use branch records for histogram filling", parse_branch_mode),
 	OPT_END()
 	};
 
@@ -536,11 +634,36 @@
 		else
 			report.input_name = "perf.data";
 	}
+	session = perf_session__new(report.input_name, O_RDONLY,
+				    report.force, false, &report.tool);
+	if (session == NULL)
+		return -ENOMEM;
 
-	if (strcmp(report.input_name, "-") != 0)
+	report.session = session;
+
+	has_br_stack = perf_header__has_feat(&session->header,
+					     HEADER_BRANCH_STACK);
+
+	if (sort__branch_mode == -1 && has_br_stack)
+		sort__branch_mode = 1;
+
+	/* sort__branch_mode could be 0 if --no-branch-stack */
+	if (sort__branch_mode == 1) {
+		/*
+		 * if no sort_order is provided, then specify
+		 * branch-mode specific order
+		 */
+		if (sort_order == default_sort_order)
+			sort_order = "comm,dso_from,symbol_from,"
+				     "dso_to,symbol_to";
+
+	}
+
+	if (strcmp(report.input_name, "-") != 0) {
 		setup_browser(true);
-	else
+	} else {
 		use_browser = 0;
+	}
 
 	/*
 	 * Only in the newt browser we are doing integrated annotation,
@@ -568,13 +691,13 @@
 	}
 
 	if (symbol__init() < 0)
-		return -1;
+		goto error;
 
 	setup_sorting(report_usage, options);
 
 	if (parent_pattern != default_parent_pattern) {
 		if (sort_dimension__add("parent") < 0)
-			return -1;
+			goto error;
 
 		/*
 		 * Only show the parent fields if we explicitly
@@ -592,9 +715,20 @@
 	if (argc)
 		usage_with_options(report_usage, options);
 
-	sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
 	sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
-	sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
 
-	return __cmd_report(&report);
+	if (sort__branch_mode == 1) {
+		sort_entry__setup_elide(&sort_dso_from, symbol_conf.dso_from_list, "dso_from", stdout);
+		sort_entry__setup_elide(&sort_dso_to, symbol_conf.dso_to_list, "dso_to", stdout);
+		sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout);
+		sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout);
+	} else {
+		sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
+		sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
+	}
+
+	ret = __cmd_report(&report);
+error:
+	perf_session__delete(session);
+	return ret;
 }
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index bb68ddf..d4ce733 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -40,6 +40,7 @@
 	PERF_OUTPUT_SYM             = 1U << 8,
 	PERF_OUTPUT_DSO             = 1U << 9,
 	PERF_OUTPUT_ADDR            = 1U << 10,
+	PERF_OUTPUT_SYMOFFSET       = 1U << 11,
 };
 
 struct output_option {
@@ -57,6 +58,7 @@
 	{.str = "sym",   .field = PERF_OUTPUT_SYM},
 	{.str = "dso",   .field = PERF_OUTPUT_DSO},
 	{.str = "addr",  .field = PERF_OUTPUT_ADDR},
+	{.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET},
 };
 
 /* default set to maintain compatibility with current format */
@@ -193,6 +195,11 @@
 		       "to symbols.\n");
 		return -EINVAL;
 	}
+	if (PRINT_FIELD(SYMOFFSET) && !PRINT_FIELD(SYM)) {
+		pr_err("Display of offsets requested but symbol is not"
+		       "selected.\n");
+		return -EINVAL;
+	}
 	if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
 		pr_err("Display of DSO requested but neither sample IP nor "
 			   "sample address\nis selected. Hence, no addresses to convert "
@@ -300,10 +307,17 @@
 		} else
 			evname = __event_name(attr->type, attr->config);
 
-		printf("%s: ", evname ? evname : "(unknown)");
+		printf("%s: ", evname ? evname : "[unknown]");
 	}
 }
 
+static bool is_bts_event(struct perf_event_attr *attr)
+{
+	return ((attr->type == PERF_TYPE_HARDWARE) &&
+		(attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
+		(attr->sample_period == 1));
+}
+
 static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
 {
 	if ((attr->type == PERF_TYPE_SOFTWARE) &&
@@ -312,6 +326,9 @@
 	     (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)))
 		return true;
 
+	if (is_bts_event(attr))
+		return true;
+
 	return false;
 }
 
@@ -323,7 +340,6 @@
 {
 	struct addr_location al;
 	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
-	const char *symname, *dsoname;
 
 	printf("%16" PRIx64, sample->addr);
 
@@ -343,24 +359,48 @@
 		al.sym = map__find_symbol(al.map, al.addr, NULL);
 
 	if (PRINT_FIELD(SYM)) {
-		if (al.sym && al.sym->name)
-			symname = al.sym->name;
+		printf(" ");
+		if (PRINT_FIELD(SYMOFFSET))
+			symbol__fprintf_symname_offs(al.sym, &al, stdout);
 		else
-			symname = "";
-
-		printf(" %16s", symname);
+			symbol__fprintf_symname(al.sym, stdout);
 	}
 
 	if (PRINT_FIELD(DSO)) {
-		if (al.map && al.map->dso && al.map->dso->name)
-			dsoname = al.map->dso->name;
-		else
-			dsoname = "";
-
-		printf(" (%s)", dsoname);
+		printf(" (");
+		map__fprintf_dsoname(al.map, stdout);
+		printf(")");
 	}
 }
 
+static void print_sample_bts(union perf_event *event,
+			     struct perf_sample *sample,
+			     struct perf_evsel *evsel,
+			     struct machine *machine,
+			     struct thread *thread)
+{
+	struct perf_event_attr *attr = &evsel->attr;
+
+	/* print branch_from information */
+	if (PRINT_FIELD(IP)) {
+		if (!symbol_conf.use_callchain)
+			printf(" ");
+		else
+			printf("\n");
+		perf_event__print_ip(event, sample, machine, evsel,
+				     PRINT_FIELD(SYM), PRINT_FIELD(DSO),
+				     PRINT_FIELD(SYMOFFSET));
+	}
+
+	printf(" => ");
+
+	/* print branch_to information */
+	if (PRINT_FIELD(ADDR))
+		print_sample_addr(event, sample, machine, thread, attr);
+
+	printf("\n");
+}
+
 static void process_event(union perf_event *event __unused,
 			  struct perf_sample *sample,
 			  struct perf_evsel *evsel,
@@ -374,6 +414,11 @@
 
 	print_sample_start(sample, thread, attr);
 
+	if (is_bts_event(attr)) {
+		print_sample_bts(event, sample, evsel, machine, thread);
+		return;
+	}
+
 	if (PRINT_FIELD(TRACE))
 		print_trace_event(sample->cpu, sample->raw_data,
 				  sample->raw_size);
@@ -387,7 +432,8 @@
 		else
 			printf("\n");
 		perf_event__print_ip(event, sample, machine, evsel,
-				     PRINT_FIELD(SYM), PRINT_FIELD(DSO));
+				     PRINT_FIELD(SYM), PRINT_FIELD(DSO),
+				     PRINT_FIELD(SYMOFFSET));
 	}
 
 	printf("\n");
@@ -1097,7 +1143,10 @@
 	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
 		    "Look for files with symbols relative to this directory"),
 	OPT_CALLBACK('f', "fields", NULL, "str",
-		     "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr",
+		     "comma separated output fields prepend with 'type:'. "
+		     "Valid types: hw,sw,trace,raw. "
+		     "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
+		     "addr,symoff",
 		     parse_output_fields),
 	OPT_BOOLEAN('a', "all-cpus", &system_wide,
 		     "system-wide collection from all CPUs"),
@@ -1106,6 +1155,9 @@
 		   "only display events for these comms"),
 	OPT_BOOLEAN('I', "show-info", &show_full_info,
 		    "display extended information from perf.data file"),
+	OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path,
+		    "Show the path of [kernel.kallsyms]"),
+
 	OPT_END()
 };
 
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index f5d2a63..ea40e4e 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -182,8 +182,8 @@
 static bool			no_inherit			= false;
 static bool			scale				=  true;
 static bool			no_aggr				= false;
-static pid_t			target_pid			= -1;
-static pid_t			target_tid			= -1;
+static const char		*target_pid;
+static const char		*target_tid;
 static pid_t			child_pid			= -1;
 static bool			null_run			=  false;
 static int			detailed_run			=  0;
@@ -296,7 +296,7 @@
 	if (system_wide)
 		return perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
 						group, group_fd);
-	if (target_pid == -1 && target_tid == -1) {
+	if (!target_pid && !target_tid) {
 		attr->disabled = 1;
 		attr->enable_on_exec = 1;
 	}
@@ -446,7 +446,7 @@
 			exit(-1);
 		}
 
-		if (target_tid == -1 && target_pid == -1 && !system_wide)
+		if (!target_tid && !target_pid && !system_wide)
 			evsel_list->threads->map[0] = child_pid;
 
 		/*
@@ -576,6 +576,8 @@
 	if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
 		fprintf(output, " # %8.3f CPUs utilized          ",
 			avg / avg_stats(&walltime_nsecs_stats));
+	else
+		fprintf(output, "                                   ");
 }
 
 /* used for get_ratio_color() */
@@ -844,12 +846,18 @@
 
 		fprintf(output, " # %8.3f GHz                    ", ratio);
 	} else if (runtime_nsecs_stats[cpu].n != 0) {
+		char unit = 'M';
+
 		total = avg_stats(&runtime_nsecs_stats[cpu]);
 
 		if (total)
 			ratio = 1000.0 * avg / total;
+		if (ratio < 0.001) {
+			ratio *= 1000;
+			unit = 'K';
+		}
 
-		fprintf(output, " # %8.3f M/sec                  ", ratio);
+		fprintf(output, " # %8.3f %c/sec                  ", ratio, unit);
 	} else {
 		fprintf(output, "                                   ");
 	}
@@ -960,14 +968,14 @@
 	if (!csv_output) {
 		fprintf(output, "\n");
 		fprintf(output, " Performance counter stats for ");
-		if(target_pid == -1 && target_tid == -1) {
+		if (!target_pid && !target_tid) {
 			fprintf(output, "\'%s", argv[0]);
 			for (i = 1; i < argc; i++)
 				fprintf(output, " %s", argv[i]);
-		} else if (target_pid != -1)
-			fprintf(output, "process id \'%d", target_pid);
+		} else if (target_pid)
+			fprintf(output, "process id \'%s", target_pid);
 		else
-			fprintf(output, "thread id \'%d", target_tid);
+			fprintf(output, "thread id \'%s", target_tid);
 
 		fprintf(output, "\'");
 		if (run_count > 1)
@@ -1041,10 +1049,10 @@
 		     "event filter", parse_filter),
 	OPT_BOOLEAN('i', "no-inherit", &no_inherit,
 		    "child tasks do not inherit counters"),
-	OPT_INTEGER('p', "pid", &target_pid,
-		    "stat events on existing process id"),
-	OPT_INTEGER('t', "tid", &target_tid,
-		    "stat events on existing thread id"),
+	OPT_STRING('p', "pid", &target_pid, "pid",
+		   "stat events on existing process id"),
+	OPT_STRING('t', "tid", &target_tid, "tid",
+		   "stat events on existing thread id"),
 	OPT_BOOLEAN('a', "all-cpus", &system_wide,
 		    "system-wide collection from all CPUs"),
 	OPT_BOOLEAN('g', "group", &group,
@@ -1182,7 +1190,7 @@
 	} else if (big_num_opt == 0) /* User passed --no-big-num */
 		big_num = false;
 
-	if (!argc && target_pid == -1 && target_tid == -1)
+	if (!argc && !target_pid && !target_tid)
 		usage_with_options(stat_usage, options);
 	if (run_count <= 0)
 		usage_with_options(stat_usage, options);
@@ -1198,10 +1206,11 @@
 	if (add_default_attributes())
 		goto out;
 
-	if (target_pid != -1)
+	if (target_pid)
 		target_tid = target_pid;
 
-	evsel_list->threads = thread_map__new(target_pid, target_tid);
+	evsel_list->threads = thread_map__new_str(target_pid,
+						  target_tid, UINT_MAX);
 	if (evsel_list->threads == NULL) {
 		pr_err("Problems finding threads of monitor\n");
 		usage_with_options(stat_usage, options);
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 3854e86..3e087ce 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -15,6 +15,8 @@
 #include "util/thread_map.h"
 #include "../../include/linux/hw_breakpoint.h"
 
+#include <sys/mman.h>
+
 static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym)
 {
 	bool *visited = symbol__priv(sym);
@@ -276,7 +278,7 @@
 		return -1;
 	}
 
-	threads = thread_map__new(-1, getpid());
+	threads = thread_map__new(-1, getpid(), UINT_MAX);
 	if (threads == NULL) {
 		pr_debug("thread_map__new\n");
 		return -1;
@@ -342,7 +344,7 @@
 		return -1;
 	}
 
-	threads = thread_map__new(-1, getpid());
+	threads = thread_map__new(-1, getpid(), UINT_MAX);
 	if (threads == NULL) {
 		pr_debug("thread_map__new\n");
 		return -1;
@@ -490,7 +492,7 @@
 		expected_nr_events[i] = random() % 257;
 	}
 
-	threads = thread_map__new(-1, getpid());
+	threads = thread_map__new(-1, getpid(), UINT_MAX);
 	if (threads == NULL) {
 		pr_debug("thread_map__new\n");
 		return -1;
@@ -1008,12 +1010,9 @@
 static int test__PERF_RECORD(void)
 {
 	struct perf_record_opts opts = {
-		.target_pid = -1,
-		.target_tid = -1,
 		.no_delay   = true,
 		.freq	    = 10,
 		.mmap_pages = 256,
-		.sample_id_all_avail = true,
 	};
 	cpu_set_t *cpu_mask = NULL;
 	size_t cpu_mask_size = 0;
@@ -1054,7 +1053,7 @@
 	 * we're monitoring, the one forked there.
 	 */
 	err = perf_evlist__create_maps(evlist, opts.target_pid,
-				       opts.target_tid, opts.cpu_list);
+				       opts.target_tid, UINT_MAX, opts.cpu_list);
 	if (err < 0) {
 		pr_debug("Not enough memory to create thread/cpu maps\n");
 		goto out_delete_evlist;
@@ -1296,6 +1295,173 @@
 	return (err < 0 || errs > 0) ? -1 : 0;
 }
 
+
+#if defined(__x86_64__) || defined(__i386__)
+
+#define barrier() asm volatile("" ::: "memory")
+
+static u64 rdpmc(unsigned int counter)
+{
+	unsigned int low, high;
+
+	asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter));
+
+	return low | ((u64)high) << 32;
+}
+
+static u64 rdtsc(void)
+{
+	unsigned int low, high;
+
+	asm volatile("rdtsc" : "=a" (low), "=d" (high));
+
+	return low | ((u64)high) << 32;
+}
+
+static u64 mmap_read_self(void *addr)
+{
+	struct perf_event_mmap_page *pc = addr;
+	u32 seq, idx, time_mult = 0, time_shift = 0;
+	u64 count, cyc = 0, time_offset = 0, enabled, running, delta;
+
+	do {
+		seq = pc->lock;
+		barrier();
+
+		enabled = pc->time_enabled;
+		running = pc->time_running;
+
+		if (enabled != running) {
+			cyc = rdtsc();
+			time_mult = pc->time_mult;
+			time_shift = pc->time_shift;
+			time_offset = pc->time_offset;
+		}
+
+		idx = pc->index;
+		count = pc->offset;
+		if (idx)
+			count += rdpmc(idx - 1);
+
+		barrier();
+	} while (pc->lock != seq);
+
+	if (enabled != running) {
+		u64 quot, rem;
+
+		quot = (cyc >> time_shift);
+		rem = cyc & ((1 << time_shift) - 1);
+		delta = time_offset + quot * time_mult +
+			((rem * time_mult) >> time_shift);
+
+		enabled += delta;
+		if (idx)
+			running += delta;
+
+		quot = count / running;
+		rem = count % running;
+		count = quot * enabled + (rem * enabled) / running;
+	}
+
+	return count;
+}
+
+/*
+ * If the RDPMC instruction faults then signal this back to the test parent task:
+ */
+static void segfault_handler(int sig __used, siginfo_t *info __used, void *uc __used)
+{
+	exit(-1);
+}
+
+static int __test__rdpmc(void)
+{
+	long page_size = sysconf(_SC_PAGE_SIZE);
+	volatile int tmp = 0;
+	u64 i, loops = 1000;
+	int n;
+	int fd;
+	void *addr;
+	struct perf_event_attr attr = {
+		.type = PERF_TYPE_HARDWARE,
+		.config = PERF_COUNT_HW_INSTRUCTIONS,
+		.exclude_kernel = 1,
+	};
+	u64 delta_sum = 0;
+        struct sigaction sa;
+
+	sigfillset(&sa.sa_mask);
+	sa.sa_sigaction = segfault_handler;
+	sigaction(SIGSEGV, &sa, NULL);
+
+	fprintf(stderr, "\n\n");
+
+	fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
+	if (fd < 0) {
+		die("Error: sys_perf_event_open() syscall returned "
+		    "with %d (%s)\n", fd, strerror(errno));
+	}
+
+	addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
+	if (addr == (void *)(-1)) {
+		die("Error: mmap() syscall returned "
+		    "with (%s)\n", strerror(errno));
+	}
+
+	for (n = 0; n < 6; n++) {
+		u64 stamp, now, delta;
+
+		stamp = mmap_read_self(addr);
+
+		for (i = 0; i < loops; i++)
+			tmp++;
+
+		now = mmap_read_self(addr);
+		loops *= 10;
+
+		delta = now - stamp;
+		fprintf(stderr, "%14d: %14Lu\n", n, (long long)delta);
+
+		delta_sum += delta;
+	}
+
+	munmap(addr, page_size);
+	close(fd);
+
+	fprintf(stderr, "   ");
+
+	if (!delta_sum)
+		return -1;
+
+	return 0;
+}
+
+static int test__rdpmc(void)
+{
+	int status = 0;
+	int wret = 0;
+	int ret;
+	int pid;
+
+	pid = fork();
+	if (pid < 0)
+		return -1;
+
+	if (!pid) {
+		ret = __test__rdpmc();
+
+		exit(ret);
+	}
+
+	wret = waitpid(pid, &status, 0);
+	if (wret < 0 || status)
+		return -1;
+
+	return 0;
+}
+
+#endif
+
 static struct test {
 	const char *desc;
 	int (*func)(void);
@@ -1320,6 +1486,12 @@
 		.desc = "parse events tests",
 		.func = test__parse_events,
 	},
+#if defined(__x86_64__) || defined(__i386__)
+	{
+		.desc = "x86 rdpmc test",
+		.func = test__rdpmc,
+	},
+#endif
 	{
 		.desc = "Validate PERF_RECORD_* events & perf_sample fields",
 		.func = test__PERF_RECORD,
@@ -1412,7 +1584,5 @@
 	if (symbol__init() < 0)
 		return -1;
 
-	setup_pager();
-
 	return __cmd_test(argc, argv);
 }
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ecff312..e3c63ae 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -64,7 +64,6 @@
 #include <linux/unistd.h>
 #include <linux/types.h>
 
-
 void get_term_dimensions(struct winsize *ws)
 {
 	char *s = getenv("LINES");
@@ -544,10 +543,20 @@
 
 static void *display_thread_tui(void *arg)
 {
+	struct perf_evsel *pos;
 	struct perf_top *top = arg;
 	const char *help = "For a higher level overview, try: perf top --sort comm,dso";
 
 	perf_top__sort_new_samples(top);
+
+	/*
+	 * Initialize the uid_filter_str, in the future the TUI will allow
+	 * Zooming in/out UIDs. For now juse use whatever the user passed
+	 * via --uid.
+	 */
+	list_for_each_entry(pos, &top->evlist->entries, node)
+		pos->hists.uid_filter_str = top->uid_str;
+
 	perf_evlist__tui_browse_hists(top->evlist, help,
 				      perf_top__sort_new_samples,
 				      top, top->delay_secs);
@@ -668,6 +677,12 @@
 		return;
 	}
 
+	if (!machine) {
+		pr_err("%u unprocessable samples recorded.",
+		       top->session->hists.stats.nr_unprocessable_samples++);
+		return;
+	}
+
 	if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
 		top->exact_samples++;
 
@@ -861,7 +876,7 @@
 		if (top->exclude_guest_missing)
 			attr->exclude_guest = attr->exclude_host = 0;
 retry_sample_id:
-		attr->sample_id_all = top->sample_id_all_avail ? 1 : 0;
+		attr->sample_id_all = top->sample_id_all_missing ? 0 : 1;
 try_again:
 		if (perf_evsel__open(counter, top->evlist->cpus,
 				     top->evlist->threads, top->group,
@@ -878,11 +893,11 @@
 						 "guest or host samples.\n");
 					top->exclude_guest_missing = true;
 					goto fallback_missing_features;
-				} else if (top->sample_id_all_avail) {
+				} else if (!top->sample_id_all_missing) {
 					/*
 					 * Old kernel, no attr->sample_id_type_all field
 					 */
-					top->sample_id_all_avail = false;
+					top->sample_id_all_missing = true;
 					goto retry_sample_id;
 				}
 			}
@@ -967,7 +982,7 @@
 	if (ret)
 		goto out_delete;
 
-	if (top->target_tid != -1)
+	if (top->target_tid || top->uid != UINT_MAX)
 		perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
 						  perf_event__process,
 						  &top->session->host_machine);
@@ -1105,10 +1120,8 @@
 	struct perf_top top = {
 		.count_filter	     = 5,
 		.delay_secs	     = 2,
-		.target_pid	     = -1,
-		.target_tid	     = -1,
+		.uid		     = UINT_MAX,
 		.freq		     = 1000, /* 1 KHz */
-		.sample_id_all_avail = true,
 		.mmap_pages	     = 128,
 		.sym_pcnt_filter     = 5,
 	};
@@ -1119,9 +1132,9 @@
 		     parse_events_option),
 	OPT_INTEGER('c', "count", &top.default_interval,
 		    "event period to sample"),
-	OPT_INTEGER('p', "pid", &top.target_pid,
+	OPT_STRING('p', "pid", &top.target_pid, "pid",
 		    "profile events on existing process id"),
-	OPT_INTEGER('t', "tid", &top.target_tid,
+	OPT_STRING('t', "tid", &top.target_tid, "tid",
 		    "profile events on existing thread id"),
 	OPT_BOOLEAN('a', "all-cpus", &top.system_wide,
 			    "system-wide collection from all CPUs"),
@@ -1180,6 +1193,7 @@
 		    "Display raw encoding of assembly instructions (default)"),
 	OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
 		   "Specify disassembler style (e.g. -M intel for intel syntax)"),
+	OPT_STRING('u', "uid", &top.uid_str, "user", "user to profile"),
 	OPT_END()
 	};
 
@@ -1205,18 +1219,22 @@
 
 	setup_browser(false);
 
+	top.uid = parse_target_uid(top.uid_str, top.target_tid, top.target_pid);
+	if (top.uid_str != NULL && top.uid == UINT_MAX - 1)
+		goto out_delete_evlist;
+
 	/* CPU and PID are mutually exclusive */
-	if (top.target_tid > 0 && top.cpu_list) {
+	if (top.target_tid && top.cpu_list) {
 		printf("WARNING: PID switch overriding CPU\n");
 		sleep(1);
 		top.cpu_list = NULL;
 	}
 
-	if (top.target_pid != -1)
+	if (top.target_pid)
 		top.target_tid = top.target_pid;
 
 	if (perf_evlist__create_maps(top.evlist, top.target_pid,
-				     top.target_tid, top.cpu_list) < 0)
+				     top.target_tid, top.uid, top.cpu_list) < 0)
 		usage_with_options(top_usage, options);
 
 	if (!top.evlist->nr_entries &&
@@ -1280,6 +1298,7 @@
 
 	status = __cmd_top(&top);
 
+out_delete_evlist:
 	perf_evlist__delete(top.evlist);
 
 	return status;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 16e7d20..89e3355 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -10,6 +10,9 @@
 #define rmb()		asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
 #define cpu_relax()	asm volatile("rep; nop" ::: "memory");
 #define CPUINFO_PROC	"model name"
+#ifndef __NR_perf_event_open
+# define __NR_perf_event_open 336
+#endif
 #endif
 
 #if defined(__x86_64__)
@@ -17,6 +20,9 @@
 #define rmb()		asm volatile("lfence" ::: "memory")
 #define cpu_relax()	asm volatile("rep; nop" ::: "memory");
 #define CPUINFO_PROC	"model name"
+#ifndef __NR_perf_event_open
+# define __NR_perf_event_open 298
+#endif
 #endif
 
 #ifdef __powerpc__
@@ -167,7 +173,6 @@
 		      pid_t pid, int cpu, int group_fd,
 		      unsigned long flags)
 {
-	attr->size = sizeof(*attr);
 	return syscall(__NR_perf_event_open, attr, pid, cpu,
 		       group_fd, flags);
 }
@@ -180,14 +185,32 @@
 	u64 ips[0];
 };
 
+struct branch_flags {
+	u64 mispred:1;
+	u64 predicted:1;
+	u64 reserved:62;
+};
+
+struct branch_entry {
+	u64				from;
+	u64				to;
+	struct branch_flags flags;
+};
+
+struct branch_stack {
+	u64				nr;
+	struct branch_entry	entries[0];
+};
+
 extern bool perf_host, perf_guest;
 extern const char perf_version_string[];
 
 void pthread__unblock_sigwinch(void);
 
 struct perf_record_opts {
-	pid_t	     target_pid;
-	pid_t	     target_tid;
+	const char   *target_pid;
+	const char   *target_tid;
+	uid_t	     uid;
 	bool	     call_graph;
 	bool	     group;
 	bool	     inherit_stat;
@@ -198,13 +221,14 @@
 	bool	     raw_samples;
 	bool	     sample_address;
 	bool	     sample_time;
-	bool	     sample_id_all_avail;
+	bool	     sample_id_all_missing;
 	bool	     exclude_guest_missing;
 	bool	     system_wide;
 	bool	     period;
 	unsigned int freq;
 	unsigned int mmap_pages;
 	unsigned int user_freq;
+	int	     branch_stack;
 	u64	     default_interval;
 	u64	     user_interval;
 	const char   *cpu_list;
diff --git a/tools/perf/python/twatch.py b/tools/perf/python/twatch.py
index df638c4..b11cca5 100755
--- a/tools/perf/python/twatch.py
+++ b/tools/perf/python/twatch.py
@@ -19,7 +19,7 @@
 	cpus = perf.cpu_map()
 	threads = perf.thread_map()
 	evsel = perf.evsel(task = 1, comm = 1, mmap = 0,
-			   wakeup_events = 1, sample_period = 1,
+			   wakeup_events = 1, watermark = 1,
 			   sample_id_all = 1,
 			   sample_type = perf.SAMPLE_PERIOD | perf.SAMPLE_TID | perf.SAMPLE_CPU | perf.SAMPLE_TID)
 	evsel.open(cpus = cpus, threads = threads);
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 011ed26..e5a462f 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -315,7 +315,7 @@
 		       "Please use:\n\n"
 		       "  perf buildid-cache -av vmlinux\n\n"
 		       "or:\n\n"
-		       "  --vmlinux vmlinux",
+		       "  --vmlinux vmlinux\n",
 		       sym->name, build_id_msg ?: "");
 		goto out_free_filename;
 	}
diff --git a/tools/perf/util/bitmap.c b/tools/perf/util/bitmap.c
index 5e230ac..0a1adc1 100644
--- a/tools/perf/util/bitmap.c
+++ b/tools/perf/util/bitmap.c
@@ -19,3 +19,13 @@
 
 	return w;
 }
+
+void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+		 const unsigned long *bitmap2, int bits)
+{
+	int k;
+	int nr = BITS_TO_LONGS(bits);
+
+	for (k = 0; k < nr; k++)
+		dst[k] = bitmap1[k] | bitmap2[k];
+}
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 521c38a..11e46da1 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -1,3 +1,4 @@
+#include <linux/kernel.h>
 #include "cache.h"
 #include "color.h"
 
@@ -182,12 +183,12 @@
 	}
 
 	if (perf_use_color_default && *color)
-		r += snprintf(bf, size, "%s", color);
-	r += vsnprintf(bf + r, size - r, fmt, args);
+		r += scnprintf(bf, size, "%s", color);
+	r += vscnprintf(bf + r, size - r, fmt, args);
 	if (perf_use_color_default && *color)
-		r += snprintf(bf + r, size - r, "%s", PERF_COLOR_RESET);
+		r += scnprintf(bf + r, size - r, "%s", PERF_COLOR_RESET);
 	if (trail)
-		r += snprintf(bf + r, size - r, "%s", trail);
+		r += scnprintf(bf + r, size - r, "%s", trail);
 	return r;
 }
 
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 6893eec..adc72f0 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -166,6 +166,17 @@
 	return cpus;
 }
 
+size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
+{
+	int i;
+	size_t printed = fprintf(fp, "%d cpu%s: ",
+				 map->nr, map->nr > 1 ? "s" : "");
+	for (i = 0; i < map->nr; ++i)
+		printed += fprintf(fp, "%s%d", i ? ", " : "", map->map[i]);
+
+	return printed + fprintf(fp, "\n");
+}
+
 struct cpu_map *cpu_map__dummy_new(void)
 {
 	struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 072c0a3..c415185 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -1,6 +1,8 @@
 #ifndef __PERF_CPUMAP_H
 #define __PERF_CPUMAP_H
 
+#include <stdio.h>
+
 struct cpu_map {
 	int nr;
 	int map[];
@@ -10,4 +12,6 @@
 struct cpu_map *cpu_map__dummy_new(void);
 void cpu_map__delete(struct cpu_map *map);
 
+size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
+
 #endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c
index 3507362..aada3ac 100644
--- a/tools/perf/util/ctype.c
+++ b/tools/perf/util/ctype.c
@@ -3,7 +3,7 @@
  *
  * No surprises, and works with signed and unsigned chars.
  */
-#include "cache.h"
+#include "util.h"
 
 enum {
 	S = GIT_SPACE,
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
index ffc35e7..dd8b193 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/perf/util/debugfs.c
@@ -15,32 +15,6 @@
 	0,
 };
 
-/* use this to force a umount */
-void debugfs_force_cleanup(void)
-{
-	debugfs_find_mountpoint();
-	debugfs_premounted = 0;
-	debugfs_umount();
-}
-
-/* construct a full path to a debugfs element */
-int debugfs_make_path(const char *element, char *buffer, int size)
-{
-	int len;
-
-	if (strlen(debugfs_mountpoint) == 0) {
-		buffer[0] = '\0';
-		return -1;
-	}
-
-	len = strlen(debugfs_mountpoint) + strlen(element) + 1;
-	if (len >= size)
-		return len+1;
-
-	snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element);
-	return 0;
-}
-
 static int debugfs_found;
 
 /* find the path to the mounted debugfs */
@@ -97,17 +71,6 @@
 	return 0;
 }
 
-
-int debugfs_valid_entry(const char *path)
-{
-	struct stat st;
-
-	if (stat(path, &st))
-		return -errno;
-
-	return 0;
-}
-
 static void debugfs_set_tracing_events_path(const char *mountpoint)
 {
 	snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
@@ -149,107 +112,3 @@
 	snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint);
 	debugfs_set_tracing_events_path(mountpoint);
 }
-
-/* umount the debugfs */
-
-int debugfs_umount(void)
-{
-	char umountcmd[128];
-	int ret;
-
-	/* if it was already mounted, leave it */
-	if (debugfs_premounted)
-		return 0;
-
-	/* make sure it's a valid mount point */
-	ret = debugfs_valid_mountpoint(debugfs_mountpoint);
-	if (ret)
-		return ret;
-
-	snprintf(umountcmd, sizeof(umountcmd),
-		 "/bin/umount %s", debugfs_mountpoint);
-	return system(umountcmd);
-}
-
-int debugfs_write(const char *entry, const char *value)
-{
-	char path[PATH_MAX + 1];
-	int ret, count;
-	int fd;
-
-	/* construct the path */
-	snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
-
-	/* verify that it exists */
-	ret = debugfs_valid_entry(path);
-	if (ret)
-		return ret;
-
-	/* get how many chars we're going to write */
-	count = strlen(value);
-
-	/* open the debugfs entry */
-	fd = open(path, O_RDWR);
-	if (fd < 0)
-		return -errno;
-
-	while (count > 0) {
-		/* write it */
-		ret = write(fd, value, count);
-		if (ret <= 0) {
-			if (ret == EAGAIN)
-				continue;
-			close(fd);
-			return -errno;
-		}
-		count -= ret;
-	}
-
-	/* close it */
-	close(fd);
-
-	/* return success */
-	return 0;
-}
-
-/*
- * read a debugfs entry
- * returns the number of chars read or a negative errno
- */
-int debugfs_read(const char *entry, char *buffer, size_t size)
-{
-	char path[PATH_MAX + 1];
-	int ret;
-	int fd;
-
-	/* construct the path */
-	snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
-
-	/* verify that it exists */
-	ret = debugfs_valid_entry(path);
-	if (ret)
-		return ret;
-
-	/* open the debugfs entry */
-	fd = open(path, O_RDONLY);
-	if (fd < 0)
-		return -errno;
-
-	do {
-		/* read it */
-		ret = read(fd, buffer, size);
-		if (ret == 0) {
-			close(fd);
-			return EOF;
-		}
-	} while (ret < 0 && errno == EAGAIN);
-
-	/* close it */
-	close(fd);
-
-	/* make *sure* there's a null character at the end */
-	buffer[ret] = '\0';
-
-	/* return the number of chars read */
-	return ret;
-}
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
index 4a878f7..68f3e87 100644
--- a/tools/perf/util/debugfs.h
+++ b/tools/perf/util/debugfs.h
@@ -3,14 +3,8 @@
 
 const char *debugfs_find_mountpoint(void);
 int debugfs_valid_mountpoint(const char *debugfs);
-int debugfs_valid_entry(const char *path);
 char *debugfs_mount(const char *mountpoint);
-int debugfs_umount(void);
 void debugfs_set_path(const char *mountpoint);
-int debugfs_write(const char *entry, const char *value);
-int debugfs_read(const char *entry, char *buffer, size_t size);
-void debugfs_force_cleanup(void);
-int debugfs_make_path(const char *element, char *buffer, int size);
 
 extern char debugfs_mountpoint[];
 extern char tracing_events_path[];
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index cbdeaad..1b19728 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -81,6 +81,7 @@
 	u32 raw_size;
 	void *raw_data;
 	struct ip_callchain *callchain;
+	struct branch_stack *branch_stack;
 };
 
 #define BUILD_ID_SIZE 20
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index ea32a06..159263d 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -97,9 +97,9 @@
 	++evlist->nr_entries;
 }
 
-static void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
-					  struct list_head *list,
-					  int nr_entries)
+void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
+				   struct list_head *list,
+				   int nr_entries)
 {
 	list_splice_tail(list, &evlist->entries);
 	evlist->nr_entries += nr_entries;
@@ -597,15 +597,15 @@
 	return perf_evlist__mmap_per_cpu(evlist, prot, mask);
 }
 
-int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
-			     pid_t target_tid, const char *cpu_list)
+int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid,
+			     const char *target_tid, uid_t uid, const char *cpu_list)
 {
-	evlist->threads = thread_map__new(target_pid, target_tid);
+	evlist->threads = thread_map__new_str(target_pid, target_tid, uid);
 
 	if (evlist->threads == NULL)
 		return -1;
 
-	if (cpu_list == NULL && target_tid != -1)
+	if (uid != UINT_MAX || (cpu_list == NULL && target_tid))
 		evlist->cpus = cpu_map__dummy_new();
 	else
 		evlist->cpus = cpu_map__new(cpu_list);
@@ -765,6 +765,7 @@
 	list_for_each_entry_reverse(evsel, &evlist->entries, node)
 		perf_evsel__close(evsel, ncpus, nthreads);
 
+	errno = -err;
 	return err;
 }
 
@@ -824,7 +825,7 @@
 		exit(-1);
 	}
 
-	if (!opts->system_wide && opts->target_tid == -1 && opts->target_pid == -1)
+	if (!opts->system_wide && !opts->target_tid && !opts->target_pid)
 		evlist->threads->map[0] = evlist->workload.pid;
 
 	close(child_ready_pipe[1]);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 8922aee..21f1c9e 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -106,8 +106,8 @@
 	evlist->threads	= threads;
 }
 
-int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
-			     pid_t target_tid, const char *cpu_list);
+int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid,
+			     const char *tid, uid_t uid, const char *cpu_list);
 void perf_evlist__delete_maps(struct perf_evlist *evlist);
 int perf_evlist__set_filters(struct perf_evlist *evlist);
 
@@ -117,4 +117,9 @@
 
 bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
 bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
+
+void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
+				   struct list_head *list,
+				   int nr_entries);
+
 #endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 7132ee8..f421f7c 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -68,7 +68,7 @@
 	struct perf_event_attr *attr = &evsel->attr;
 	int track = !evsel->idx; /* only the first counter needs these */
 
-	attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
+	attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
 	attr->inherit	    = !opts->no_inherit;
 	attr->read_format   = PERF_FORMAT_TOTAL_TIME_ENABLED |
 			      PERF_FORMAT_TOTAL_TIME_RUNNING |
@@ -111,7 +111,7 @@
 	if (opts->period)
 		attr->sample_type	|= PERF_SAMPLE_PERIOD;
 
-	if (opts->sample_id_all_avail &&
+	if (!opts->sample_id_all_missing &&
 	    (opts->sample_time || opts->system_wide ||
 	     !opts->no_inherit || opts->cpu_list))
 		attr->sample_type	|= PERF_SAMPLE_TIME;
@@ -126,11 +126,15 @@
 		attr->watermark = 0;
 		attr->wakeup_events = 1;
 	}
+	if (opts->branch_stack) {
+		attr->sample_type	|= PERF_SAMPLE_BRANCH_STACK;
+		attr->branch_sample_type = opts->branch_stack;
+	}
 
 	attr->mmap = track;
 	attr->comm = track;
 
-	if (opts->target_pid == -1 && opts->target_tid == -1 && !opts->system_wide) {
+	if (!opts->target_pid && !opts->target_tid && !opts->system_wide) {
 		attr->disabled = 1;
 		attr->enable_on_exec = 1;
 	}
@@ -536,7 +540,7 @@
 	}
 
 	if (type & PERF_SAMPLE_READ) {
-		fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n");
+		fprintf(stderr, "PERF_SAMPLE_READ is unsupported for now\n");
 		return -1;
 	}
 
@@ -576,6 +580,16 @@
 		data->raw_data = (void *) pdata;
 	}
 
+	if (type & PERF_SAMPLE_BRANCH_STACK) {
+		u64 sz;
+
+		data->branch_stack = (struct branch_stack *)array;
+		array++; /* nr */
+
+		sz = data->branch_stack->nr * sizeof(struct branch_entry);
+		sz /= sizeof(u64);
+		array += sz;
+	}
 	return 0;
 }
 
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index ecd7f4d..fcd9cf3 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -63,9 +63,20 @@
 	return NULL;
 }
 
-static const char *__perf_magic = "PERFFILE";
+/*
+ * magic2 = "PERFILE2"
+ * must be a numerical value to let the endianness
+ * determine the memory layout. That way we are able
+ * to detect endianness when reading the perf.data file
+ * back.
+ *
+ * we check for legacy (PERFFILE) format.
+ */
+static const char *__perf_magic1 = "PERFFILE";
+static const u64 __perf_magic2    = 0x32454c4946524550ULL;
+static const u64 __perf_magic2_sw = 0x50455246494c4532ULL;
 
-#define PERF_MAGIC	(*(u64 *)__perf_magic)
+#define PERF_MAGIC	__perf_magic2
 
 struct perf_file_attr {
 	struct perf_event_attr	attr;
@@ -280,7 +291,7 @@
 	if (realname == NULL || filename == NULL || linkname == NULL)
 		goto out_free;
 
-	len = snprintf(filename, size, "%s%s%s",
+	len = scnprintf(filename, size, "%s%s%s",
 		       debugdir, is_kallsyms ? "/" : "", realname);
 	if (mkdir_p(filename, 0755))
 		goto out_free;
@@ -295,7 +306,7 @@
 			goto out_free;
 	}
 
-	len = snprintf(linkname, size, "%s/.build-id/%.2s",
+	len = scnprintf(linkname, size, "%s/.build-id/%.2s",
 		       debugdir, sbuild_id);
 
 	if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
@@ -1012,6 +1023,12 @@
 	return do_write_string(fd, buffer);
 }
 
+static int write_branch_stack(int fd __used, struct perf_header *h __used,
+		       struct perf_evlist *evlist __used)
+{
+	return 0;
+}
+
 static void print_hostname(struct perf_header *ph, int fd, FILE *fp)
 {
 	char *str = do_read_string(fd, ph);
@@ -1133,8 +1150,9 @@
 	uint64_t id;
 	void *buf = NULL;
 	char *str;
-	u32 nre, sz, nr, i, j, msz;
-	int ret;
+	u32 nre, sz, nr, i, j;
+	ssize_t ret;
+	size_t msz;
 
 	/* number of events */
 	ret = read(fd, &nre, sizeof(nre));
@@ -1151,25 +1169,23 @@
 	if (ph->needs_swap)
 		sz = bswap_32(sz);
 
-	/*
-	 * ensure it is at least to our ABI rev
-	 */
-	if (sz < (u32)sizeof(attr))
-		goto error;
-
 	memset(&attr, 0, sizeof(attr));
 
-	/* read entire region to sync up to next field */
+	/* buffer to hold on file attr struct */
 	buf = malloc(sz);
 	if (!buf)
 		goto error;
 
 	msz = sizeof(attr);
-	if (sz < msz)
+	if (sz < (ssize_t)msz)
 		msz = sz;
 
 	for (i = 0 ; i < nre; i++) {
 
+		/*
+		 * must read entire on-file attr struct to
+		 * sync up with layout.
+		 */
 		ret = read(fd, buf, sz);
 		if (ret != (ssize_t)sz)
 			goto error;
@@ -1305,25 +1321,204 @@
 	free(str);
 }
 
+static void print_branch_stack(struct perf_header *ph __used, int fd __used,
+			       FILE *fp)
+{
+	fprintf(fp, "# contains samples with branch stack\n");
+}
+
+static int __event_process_build_id(struct build_id_event *bev,
+				    char *filename,
+				    struct perf_session *session)
+{
+	int err = -1;
+	struct list_head *head;
+	struct machine *machine;
+	u16 misc;
+	struct dso *dso;
+	enum dso_kernel_type dso_type;
+
+	machine = perf_session__findnew_machine(session, bev->pid);
+	if (!machine)
+		goto out;
+
+	misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+
+	switch (misc) {
+	case PERF_RECORD_MISC_KERNEL:
+		dso_type = DSO_TYPE_KERNEL;
+		head = &machine->kernel_dsos;
+		break;
+	case PERF_RECORD_MISC_GUEST_KERNEL:
+		dso_type = DSO_TYPE_GUEST_KERNEL;
+		head = &machine->kernel_dsos;
+		break;
+	case PERF_RECORD_MISC_USER:
+	case PERF_RECORD_MISC_GUEST_USER:
+		dso_type = DSO_TYPE_USER;
+		head = &machine->user_dsos;
+		break;
+	default:
+		goto out;
+	}
+
+	dso = __dsos__findnew(head, filename);
+	if (dso != NULL) {
+		char sbuild_id[BUILD_ID_SIZE * 2 + 1];
+
+		dso__set_build_id(dso, &bev->build_id);
+
+		if (filename[0] == '[')
+			dso->kernel = dso_type;
+
+		build_id__sprintf(dso->build_id, sizeof(dso->build_id),
+				  sbuild_id);
+		pr_debug("build id event received for %s: %s\n",
+			 dso->long_name, sbuild_id);
+	}
+
+	err = 0;
+out:
+	return err;
+}
+
+static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
+						 int input, u64 offset, u64 size)
+{
+	struct perf_session *session = container_of(header, struct perf_session, header);
+	struct {
+		struct perf_event_header   header;
+		u8			   build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
+		char			   filename[0];
+	} old_bev;
+	struct build_id_event bev;
+	char filename[PATH_MAX];
+	u64 limit = offset + size;
+
+	while (offset < limit) {
+		ssize_t len;
+
+		if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
+			return -1;
+
+		if (header->needs_swap)
+			perf_event_header__bswap(&old_bev.header);
+
+		len = old_bev.header.size - sizeof(old_bev);
+		if (read(input, filename, len) != len)
+			return -1;
+
+		bev.header = old_bev.header;
+
+		/*
+		 * As the pid is the missing value, we need to fill
+		 * it properly. The header.misc value give us nice hint.
+		 */
+		bev.pid	= HOST_KERNEL_ID;
+		if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER ||
+		    bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL)
+			bev.pid	= DEFAULT_GUEST_KERNEL_ID;
+
+		memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
+		__event_process_build_id(&bev, filename, session);
+
+		offset += bev.header.size;
+	}
+
+	return 0;
+}
+
+static int perf_header__read_build_ids(struct perf_header *header,
+				       int input, u64 offset, u64 size)
+{
+	struct perf_session *session = container_of(header, struct perf_session, header);
+	struct build_id_event bev;
+	char filename[PATH_MAX];
+	u64 limit = offset + size, orig_offset = offset;
+	int err = -1;
+
+	while (offset < limit) {
+		ssize_t len;
+
+		if (read(input, &bev, sizeof(bev)) != sizeof(bev))
+			goto out;
+
+		if (header->needs_swap)
+			perf_event_header__bswap(&bev.header);
+
+		len = bev.header.size - sizeof(bev);
+		if (read(input, filename, len) != len)
+			goto out;
+		/*
+		 * The a1645ce1 changeset:
+		 *
+		 * "perf: 'perf kvm' tool for monitoring guest performance from host"
+		 *
+		 * Added a field to struct build_id_event that broke the file
+		 * format.
+		 *
+		 * Since the kernel build-id is the first entry, process the
+		 * table using the old format if the well known
+		 * '[kernel.kallsyms]' string for the kernel build-id has the
+		 * first 4 characters chopped off (where the pid_t sits).
+		 */
+		if (memcmp(filename, "nel.kallsyms]", 13) == 0) {
+			if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1)
+				return -1;
+			return perf_header__read_build_ids_abi_quirk(header, input, offset, size);
+		}
+
+		__event_process_build_id(&bev, filename, session);
+
+		offset += bev.header.size;
+	}
+	err = 0;
+out:
+	return err;
+}
+
+static int process_trace_info(struct perf_file_section *section __unused,
+			      struct perf_header *ph __unused,
+			      int feat __unused, int fd)
+{
+	trace_report(fd, false);
+	return 0;
+}
+
+static int process_build_id(struct perf_file_section *section,
+			    struct perf_header *ph,
+			    int feat __unused, int fd)
+{
+	if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
+		pr_debug("Failed to read buildids, continuing...\n");
+	return 0;
+}
+
 struct feature_ops {
 	int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
 	void (*print)(struct perf_header *h, int fd, FILE *fp);
+	int (*process)(struct perf_file_section *section,
+		       struct perf_header *h, int feat, int fd);
 	const char *name;
 	bool full_only;
 };
 
 #define FEAT_OPA(n, func) \
 	[n] = { .name = #n, .write = write_##func, .print = print_##func }
+#define FEAT_OPP(n, func) \
+	[n] = { .name = #n, .write = write_##func, .print = print_##func, \
+		.process = process_##func }
 #define FEAT_OPF(n, func) \
-	[n] = { .name = #n, .write = write_##func, .print = print_##func, .full_only = true }
+	[n] = { .name = #n, .write = write_##func, .print = print_##func, \
+		.full_only = true }
 
 /* feature_ops not implemented: */
 #define print_trace_info		NULL
 #define print_build_id			NULL
 
 static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
-	FEAT_OPA(HEADER_TRACE_INFO,	trace_info),
-	FEAT_OPA(HEADER_BUILD_ID,	build_id),
+	FEAT_OPP(HEADER_TRACE_INFO,	trace_info),
+	FEAT_OPP(HEADER_BUILD_ID,	build_id),
 	FEAT_OPA(HEADER_HOSTNAME,	hostname),
 	FEAT_OPA(HEADER_OSRELEASE,	osrelease),
 	FEAT_OPA(HEADER_VERSION,	version),
@@ -1336,6 +1531,7 @@
 	FEAT_OPA(HEADER_CMDLINE,	cmdline),
 	FEAT_OPF(HEADER_CPU_TOPOLOGY,	cpu_topology),
 	FEAT_OPF(HEADER_NUMA_TOPOLOGY,	numa_topology),
+	FEAT_OPA(HEADER_BRANCH_STACK,	branch_stack),
 };
 
 struct header_print_data {
@@ -1620,24 +1816,128 @@
 	return err;
 }
 
+static const int attr_file_abi_sizes[] = {
+	[0] = PERF_ATTR_SIZE_VER0,
+	[1] = PERF_ATTR_SIZE_VER1,
+	0,
+};
+
+/*
+ * In the legacy file format, the magic number is not used to encode endianness.
+ * hdr_sz was used to encode endianness. But given that hdr_sz can vary based
+ * on ABI revisions, we need to try all combinations for all endianness to
+ * detect the endianness.
+ */
+static int try_all_file_abis(uint64_t hdr_sz, struct perf_header *ph)
+{
+	uint64_t ref_size, attr_size;
+	int i;
+
+	for (i = 0 ; attr_file_abi_sizes[i]; i++) {
+		ref_size = attr_file_abi_sizes[i]
+			 + sizeof(struct perf_file_section);
+		if (hdr_sz != ref_size) {
+			attr_size = bswap_64(hdr_sz);
+			if (attr_size != ref_size)
+				continue;
+
+			ph->needs_swap = true;
+		}
+		pr_debug("ABI%d perf.data file detected, need_swap=%d\n",
+			 i,
+			 ph->needs_swap);
+		return 0;
+	}
+	/* could not determine endianness */
+	return -1;
+}
+
+#define PERF_PIPE_HDR_VER0	16
+
+static const size_t attr_pipe_abi_sizes[] = {
+	[0] = PERF_PIPE_HDR_VER0,
+	0,
+};
+
+/*
+ * In the legacy pipe format, there is an implicit assumption that endiannesss
+ * between host recording the samples, and host parsing the samples is the
+ * same. This is not always the case given that the pipe output may always be
+ * redirected into a file and analyzed on a different machine with possibly a
+ * different endianness and perf_event ABI revsions in the perf tool itself.
+ */
+static int try_all_pipe_abis(uint64_t hdr_sz, struct perf_header *ph)
+{
+	u64 attr_size;
+	int i;
+
+	for (i = 0 ; attr_pipe_abi_sizes[i]; i++) {
+		if (hdr_sz != attr_pipe_abi_sizes[i]) {
+			attr_size = bswap_64(hdr_sz);
+			if (attr_size != hdr_sz)
+				continue;
+
+			ph->needs_swap = true;
+		}
+		pr_debug("Pipe ABI%d perf.data file detected\n", i);
+		return 0;
+	}
+	return -1;
+}
+
+static int check_magic_endian(u64 magic, uint64_t hdr_sz,
+			      bool is_pipe, struct perf_header *ph)
+{
+	int ret;
+
+	/* check for legacy format */
+	ret = memcmp(&magic, __perf_magic1, sizeof(magic));
+	if (ret == 0) {
+		pr_debug("legacy perf.data format\n");
+		if (is_pipe)
+			return try_all_pipe_abis(hdr_sz, ph);
+
+		return try_all_file_abis(hdr_sz, ph);
+	}
+	/*
+	 * the new magic number serves two purposes:
+	 * - unique number to identify actual perf.data files
+	 * - encode endianness of file
+	 */
+
+	/* check magic number with one endianness */
+	if (magic == __perf_magic2)
+		return 0;
+
+	/* check magic number with opposite endianness */
+	if (magic != __perf_magic2_sw)
+		return -1;
+
+	ph->needs_swap = true;
+
+	return 0;
+}
+
 int perf_file_header__read(struct perf_file_header *header,
 			   struct perf_header *ph, int fd)
 {
+	int ret;
+
 	lseek(fd, 0, SEEK_SET);
 
-	if (readn(fd, header, sizeof(*header)) <= 0 ||
-	    memcmp(&header->magic, __perf_magic, sizeof(header->magic)))
+	ret = readn(fd, header, sizeof(*header));
+	if (ret <= 0)
 		return -1;
 
-	if (header->attr_size != sizeof(struct perf_file_attr)) {
-		u64 attr_size = bswap_64(header->attr_size);
+	if (check_magic_endian(header->magic,
+			       header->attr_size, false, ph) < 0) {
+		pr_debug("magic/endian check failed\n");
+		return -1;
+	}
 
-		if (attr_size != sizeof(struct perf_file_attr))
-			return -1;
-
+	if (ph->needs_swap) {
 		mem_bswap_64(header, offsetof(struct perf_file_header,
-					    adds_features));
-		ph->needs_swap = true;
+			     adds_features));
 	}
 
 	if (header->size != sizeof(*header)) {
@@ -1689,156 +1989,6 @@
 	return 0;
 }
 
-static int __event_process_build_id(struct build_id_event *bev,
-				    char *filename,
-				    struct perf_session *session)
-{
-	int err = -1;
-	struct list_head *head;
-	struct machine *machine;
-	u16 misc;
-	struct dso *dso;
-	enum dso_kernel_type dso_type;
-
-	machine = perf_session__findnew_machine(session, bev->pid);
-	if (!machine)
-		goto out;
-
-	misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
-
-	switch (misc) {
-	case PERF_RECORD_MISC_KERNEL:
-		dso_type = DSO_TYPE_KERNEL;
-		head = &machine->kernel_dsos;
-		break;
-	case PERF_RECORD_MISC_GUEST_KERNEL:
-		dso_type = DSO_TYPE_GUEST_KERNEL;
-		head = &machine->kernel_dsos;
-		break;
-	case PERF_RECORD_MISC_USER:
-	case PERF_RECORD_MISC_GUEST_USER:
-		dso_type = DSO_TYPE_USER;
-		head = &machine->user_dsos;
-		break;
-	default:
-		goto out;
-	}
-
-	dso = __dsos__findnew(head, filename);
-	if (dso != NULL) {
-		char sbuild_id[BUILD_ID_SIZE * 2 + 1];
-
-		dso__set_build_id(dso, &bev->build_id);
-
-		if (filename[0] == '[')
-			dso->kernel = dso_type;
-
-		build_id__sprintf(dso->build_id, sizeof(dso->build_id),
-				  sbuild_id);
-		pr_debug("build id event received for %s: %s\n",
-			 dso->long_name, sbuild_id);
-	}
-
-	err = 0;
-out:
-	return err;
-}
-
-static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
-						 int input, u64 offset, u64 size)
-{
-	struct perf_session *session = container_of(header, struct perf_session, header);
-	struct {
-		struct perf_event_header   header;
-		u8			   build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
-		char			   filename[0];
-	} old_bev;
-	struct build_id_event bev;
-	char filename[PATH_MAX];
-	u64 limit = offset + size;
-
-	while (offset < limit) {
-		ssize_t len;
-
-		if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
-			return -1;
-
-		if (header->needs_swap)
-			perf_event_header__bswap(&old_bev.header);
-
-		len = old_bev.header.size - sizeof(old_bev);
-		if (read(input, filename, len) != len)
-			return -1;
-
-		bev.header = old_bev.header;
-
-		/*
-		 * As the pid is the missing value, we need to fill
-		 * it properly. The header.misc value give us nice hint.
-		 */
-		bev.pid	= HOST_KERNEL_ID;
-		if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER ||
-		    bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL)
-			bev.pid	= DEFAULT_GUEST_KERNEL_ID;
-
-		memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
-		__event_process_build_id(&bev, filename, session);
-
-		offset += bev.header.size;
-	}
-
-	return 0;
-}
-
-static int perf_header__read_build_ids(struct perf_header *header,
-				       int input, u64 offset, u64 size)
-{
-	struct perf_session *session = container_of(header, struct perf_session, header);
-	struct build_id_event bev;
-	char filename[PATH_MAX];
-	u64 limit = offset + size, orig_offset = offset;
-	int err = -1;
-
-	while (offset < limit) {
-		ssize_t len;
-
-		if (read(input, &bev, sizeof(bev)) != sizeof(bev))
-			goto out;
-
-		if (header->needs_swap)
-			perf_event_header__bswap(&bev.header);
-
-		len = bev.header.size - sizeof(bev);
-		if (read(input, filename, len) != len)
-			goto out;
-		/*
-		 * The a1645ce1 changeset:
-		 *
-		 * "perf: 'perf kvm' tool for monitoring guest performance from host"
-		 *
-		 * Added a field to struct build_id_event that broke the file
-		 * format.
-		 *
-		 * Since the kernel build-id is the first entry, process the
-		 * table using the old format if the well known
-		 * '[kernel.kallsyms]' string for the kernel build-id has the
-		 * first 4 characters chopped off (where the pid_t sits).
-		 */
-		if (memcmp(filename, "nel.kallsyms]", 13) == 0) {
-			if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1)
-				return -1;
-			return perf_header__read_build_ids_abi_quirk(header, input, offset, size);
-		}
-
-		__event_process_build_id(&bev, filename, session);
-
-		offset += bev.header.size;
-	}
-	err = 0;
-out:
-	return err;
-}
-
 static int perf_file_section__process(struct perf_file_section *section,
 				      struct perf_header *ph,
 				      int feat, int fd, void *data __used)
@@ -1854,41 +2004,33 @@
 		return 0;
 	}
 
-	switch (feat) {
-	case HEADER_TRACE_INFO:
-		trace_report(fd, false);
-		break;
-	case HEADER_BUILD_ID:
-		if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
-			pr_debug("Failed to read buildids, continuing...\n");
-		break;
-	default:
-		break;
-	}
+	if (!feat_ops[feat].process)
+		return 0;
 
-	return 0;
+	return feat_ops[feat].process(section, ph, feat, fd);
 }
 
 static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
 				       struct perf_header *ph, int fd,
 				       bool repipe)
 {
-	if (readn(fd, header, sizeof(*header)) <= 0 ||
-	    memcmp(&header->magic, __perf_magic, sizeof(header->magic)))
+	int ret;
+
+	ret = readn(fd, header, sizeof(*header));
+	if (ret <= 0)
 		return -1;
 
+	if (check_magic_endian(header->magic, header->size, true, ph) < 0) {
+		pr_debug("endian/magic failed\n");
+		return -1;
+	}
+
+	if (ph->needs_swap)
+		header->size = bswap_64(header->size);
+
 	if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0)
 		return -1;
 
-	if (header->size != sizeof(*header)) {
-		u64 size = bswap_64(header->size);
-
-		if (size != sizeof(*header))
-			return -1;
-
-		ph->needs_swap = true;
-	}
-
 	return 0;
 }
 
@@ -1908,6 +2050,52 @@
 	return 0;
 }
 
+static int read_attr(int fd, struct perf_header *ph,
+		     struct perf_file_attr *f_attr)
+{
+	struct perf_event_attr *attr = &f_attr->attr;
+	size_t sz, left;
+	size_t our_sz = sizeof(f_attr->attr);
+	int ret;
+
+	memset(f_attr, 0, sizeof(*f_attr));
+
+	/* read minimal guaranteed structure */
+	ret = readn(fd, attr, PERF_ATTR_SIZE_VER0);
+	if (ret <= 0) {
+		pr_debug("cannot read %d bytes of header attr\n",
+			 PERF_ATTR_SIZE_VER0);
+		return -1;
+	}
+
+	/* on file perf_event_attr size */
+	sz = attr->size;
+
+	if (ph->needs_swap)
+		sz = bswap_32(sz);
+
+	if (sz == 0) {
+		/* assume ABI0 */
+		sz =  PERF_ATTR_SIZE_VER0;
+	} else if (sz > our_sz) {
+		pr_debug("file uses a more recent and unsupported ABI"
+			 " (%zu bytes extra)\n", sz - our_sz);
+		return -1;
+	}
+	/* what we have not yet read and that we know about */
+	left = sz - PERF_ATTR_SIZE_VER0;
+	if (left) {
+		void *ptr = attr;
+		ptr += PERF_ATTR_SIZE_VER0;
+
+		ret = readn(fd, ptr, left);
+	}
+	/* read perf_file_section, ids are read in caller */
+	ret = readn(fd, &f_attr->ids, sizeof(f_attr->ids));
+
+	return ret <= 0 ? -1 : 0;
+}
+
 int perf_session__read_header(struct perf_session *session, int fd)
 {
 	struct perf_header *header = &session->header;
@@ -1923,19 +2111,17 @@
 	if (session->fd_pipe)
 		return perf_header__read_pipe(session, fd);
 
-	if (perf_file_header__read(&f_header, header, fd) < 0) {
-		pr_debug("incompatible file format\n");
+	if (perf_file_header__read(&f_header, header, fd) < 0)
 		return -EINVAL;
-	}
 
-	nr_attrs = f_header.attrs.size / sizeof(f_attr);
+	nr_attrs = f_header.attrs.size / f_header.attr_size;
 	lseek(fd, f_header.attrs.offset, SEEK_SET);
 
 	for (i = 0; i < nr_attrs; i++) {
 		struct perf_evsel *evsel;
 		off_t tmp;
 
-		if (readn(fd, &f_attr, sizeof(f_attr)) <= 0)
+		if (read_attr(fd, header, &f_attr) < 0)
 			goto out_errno;
 
 		if (header->needs_swap)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index ac4ec95..21a6be0 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -11,6 +11,7 @@
 
 enum {
 	HEADER_RESERVED		= 0,	/* always cleared */
+	HEADER_FIRST_FEATURE	= 1,
 	HEADER_TRACE_INFO	= 1,
 	HEADER_BUILD_ID,
 
@@ -26,7 +27,7 @@
 	HEADER_EVENT_DESC,
 	HEADER_CPU_TOPOLOGY,
 	HEADER_NUMA_TOPOLOGY,
-
+	HEADER_BRANCH_STACK,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 6f505d1..3dc99a9 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -50,21 +50,25 @@
 		hists__set_col_len(hists, col, 0);
 }
 
+static void hists__set_unres_dso_col_len(struct hists *hists, int dso)
+{
+	const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
+
+	if (hists__col_len(hists, dso) < unresolved_col_width &&
+	    !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
+	    !symbol_conf.dso_list)
+		hists__set_col_len(hists, dso, unresolved_col_width);
+}
+
 static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
 {
+	const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
 	u16 len;
 
 	if (h->ms.sym)
-		hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen);
-	else {
-		const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
-
-		if (hists__col_len(hists, HISTC_DSO) < unresolved_col_width &&
-		    !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
-		    !symbol_conf.dso_list)
-			hists__set_col_len(hists, HISTC_DSO,
-					   unresolved_col_width);
-	}
+		hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4);
+	else
+		hists__set_unres_dso_col_len(hists, HISTC_DSO);
 
 	len = thread__comm_len(h->thread);
 	if (hists__new_col_len(hists, HISTC_COMM, len))
@@ -74,6 +78,37 @@
 		len = dso__name_len(h->ms.map->dso);
 		hists__new_col_len(hists, HISTC_DSO, len);
 	}
+
+	if (h->branch_info) {
+		int symlen;
+		/*
+		 * +4 accounts for '[x] ' priv level info
+		 * +2 account of 0x prefix on raw addresses
+		 */
+		if (h->branch_info->from.sym) {
+			symlen = (int)h->branch_info->from.sym->namelen + 4;
+			hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
+
+			symlen = dso__name_len(h->branch_info->from.map->dso);
+			hists__new_col_len(hists, HISTC_DSO_FROM, symlen);
+		} else {
+			symlen = unresolved_col_width + 4 + 2;
+			hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
+			hists__set_unres_dso_col_len(hists, HISTC_DSO_FROM);
+		}
+
+		if (h->branch_info->to.sym) {
+			symlen = (int)h->branch_info->to.sym->namelen + 4;
+			hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
+
+			symlen = dso__name_len(h->branch_info->to.map->dso);
+			hists__new_col_len(hists, HISTC_DSO_TO, symlen);
+		} else {
+			symlen = unresolved_col_width + 4 + 2;
+			hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
+			hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
+		}
+	}
 }
 
 static void hist_entry__add_cpumode_period(struct hist_entry *he,
@@ -195,26 +230,14 @@
 	return 0;
 }
 
-struct hist_entry *__hists__add_entry(struct hists *hists,
+static struct hist_entry *add_hist_entry(struct hists *hists,
+				      struct hist_entry *entry,
 				      struct addr_location *al,
-				      struct symbol *sym_parent, u64 period)
+				      u64 period)
 {
 	struct rb_node **p;
 	struct rb_node *parent = NULL;
 	struct hist_entry *he;
-	struct hist_entry entry = {
-		.thread	= al->thread,
-		.ms = {
-			.map	= al->map,
-			.sym	= al->sym,
-		},
-		.cpu	= al->cpu,
-		.ip	= al->addr,
-		.level	= al->level,
-		.period	= period,
-		.parent = sym_parent,
-		.filtered = symbol__parent_filter(sym_parent),
-	};
 	int cmp;
 
 	pthread_mutex_lock(&hists->lock);
@@ -225,7 +248,7 @@
 		parent = *p;
 		he = rb_entry(parent, struct hist_entry, rb_node_in);
 
-		cmp = hist_entry__cmp(&entry, he);
+		cmp = hist_entry__cmp(entry, he);
 
 		if (!cmp) {
 			he->period += period;
@@ -239,7 +262,7 @@
 			p = &(*p)->rb_right;
 	}
 
-	he = hist_entry__new(&entry);
+	he = hist_entry__new(entry);
 	if (!he)
 		goto out_unlock;
 
@@ -252,6 +275,51 @@
 	return he;
 }
 
+struct hist_entry *__hists__add_branch_entry(struct hists *self,
+					     struct addr_location *al,
+					     struct symbol *sym_parent,
+					     struct branch_info *bi,
+					     u64 period)
+{
+	struct hist_entry entry = {
+		.thread	= al->thread,
+		.ms = {
+			.map	= bi->to.map,
+			.sym	= bi->to.sym,
+		},
+		.cpu	= al->cpu,
+		.ip	= bi->to.addr,
+		.level	= al->level,
+		.period	= period,
+		.parent = sym_parent,
+		.filtered = symbol__parent_filter(sym_parent),
+		.branch_info = bi,
+	};
+
+	return add_hist_entry(self, &entry, al, period);
+}
+
+struct hist_entry *__hists__add_entry(struct hists *self,
+				      struct addr_location *al,
+				      struct symbol *sym_parent, u64 period)
+{
+	struct hist_entry entry = {
+		.thread	= al->thread,
+		.ms = {
+			.map	= al->map,
+			.sym	= al->sym,
+		},
+		.cpu	= al->cpu,
+		.ip	= al->addr,
+		.level	= al->level,
+		.period	= period,
+		.parent = sym_parent,
+		.filtered = symbol__parent_filter(sym_parent),
+	};
+
+	return add_hist_entry(self, &entry, al, period);
+}
+
 int64_t
 hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
 {
@@ -768,7 +836,7 @@
 						     sep ? "%.2f" : "   %6.2f%%",
 						     (period * 100.0) / total);
 		else
-			ret = snprintf(s, size, sep ? "%.2f" : "   %6.2f%%",
+			ret = scnprintf(s, size, sep ? "%.2f" : "   %6.2f%%",
 				       (period * 100.0) / total);
 		if (symbol_conf.show_cpu_utilization) {
 			ret += percent_color_snprintf(s + ret, size - ret,
@@ -791,20 +859,20 @@
 			}
 		}
 	} else
-		ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
+		ret = scnprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
 
 	if (symbol_conf.show_nr_samples) {
 		if (sep)
-			ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
+			ret += scnprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
 		else
-			ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
+			ret += scnprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
 	}
 
 	if (symbol_conf.show_total_period) {
 		if (sep)
-			ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
+			ret += scnprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
 		else
-			ret += snprintf(s + ret, size - ret, " %12" PRIu64, period);
+			ret += scnprintf(s + ret, size - ret, " %12" PRIu64, period);
 	}
 
 	if (pair_hists) {
@@ -819,25 +887,25 @@
 		diff = new_percent - old_percent;
 
 		if (fabs(diff) >= 0.01)
-			snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
+			ret += scnprintf(bf, sizeof(bf), "%+4.2F%%", diff);
 		else
-			snprintf(bf, sizeof(bf), " ");
+			ret += scnprintf(bf, sizeof(bf), " ");
 
 		if (sep)
-			ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
+			ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
 		else
-			ret += snprintf(s + ret, size - ret, "%11.11s", bf);
+			ret += scnprintf(s + ret, size - ret, "%11.11s", bf);
 
 		if (show_displacement) {
 			if (displacement)
-				snprintf(bf, sizeof(bf), "%+4ld", displacement);
+				ret += scnprintf(bf, sizeof(bf), "%+4ld", displacement);
 			else
-				snprintf(bf, sizeof(bf), " ");
+				ret += scnprintf(bf, sizeof(bf), " ");
 
 			if (sep)
-				ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
+				ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
 			else
-				ret += snprintf(s + ret, size - ret, "%6.6s", bf);
+				ret += scnprintf(s + ret, size - ret, "%6.6s", bf);
 		}
 	}
 
@@ -855,7 +923,7 @@
 		if (se->elide)
 			continue;
 
-		ret += snprintf(s + ret, size - ret, "%s", sep ?: "  ");
+		ret += scnprintf(s + ret, size - ret, "%s", sep ?: "  ");
 		ret += se->se_snprintf(he, s + ret, size - ret,
 				       hists__col_len(hists, se->se_width_idx));
 	}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index f55f0a8d..9413f3e 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -32,6 +32,7 @@
 	u32 nr_unknown_events;
 	u32 nr_invalid_chains;
 	u32 nr_unknown_id;
+	u32 nr_unprocessable_samples;
 };
 
 enum hist_column {
@@ -41,6 +42,11 @@
 	HISTC_COMM,
 	HISTC_PARENT,
 	HISTC_CPU,
+	HISTC_MISPREDICT,
+	HISTC_SYMBOL_FROM,
+	HISTC_SYMBOL_TO,
+	HISTC_DSO_FROM,
+	HISTC_DSO_TO,
 	HISTC_NR_COLS, /* Last entry */
 };
 
@@ -55,6 +61,7 @@
 	u64			nr_entries;
 	const struct thread	*thread_filter;
 	const struct dso	*dso_filter;
+	const char		*uid_filter_str;
 	pthread_mutex_t		lock;
 	struct events_stats	stats;
 	u64			event_stream;
@@ -72,6 +79,12 @@
 			 struct hists *hists);
 void hist_entry__free(struct hist_entry *);
 
+struct hist_entry *__hists__add_branch_entry(struct hists *self,
+					     struct addr_location *al,
+					     struct symbol *sym_parent,
+					     struct branch_info *bi,
+					     u64 period);
+
 void hists__output_resort(struct hists *self);
 void hists__output_resort_threaded(struct hists *hists);
 void hists__collapse_resort(struct hists *self);
diff --git a/tools/perf/util/include/asm/dwarf2.h b/tools/perf/util/include/asm/dwarf2.h
index bb4198e..afe3819 100644
--- a/tools/perf/util/include/asm/dwarf2.h
+++ b/tools/perf/util/include/asm/dwarf2.h
@@ -2,10 +2,12 @@
 #ifndef PERF_DWARF2_H
 #define PERF_DWARF2_H
 
-/* dwarf2.h ... dummy header file for including arch/x86/lib/memcpy_64.S */
+/* dwarf2.h ... dummy header file for including arch/x86/lib/mem{cpy,set}_64.S */
 
 #define CFI_STARTPROC
 #define CFI_ENDPROC
+#define CFI_REMEMBER_STATE
+#define CFI_RESTORE_STATE
 
 #endif	/* PERF_DWARF2_H */
 
diff --git a/tools/perf/util/include/asm/unistd_32.h b/tools/perf/util/include/asm/unistd_32.h
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tools/perf/util/include/asm/unistd_32.h
@@ -0,0 +1 @@
+
diff --git a/tools/perf/util/include/asm/unistd_64.h b/tools/perf/util/include/asm/unistd_64.h
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tools/perf/util/include/asm/unistd_64.h
@@ -0,0 +1 @@
+
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index eda4416..bb162e4 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -5,6 +5,8 @@
 #include <linux/bitops.h>
 
 int __bitmap_weight(const unsigned long *bitmap, int bits);
+void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+		 const unsigned long *bitmap2, int bits);
 
 #define BITMAP_LAST_WORD_MASK(nbits)					\
 (									\
@@ -32,4 +34,13 @@
 	return __bitmap_weight(src, nbits);
 }
 
+static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
+			     const unsigned long *src2, int nbits)
+{
+	if (small_const_nbits(nbits))
+		*dst = *src1 | *src2;
+	else
+		__bitmap_or(dst, src1, src2, nbits);
+}
+
 #endif /* _PERF_BITOPS_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 316aa0a..dea6d1c 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -212,6 +212,21 @@
 		       self->start, self->end, self->pgoff, self->dso->name);
 }
 
+size_t map__fprintf_dsoname(struct map *map, FILE *fp)
+{
+	const char *dsoname;
+
+	if (map && map->dso && (map->dso->name || map->dso->long_name)) {
+		if (symbol_conf.show_kernel_path && map->dso->long_name)
+			dsoname = map->dso->long_name;
+		else if (map->dso->name)
+			dsoname = map->dso->name;
+	} else
+		dsoname = "[unknown]";
+
+	return fprintf(fp, "%s", dsoname);
+}
+
 /*
  * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
  * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 2b8017f..b100c20 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -118,6 +118,7 @@
 struct map *map__clone(struct map *self);
 int map__overlap(struct map *l, struct map *r);
 size_t map__fprintf(struct map *self, FILE *fp);
+size_t map__fprintf_dsoname(struct map *map, FILE *fp);
 
 int map__load(struct map *self, symbol_filter_t filter);
 struct symbol *map__find_symbol(struct map *self,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index b029296..c7a6f6f 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -165,7 +165,7 @@
 	struct tracepoint_path *path = NULL;
 	DIR *sys_dir, *evt_dir;
 	struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
-	char id_buf[4];
+	char id_buf[24];
 	int fd;
 	u64 id;
 	char evt_path[MAXPATHLEN];
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index e33554a..8a8ee64 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -34,7 +34,6 @@
 
 #include "util.h"
 #include "event.h"
-#include "string.h"
 #include "strlist.h"
 #include "debug.h"
 #include "cache.h"
@@ -273,10 +272,10 @@
 /* Try to find perf_probe_event with debuginfo */
 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 					  struct probe_trace_event **tevs,
-					  int max_tevs, const char *module)
+					  int max_tevs, const char *target)
 {
 	bool need_dwarf = perf_probe_event_need_dwarf(pev);
-	struct debuginfo *dinfo = open_debuginfo(module);
+	struct debuginfo *dinfo = open_debuginfo(target);
 	int ntevs, ret = 0;
 
 	if (!dinfo) {
@@ -295,9 +294,9 @@
 
 	if (ntevs > 0) {	/* Succeeded to find trace events */
 		pr_debug("find %d probe_trace_events.\n", ntevs);
-		if (module)
+		if (target)
 			ret = add_module_to_probe_trace_events(*tevs, ntevs,
-							       module);
+							       target);
 		return ret < 0 ? ret : ntevs;
 	}
 
@@ -1729,7 +1728,7 @@
 	}
 
 	ret = 0;
-	printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":");
+	printf("Added new event%s\n", (ntevs > 1) ? "s:" : ":");
 	for (i = 0; i < ntevs; i++) {
 		tev = &tevs[i];
 		if (pev->event)
@@ -1784,7 +1783,7 @@
 
 	if (ret >= 0) {
 		/* Show how to use the event. */
-		printf("\nYou can now use it on all perf tools, such as:\n\n");
+		printf("\nYou can now use it in all perf tools, such as:\n\n");
 		printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group,
 			 tev->event);
 	}
@@ -1796,14 +1795,14 @@
 
 static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 					  struct probe_trace_event **tevs,
-					  int max_tevs, const char *module)
+					  int max_tevs, const char *target)
 {
 	struct symbol *sym;
 	int ret = 0, i;
 	struct probe_trace_event *tev;
 
 	/* Convert perf_probe_event with debuginfo */
-	ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module);
+	ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
 	if (ret != 0)
 		return ret;	/* Found in debuginfo or got an error */
 
@@ -1819,8 +1818,8 @@
 		goto error;
 	}
 
-	if (module) {
-		tev->point.module = strdup(module);
+	if (target) {
+		tev->point.module = strdup(target);
 		if (tev->point.module == NULL) {
 			ret = -ENOMEM;
 			goto error;
@@ -1890,7 +1889,7 @@
 };
 
 int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
-			  int max_tevs, const char *module, bool force_add)
+			  int max_tevs, const char *target, bool force_add)
 {
 	int i, j, ret;
 	struct __event_package *pkgs;
@@ -1913,7 +1912,7 @@
 		ret  = convert_to_probe_trace_events(pkgs[i].pev,
 						     &pkgs[i].tevs,
 						     max_tevs,
-						     module);
+						     target);
 		if (ret < 0)
 			goto end;
 		pkgs[i].ntevs = ret;
@@ -1965,7 +1964,7 @@
 		goto error;
 	}
 
-	printf("Remove event: %s\n", ent->s);
+	printf("Removed event: %s\n", ent->s);
 	return 0;
 error:
 	pr_warning("Failed to delete event: %s\n", strerror(-ret));
@@ -2069,7 +2068,7 @@
 	return 1;
 }
 
-int show_available_funcs(const char *module, struct strfilter *_filter)
+int show_available_funcs(const char *target, struct strfilter *_filter)
 {
 	struct map *map;
 	int ret;
@@ -2080,9 +2079,9 @@
 	if (ret < 0)
 		return ret;
 
-	map = kernel_get_module_map(module);
+	map = kernel_get_module_map(target);
 	if (!map) {
-		pr_err("Failed to find %s map.\n", (module) ? : "kernel");
+		pr_err("Failed to find %s map.\n", (target) ? : "kernel");
 		return -EINVAL;
 	}
 	available_func_filter = _filter;
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 74bd2e6..2cc162d 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -30,7 +30,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
-#include <ctype.h>
 #include <dwarf-regs.h>
 
 #include <linux/bitops.h>
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
new file mode 100644
index 0000000..2884e67
--- /dev/null
+++ b/tools/perf/util/python-ext-sources
@@ -0,0 +1,19 @@
+#
+# List of files needed by perf python extention
+#
+# Each source file must be placed on its own line so that it can be
+# processed by Makefile and util/setup.py accordingly.
+#
+
+util/python.c
+util/ctype.c
+util/evlist.c
+util/evsel.c
+util/cpumap.c
+util/thread_map.c
+util/util.c
+util/xyarray.c
+util/cgroup.c
+util/debugfs.c
+util/strlist.c
+../../lib/rbtree.c
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 9dd47a4..e03b58a 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -425,14 +425,14 @@
 static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
 				 PyObject *args, PyObject *kwargs)
 {
-	static char *kwlist[] = { "pid", "tid", NULL };
-	int pid = -1, tid = -1;
+	static char *kwlist[] = { "pid", "tid", "uid", NULL };
+	int pid = -1, tid = -1, uid = UINT_MAX;
 
-	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii",
-					 kwlist, &pid, &tid))
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iii",
+					 kwlist, &pid, &tid, &uid))
 		return -1;
 
-	pthreads->threads = thread_map__new(pid, tid);
+	pthreads->threads = thread_map__new(pid, tid, uid);
 	if (pthreads->threads == NULL)
 		return -1;
 	return 0;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 0b2a487..c2623c6 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -24,7 +24,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
 #include <errno.h>
 
 #include "../../perf.h"
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index b5ca255..002ebbf 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -24,7 +24,7 @@
 		self->fd = STDIN_FILENO;
 
 		if (perf_session__read_header(self, self->fd) < 0)
-			pr_err("incompatible file format");
+			pr_err("incompatible file format (rerun with -v to learn more)");
 
 		return 0;
 	}
@@ -56,7 +56,7 @@
 	}
 
 	if (perf_session__read_header(self, self->fd) < 0) {
-		pr_err("incompatible file format");
+		pr_err("incompatible file format (rerun with -v to learn more)");
 		goto out_close;
 	}
 
@@ -229,6 +229,64 @@
 	return 0;
 }
 
+static const u8 cpumodes[] = {
+	PERF_RECORD_MISC_USER,
+	PERF_RECORD_MISC_KERNEL,
+	PERF_RECORD_MISC_GUEST_USER,
+	PERF_RECORD_MISC_GUEST_KERNEL
+};
+#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
+
+static void ip__resolve_ams(struct machine *self, struct thread *thread,
+			    struct addr_map_symbol *ams,
+			    u64 ip)
+{
+	struct addr_location al;
+	size_t i;
+	u8 m;
+
+	memset(&al, 0, sizeof(al));
+
+	for (i = 0; i < NCPUMODES; i++) {
+		m = cpumodes[i];
+		/*
+		 * We cannot use the header.misc hint to determine whether a
+		 * branch stack address is user, kernel, guest, hypervisor.
+		 * Branches may straddle the kernel/user/hypervisor boundaries.
+		 * Thus, we have to try consecutively until we find a match
+		 * or else, the symbol is unknown
+		 */
+		thread__find_addr_location(thread, self, m, MAP__FUNCTION,
+				ip, &al, NULL);
+		if (al.sym)
+			goto found;
+	}
+found:
+	ams->addr = ip;
+	ams->al_addr = al.addr;
+	ams->sym = al.sym;
+	ams->map = al.map;
+}
+
+struct branch_info *machine__resolve_bstack(struct machine *self,
+					    struct thread *thr,
+					    struct branch_stack *bs)
+{
+	struct branch_info *bi;
+	unsigned int i;
+
+	bi = calloc(bs->nr, sizeof(struct branch_info));
+	if (!bi)
+		return NULL;
+
+	for (i = 0; i < bs->nr; i++) {
+		ip__resolve_ams(self, thr, &bi[i].to, bs->entries[i].to);
+		ip__resolve_ams(self, thr, &bi[i].from, bs->entries[i].from);
+		bi[i].flags = bs->entries[i].flags;
+	}
+	return bi;
+}
+
 int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel,
 			       struct thread *thread,
 			       struct ip_callchain *chain,
@@ -697,6 +755,18 @@
 		       i, sample->callchain->ips[i]);
 }
 
+static void branch_stack__printf(struct perf_sample *sample)
+{
+	uint64_t i;
+
+	printf("... branch stack: nr:%" PRIu64 "\n", sample->branch_stack->nr);
+
+	for (i = 0; i < sample->branch_stack->nr; i++)
+		printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 "\n",
+			i, sample->branch_stack->entries[i].from,
+			sample->branch_stack->entries[i].to);
+}
+
 static void perf_session__print_tstamp(struct perf_session *session,
 				       union perf_event *event,
 				       struct perf_sample *sample)
@@ -744,6 +814,9 @@
 
 	if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
 		callchain__printf(sample);
+
+	if (session->sample_type & PERF_SAMPLE_BRANCH_STACK)
+		branch_stack__printf(sample);
 }
 
 static struct machine *
@@ -796,6 +869,10 @@
 			++session->hists.stats.nr_unknown_id;
 			return -1;
 		}
+		if (machine == NULL) {
+			++session->hists.stats.nr_unprocessable_samples;
+			return -1;
+		}
 		return tool->sample(tool, event, sample, evsel, machine);
 	case PERF_RECORD_MMAP:
 		return tool->mmap(tool, event, sample, machine);
@@ -964,6 +1041,12 @@
  			    session->hists.stats.nr_invalid_chains,
  			    session->hists.stats.nr_events[PERF_RECORD_SAMPLE]);
  	}
+
+	if (session->hists.stats.nr_unprocessable_samples != 0) {
+		ui__warning("%u unprocessable samples recorded.\n"
+			    "Do you have a KVM guest running and not using 'perf kvm'?\n",
+			    session->hists.stats.nr_unprocessable_samples);
+	}
 }
 
 #define session_done()	(*(volatile int *)(&session_done))
@@ -1293,10 +1376,9 @@
 
 void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
 			  struct machine *machine, struct perf_evsel *evsel,
-			  int print_sym, int print_dso)
+			  int print_sym, int print_dso, int print_symoffset)
 {
 	struct addr_location al;
-	const char *symname, *dsoname;
 	struct callchain_cursor *cursor = &evsel->hists.callchain_cursor;
 	struct callchain_cursor_node *node;
 
@@ -1324,20 +1406,13 @@
 
 			printf("\t%16" PRIx64, node->ip);
 			if (print_sym) {
-				if (node->sym && node->sym->name)
-					symname = node->sym->name;
-				else
-					symname = "";
-
-				printf(" %s", symname);
+				printf(" ");
+				symbol__fprintf_symname(node->sym, stdout);
 			}
 			if (print_dso) {
-				if (node->map && node->map->dso && node->map->dso->name)
-					dsoname = node->map->dso->name;
-				else
-					dsoname = "";
-
-				printf(" (%s)", dsoname);
+				printf(" (");
+				map__fprintf_dsoname(al.map, stdout);
+				printf(")");
 			}
 			printf("\n");
 
@@ -1347,21 +1422,18 @@
 	} else {
 		printf("%16" PRIx64, sample->ip);
 		if (print_sym) {
-			if (al.sym && al.sym->name)
-				symname = al.sym->name;
+			printf(" ");
+			if (print_symoffset)
+				symbol__fprintf_symname_offs(al.sym, &al,
+							     stdout);
 			else
-				symname = "";
-
-			printf(" %s", symname);
+				symbol__fprintf_symname(al.sym, stdout);
 		}
 
 		if (print_dso) {
-			if (al.map && al.map->dso && al.map->dso->name)
-				dsoname = al.map->dso->name;
-			else
-				dsoname = "";
-
-			printf(" (%s)", dsoname);
+			printf(" (");
+			map__fprintf_dsoname(al.map, stdout);
+			printf(")");
 		}
 	}
 }
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 37bc383..7a5434c 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -73,6 +73,10 @@
 				    struct ip_callchain *chain,
 				    struct symbol **parent);
 
+struct branch_info *machine__resolve_bstack(struct machine *self,
+					    struct thread *thread,
+					    struct branch_stack *bs);
+
 bool perf_session__has_traces(struct perf_session *self, const char *msg);
 
 void mem_bswap_64(void *src, int byte_size);
@@ -147,7 +151,7 @@
 
 void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
 			  struct machine *machine, struct perf_evsel *evsel,
-			  int print_sym, int print_dso);
+			  int print_sym, int print_dso, int print_symoffset);
 
 int perf_session__cpu_bitmap(struct perf_session *session,
 			     const char *cpu_list, unsigned long *cpu_bitmap);
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index 36d4c56..d0f9f29 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -24,11 +24,11 @@
 build_lib = getenv('PYTHON_EXTBUILD_LIB')
 build_tmp = getenv('PYTHON_EXTBUILD_TMP')
 
+ext_sources = [f.strip() for f in file('util/python-ext-sources')
+				if len(f.strip()) > 0 and f[0] != '#']
+
 perf = Extension('perf',
-		  sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c',
-			     'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c',
-			     'util/util.c', 'util/xyarray.c', 'util/cgroup.c',
-			     'util/debugfs.c'],
+		  sources = ext_sources,
 		  include_dirs = ['util/include'],
 		  extra_compile_args = cflags,
                  )
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 16da30d..a272374 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -8,6 +8,7 @@
 const char	*sort_order = default_sort_order;
 int		sort__need_collapse = 0;
 int		sort__has_parent = 0;
+int		sort__branch_mode = -1; /* -1 = means not set */
 
 enum sort_type	sort__first_dimension;
 
@@ -33,6 +34,9 @@
 		}
 	}
 	va_end(ap);
+
+	if (n >= (int)size)
+		return size - 1;
 	return n;
 }
 
@@ -94,21 +98,10 @@
 	return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
 }
 
-struct sort_entry sort_comm = {
-	.se_header	= "Command",
-	.se_cmp		= sort__comm_cmp,
-	.se_collapse	= sort__comm_collapse,
-	.se_snprintf	= hist_entry__comm_snprintf,
-	.se_width_idx	= HISTC_COMM,
-};
-
-/* --sort dso */
-
-static int64_t
-sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
+static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
 {
-	struct dso *dso_l = left->ms.map ? left->ms.map->dso : NULL;
-	struct dso *dso_r = right->ms.map ? right->ms.map->dso : NULL;
+	struct dso *dso_l = map_l ? map_l->dso : NULL;
+	struct dso *dso_r = map_r ? map_r->dso : NULL;
 	const char *dso_name_l, *dso_name_r;
 
 	if (!dso_l || !dso_r)
@@ -125,18 +118,87 @@
 	return strcmp(dso_name_l, dso_name_r);
 }
 
-static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
-				    size_t size, unsigned int width)
+struct sort_entry sort_comm = {
+	.se_header	= "Command",
+	.se_cmp		= sort__comm_cmp,
+	.se_collapse	= sort__comm_collapse,
+	.se_snprintf	= hist_entry__comm_snprintf,
+	.se_width_idx	= HISTC_COMM,
+};
+
+/* --sort dso */
+
+static int64_t
+sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
 {
-	if (self->ms.map && self->ms.map->dso) {
-		const char *dso_name = !verbose ? self->ms.map->dso->short_name :
-						  self->ms.map->dso->long_name;
+	return _sort__dso_cmp(left->ms.map, right->ms.map);
+}
+
+
+static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
+			      u64 ip_l, u64 ip_r)
+{
+	if (!sym_l || !sym_r)
+		return cmp_null(sym_l, sym_r);
+
+	if (sym_l == sym_r)
+		return 0;
+
+	if (sym_l)
+		ip_l = sym_l->start;
+	if (sym_r)
+		ip_r = sym_r->start;
+
+	return (int64_t)(ip_r - ip_l);
+}
+
+static int _hist_entry__dso_snprintf(struct map *map, char *bf,
+				     size_t size, unsigned int width)
+{
+	if (map && map->dso) {
+		const char *dso_name = !verbose ? map->dso->short_name :
+			map->dso->long_name;
 		return repsep_snprintf(bf, size, "%-*s", width, dso_name);
 	}
 
 	return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
 }
 
+static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
+				    size_t size, unsigned int width)
+{
+	return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
+}
+
+static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
+				     u64 ip, char level, char *bf, size_t size,
+				     unsigned int width __used)
+{
+	size_t ret = 0;
+
+	if (verbose) {
+		char o = map ? dso__symtab_origin(map->dso) : '!';
+		ret += repsep_snprintf(bf, size, "%-#*llx %c ",
+				       BITS_PER_LONG / 4, ip, o);
+	}
+
+	ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
+	if (sym)
+		ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
+				       width - ret,
+				       sym->name);
+	else {
+		size_t len = BITS_PER_LONG / 4;
+		ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
+				       len, ip);
+		ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
+				       width - ret, "");
+	}
+
+	return ret;
+}
+
+
 struct sort_entry sort_dso = {
 	.se_header	= "Shared Object",
 	.se_cmp		= sort__dso_cmp,
@@ -144,8 +206,14 @@
 	.se_width_idx	= HISTC_DSO,
 };
 
-/* --sort symbol */
+static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
+				    size_t size, unsigned int width __used)
+{
+	return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
+					 self->level, bf, size, width);
+}
 
+/* --sort symbol */
 static int64_t
 sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
 {
@@ -163,31 +231,7 @@
 	ip_l = left->ms.sym->start;
 	ip_r = right->ms.sym->start;
 
-	return (int64_t)(ip_r - ip_l);
-}
-
-static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
-				    size_t size, unsigned int width __used)
-{
-	size_t ret = 0;
-
-	if (verbose) {
-		char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!';
-		ret += repsep_snprintf(bf, size, "%-#*llx %c ",
-				       BITS_PER_LONG / 4, self->ip, o);
-	}
-
-	if (!sort_dso.elide)
-		ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level);
-
-	if (self->ms.sym)
-		ret += repsep_snprintf(bf + ret, size - ret, "%s",
-				       self->ms.sym->name);
-	else
-		ret += repsep_snprintf(bf + ret, size - ret, "%-#*llx",
-				       BITS_PER_LONG / 4, self->ip);
-
-	return ret;
+	return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r);
 }
 
 struct sort_entry sort_sym = {
@@ -246,19 +290,155 @@
 	.se_width_idx	= HISTC_CPU,
 };
 
+static int64_t
+sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+	return _sort__dso_cmp(left->branch_info->from.map,
+			      right->branch_info->from.map);
+}
+
+static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf,
+				    size_t size, unsigned int width)
+{
+	return _hist_entry__dso_snprintf(self->branch_info->from.map,
+					 bf, size, width);
+}
+
+struct sort_entry sort_dso_from = {
+	.se_header	= "Source Shared Object",
+	.se_cmp		= sort__dso_from_cmp,
+	.se_snprintf	= hist_entry__dso_from_snprintf,
+	.se_width_idx	= HISTC_DSO_FROM,
+};
+
+static int64_t
+sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+	return _sort__dso_cmp(left->branch_info->to.map,
+			      right->branch_info->to.map);
+}
+
+static int hist_entry__dso_to_snprintf(struct hist_entry *self, char *bf,
+				       size_t size, unsigned int width)
+{
+	return _hist_entry__dso_snprintf(self->branch_info->to.map,
+					 bf, size, width);
+}
+
+static int64_t
+sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+	struct addr_map_symbol *from_l = &left->branch_info->from;
+	struct addr_map_symbol *from_r = &right->branch_info->from;
+
+	if (!from_l->sym && !from_r->sym)
+		return right->level - left->level;
+
+	return _sort__sym_cmp(from_l->sym, from_r->sym, from_l->addr,
+			     from_r->addr);
+}
+
+static int64_t
+sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+	struct addr_map_symbol *to_l = &left->branch_info->to;
+	struct addr_map_symbol *to_r = &right->branch_info->to;
+
+	if (!to_l->sym && !to_r->sym)
+		return right->level - left->level;
+
+	return _sort__sym_cmp(to_l->sym, to_r->sym, to_l->addr, to_r->addr);
+}
+
+static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
+				    size_t size, unsigned int width __used)
+{
+	struct addr_map_symbol *from = &self->branch_info->from;
+	return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
+					 self->level, bf, size, width);
+
+}
+
+static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
+				    size_t size, unsigned int width __used)
+{
+	struct addr_map_symbol *to = &self->branch_info->to;
+	return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
+					 self->level, bf, size, width);
+
+}
+
+struct sort_entry sort_dso_to = {
+	.se_header	= "Target Shared Object",
+	.se_cmp		= sort__dso_to_cmp,
+	.se_snprintf	= hist_entry__dso_to_snprintf,
+	.se_width_idx	= HISTC_DSO_TO,
+};
+
+struct sort_entry sort_sym_from = {
+	.se_header	= "Source Symbol",
+	.se_cmp		= sort__sym_from_cmp,
+	.se_snprintf	= hist_entry__sym_from_snprintf,
+	.se_width_idx	= HISTC_SYMBOL_FROM,
+};
+
+struct sort_entry sort_sym_to = {
+	.se_header	= "Target Symbol",
+	.se_cmp		= sort__sym_to_cmp,
+	.se_snprintf	= hist_entry__sym_to_snprintf,
+	.se_width_idx	= HISTC_SYMBOL_TO,
+};
+
+static int64_t
+sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+	const unsigned char mp = left->branch_info->flags.mispred !=
+					right->branch_info->flags.mispred;
+	const unsigned char p = left->branch_info->flags.predicted !=
+					right->branch_info->flags.predicted;
+
+	return mp || p;
+}
+
+static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf,
+				    size_t size, unsigned int width){
+	static const char *out = "N/A";
+
+	if (self->branch_info->flags.predicted)
+		out = "N";
+	else if (self->branch_info->flags.mispred)
+		out = "Y";
+
+	return repsep_snprintf(bf, size, "%-*s", width, out);
+}
+
+struct sort_entry sort_mispredict = {
+	.se_header	= "Branch Mispredicted",
+	.se_cmp		= sort__mispredict_cmp,
+	.se_snprintf	= hist_entry__mispredict_snprintf,
+	.se_width_idx	= HISTC_MISPREDICT,
+};
+
 struct sort_dimension {
 	const char		*name;
 	struct sort_entry	*entry;
 	int			taken;
 };
 
+#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
+
 static struct sort_dimension sort_dimensions[] = {
-	{ .name = "pid",	.entry = &sort_thread,	},
-	{ .name = "comm",	.entry = &sort_comm,	},
-	{ .name = "dso",	.entry = &sort_dso,	},
-	{ .name = "symbol",	.entry = &sort_sym,	},
-	{ .name = "parent",	.entry = &sort_parent,	},
-	{ .name = "cpu",	.entry = &sort_cpu,	},
+	DIM(SORT_PID, "pid", sort_thread),
+	DIM(SORT_COMM, "comm", sort_comm),
+	DIM(SORT_DSO, "dso", sort_dso),
+	DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
+	DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
+	DIM(SORT_SYM, "symbol", sort_sym),
+	DIM(SORT_SYM_TO, "symbol_from", sort_sym_from),
+	DIM(SORT_SYM_FROM, "symbol_to", sort_sym_to),
+	DIM(SORT_PARENT, "parent", sort_parent),
+	DIM(SORT_CPU, "cpu", sort_cpu),
+	DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
 };
 
 int sort_dimension__add(const char *tok)
@@ -270,7 +450,6 @@
 
 		if (strncasecmp(tok, sd->name, strlen(tok)))
 			continue;
-
 		if (sd->entry == &sort_parent) {
 			int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
 			if (ret) {
@@ -302,6 +481,16 @@
 				sort__first_dimension = SORT_PARENT;
 			else if (!strcmp(sd->name, "cpu"))
 				sort__first_dimension = SORT_CPU;
+			else if (!strcmp(sd->name, "symbol_from"))
+				sort__first_dimension = SORT_SYM_FROM;
+			else if (!strcmp(sd->name, "symbol_to"))
+				sort__first_dimension = SORT_SYM_TO;
+			else if (!strcmp(sd->name, "dso_from"))
+				sort__first_dimension = SORT_DSO_FROM;
+			else if (!strcmp(sd->name, "dso_to"))
+				sort__first_dimension = SORT_DSO_TO;
+			else if (!strcmp(sd->name, "mispredict"))
+				sort__first_dimension = SORT_MISPREDICT;
 		}
 
 		list_add_tail(&sd->entry->list, &hist_entry__sort_list);
@@ -309,7 +498,6 @@
 
 		return 0;
 	}
-
 	return -ESRCH;
 }
 
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 3f67ae3..472aa5a 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -31,11 +31,16 @@
 extern const char default_sort_order[];
 extern int sort__need_collapse;
 extern int sort__has_parent;
+extern int sort__branch_mode;
 extern char *field_sep;
 extern struct sort_entry sort_comm;
 extern struct sort_entry sort_dso;
 extern struct sort_entry sort_sym;
 extern struct sort_entry sort_parent;
+extern struct sort_entry sort_dso_from;
+extern struct sort_entry sort_dso_to;
+extern struct sort_entry sort_sym_from;
+extern struct sort_entry sort_sym_to;
 extern enum sort_type sort__first_dimension;
 
 /**
@@ -72,6 +77,7 @@
 		struct hist_entry *pair;
 		struct rb_root	  sorted_chain;
 	};
+	struct branch_info	*branch_info;
 	struct callchain_root	callchain[0];
 };
 
@@ -82,6 +88,11 @@
 	SORT_SYM,
 	SORT_PARENT,
 	SORT_CPU,
+	SORT_DSO_FROM,
+	SORT_DSO_TO,
+	SORT_SYM_FROM,
+	SORT_SYM_TO,
+	SORT_MISPREDICT,
 };
 
 /*
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index 92e0685..2eeb51b 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include <linux/kernel.h>
 
 int prefixcmp(const char *str, const char *prefix)
 {
@@ -89,14 +90,14 @@
 	if (!strbuf_avail(sb))
 		strbuf_grow(sb, 64);
 	va_start(ap, fmt);
-	len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
+	len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
 	va_end(ap);
 	if (len < 0)
-		die("your vsnprintf is broken");
+		die("your vscnprintf is broken");
 	if (len > strbuf_avail(sb)) {
 		strbuf_grow(sb, len);
 		va_start(ap, fmt);
-		len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
+		len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
 		va_end(ap);
 		if (len > strbuf_avail(sb)) {
 			die("this should not happen, your snprintf is broken");
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 0975438..5dd83c3 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,4 +1,3 @@
-#include <ctype.h>
 #include <dirent.h>
 #include <errno.h>
 #include <libgen.h>
@@ -12,6 +11,7 @@
 #include <unistd.h>
 #include <inttypes.h>
 #include "build-id.h"
+#include "util.h"
 #include "debug.h"
 #include "symbol.h"
 #include "strlist.h"
@@ -263,6 +263,28 @@
 		       sym->name);
 }
 
+size_t symbol__fprintf_symname_offs(const struct symbol *sym,
+				    const struct addr_location *al, FILE *fp)
+{
+	unsigned long offset;
+	size_t length;
+
+	if (sym && sym->name) {
+		length = fprintf(fp, "%s", sym->name);
+		if (al) {
+			offset = al->addr - sym->start;
+			length += fprintf(fp, "+0x%lx", offset);
+		}
+		return length;
+	} else
+		return fprintf(fp, "[unknown]");
+}
+
+size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
+{
+	return symbol__fprintf_symname_offs(sym, NULL, fp);
+}
+
 void dso__set_long_name(struct dso *dso, char *name)
 {
 	if (name == NULL)
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 123c2e1..ac49ef2 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -5,6 +5,7 @@
 #include <stdbool.h>
 #include <stdint.h>
 #include "map.h"
+#include "../perf.h"
 #include <linux/list.h>
 #include <linux/rbtree.h>
 #include <stdio.h>
@@ -70,6 +71,7 @@
 	unsigned short	priv_size;
 	unsigned short	nr_events;
 	bool		try_vmlinux_path,
+			show_kernel_path,
 			use_modules,
 			sort_by_name,
 			show_nr_samples,
@@ -95,7 +97,11 @@
 			*col_width_list_str;
        struct strlist	*dso_list,
 			*comm_list,
-			*sym_list;
+			*sym_list,
+			*dso_from_list,
+			*dso_to_list,
+			*sym_from_list,
+			*sym_to_list;
 	const char	*symfs;
 };
 
@@ -119,6 +125,19 @@
 	bool	      has_children;
 };
 
+struct addr_map_symbol {
+	struct map    *map;
+	struct symbol *sym;
+	u64	      addr;
+	u64	      al_addr;
+};
+
+struct branch_info {
+	struct addr_map_symbol from;
+	struct addr_map_symbol to;
+	struct branch_flags flags;
+};
+
 struct addr_location {
 	struct thread *thread;
 	struct map    *map;
@@ -241,6 +260,9 @@
 
 int symbol__init(void);
 void symbol__exit(void);
+size_t symbol__fprintf_symname_offs(const struct symbol *sym,
+				    const struct addr_location *al, FILE *fp);
+size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
 bool symbol_type__is_a(char symbol_type, enum map_type map_type);
 
 size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c
new file mode 100644
index 0000000..48c6902
--- /dev/null
+++ b/tools/perf/util/sysfs.c
@@ -0,0 +1,60 @@
+
+#include "util.h"
+#include "sysfs.h"
+
+static const char * const sysfs_known_mountpoints[] = {
+	"/sys",
+	0,
+};
+
+static int sysfs_found;
+char sysfs_mountpoint[PATH_MAX];
+
+static int sysfs_valid_mountpoint(const char *sysfs)
+{
+	struct statfs st_fs;
+
+	if (statfs(sysfs, &st_fs) < 0)
+		return -ENOENT;
+	else if (st_fs.f_type != (long) SYSFS_MAGIC)
+		return -ENOENT;
+
+	return 0;
+}
+
+const char *sysfs_find_mountpoint(void)
+{
+	const char * const *ptr;
+	char type[100];
+	FILE *fp;
+
+	if (sysfs_found)
+		return (const char *) sysfs_mountpoint;
+
+	ptr = sysfs_known_mountpoints;
+	while (*ptr) {
+		if (sysfs_valid_mountpoint(*ptr) == 0) {
+			sysfs_found = 1;
+			strcpy(sysfs_mountpoint, *ptr);
+			return sysfs_mountpoint;
+		}
+		ptr++;
+	}
+
+	/* give up and parse /proc/mounts */
+	fp = fopen("/proc/mounts", "r");
+	if (fp == NULL)
+		return NULL;
+
+	while (!sysfs_found &&
+	       fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
+		      sysfs_mountpoint, type) == 2) {
+
+		if (strcmp(type, "sysfs") == 0)
+			sysfs_found = 1;
+	}
+
+	fclose(fp);
+
+	return sysfs_found ? sysfs_mountpoint : NULL;
+}
diff --git a/tools/perf/util/sysfs.h b/tools/perf/util/sysfs.h
new file mode 100644
index 0000000..a813b72
--- /dev/null
+++ b/tools/perf/util/sysfs.h
@@ -0,0 +1,6 @@
+#ifndef __SYSFS_H__
+#define __SYSFS_H__
+
+const char *sysfs_find_mountpoint(void);
+
+#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index a5df131..84d9bd78 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -1,6 +1,13 @@
 #include <dirent.h>
+#include <limits.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "strlist.h"
+#include <string.h>
 #include "thread_map.h"
 
 /* Skip "." and ".." directories */
@@ -23,7 +30,7 @@
 	sprintf(name, "/proc/%d/task", pid);
 	items = scandir(name, &namelist, filter, NULL);
 	if (items <= 0)
-                return NULL;
+		return NULL;
 
 	threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
 	if (threads != NULL) {
@@ -51,14 +58,240 @@
 	return threads;
 }
 
-struct thread_map *thread_map__new(pid_t pid, pid_t tid)
+struct thread_map *thread_map__new_by_uid(uid_t uid)
+{
+	DIR *proc;
+	int max_threads = 32, items, i;
+	char path[256];
+	struct dirent dirent, *next, **namelist = NULL;
+	struct thread_map *threads = malloc(sizeof(*threads) +
+					    max_threads * sizeof(pid_t));
+	if (threads == NULL)
+		goto out;
+
+	proc = opendir("/proc");
+	if (proc == NULL)
+		goto out_free_threads;
+
+	threads->nr = 0;
+
+	while (!readdir_r(proc, &dirent, &next) && next) {
+		char *end;
+		bool grow = false;
+		struct stat st;
+		pid_t pid = strtol(dirent.d_name, &end, 10);
+
+		if (*end) /* only interested in proper numerical dirents */
+			continue;
+
+		snprintf(path, sizeof(path), "/proc/%s", dirent.d_name);
+
+		if (stat(path, &st) != 0)
+			continue;
+
+		if (st.st_uid != uid)
+			continue;
+
+		snprintf(path, sizeof(path), "/proc/%d/task", pid);
+		items = scandir(path, &namelist, filter, NULL);
+		if (items <= 0)
+			goto out_free_closedir;
+
+		while (threads->nr + items >= max_threads) {
+			max_threads *= 2;
+			grow = true;
+		}
+
+		if (grow) {
+			struct thread_map *tmp;
+
+			tmp = realloc(threads, (sizeof(*threads) +
+						max_threads * sizeof(pid_t)));
+			if (tmp == NULL)
+				goto out_free_namelist;
+
+			threads = tmp;
+		}
+
+		for (i = 0; i < items; i++)
+			threads->map[threads->nr + i] = atoi(namelist[i]->d_name);
+
+		for (i = 0; i < items; i++)
+			free(namelist[i]);
+		free(namelist);
+
+		threads->nr += items;
+	}
+
+out_closedir:
+	closedir(proc);
+out:
+	return threads;
+
+out_free_threads:
+	free(threads);
+	return NULL;
+
+out_free_namelist:
+	for (i = 0; i < items; i++)
+		free(namelist[i]);
+	free(namelist);
+
+out_free_closedir:
+	free(threads);
+	threads = NULL;
+	goto out_closedir;
+}
+
+struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid)
 {
 	if (pid != -1)
 		return thread_map__new_by_pid(pid);
+
+	if (tid == -1 && uid != UINT_MAX)
+		return thread_map__new_by_uid(uid);
+
 	return thread_map__new_by_tid(tid);
 }
 
+static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
+{
+	struct thread_map *threads = NULL, *nt;
+	char name[256];
+	int items, total_tasks = 0;
+	struct dirent **namelist = NULL;
+	int i, j = 0;
+	pid_t pid, prev_pid = INT_MAX;
+	char *end_ptr;
+	struct str_node *pos;
+	struct strlist *slist = strlist__new(false, pid_str);
+
+	if (!slist)
+		return NULL;
+
+	strlist__for_each(pos, slist) {
+		pid = strtol(pos->s, &end_ptr, 10);
+
+		if (pid == INT_MIN || pid == INT_MAX ||
+		    (*end_ptr != '\0' && *end_ptr != ','))
+			goto out_free_threads;
+
+		if (pid == prev_pid)
+			continue;
+
+		sprintf(name, "/proc/%d/task", pid);
+		items = scandir(name, &namelist, filter, NULL);
+		if (items <= 0)
+			goto out_free_threads;
+
+		total_tasks += items;
+		nt = realloc(threads, (sizeof(*threads) +
+				       sizeof(pid_t) * total_tasks));
+		if (nt == NULL)
+			goto out_free_threads;
+
+		threads = nt;
+
+		if (threads) {
+			for (i = 0; i < items; i++)
+				threads->map[j++] = atoi(namelist[i]->d_name);
+			threads->nr = total_tasks;
+		}
+
+		for (i = 0; i < items; i++)
+			free(namelist[i]);
+		free(namelist);
+
+		if (!threads)
+			break;
+	}
+
+out:
+	strlist__delete(slist);
+	return threads;
+
+out_free_threads:
+	free(threads);
+	threads = NULL;
+	goto out;
+}
+
+static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
+{
+	struct thread_map *threads = NULL, *nt;
+	int ntasks = 0;
+	pid_t tid, prev_tid = INT_MAX;
+	char *end_ptr;
+	struct str_node *pos;
+	struct strlist *slist;
+
+	/* perf-stat expects threads to be generated even if tid not given */
+	if (!tid_str) {
+		threads = malloc(sizeof(*threads) + sizeof(pid_t));
+		if (threads != NULL) {
+			threads->map[0] = -1;
+			threads->nr	= 1;
+		}
+		return threads;
+	}
+
+	slist = strlist__new(false, tid_str);
+	if (!slist)
+		return NULL;
+
+	strlist__for_each(pos, slist) {
+		tid = strtol(pos->s, &end_ptr, 10);
+
+		if (tid == INT_MIN || tid == INT_MAX ||
+		    (*end_ptr != '\0' && *end_ptr != ','))
+			goto out_free_threads;
+
+		if (tid == prev_tid)
+			continue;
+
+		ntasks++;
+		nt = realloc(threads, sizeof(*threads) + sizeof(pid_t) * ntasks);
+
+		if (nt == NULL)
+			goto out_free_threads;
+
+		threads = nt;
+		threads->map[ntasks - 1] = tid;
+		threads->nr		 = ntasks;
+	}
+out:
+	return threads;
+
+out_free_threads:
+	free(threads);
+	threads = NULL;
+	goto out;
+}
+
+struct thread_map *thread_map__new_str(const char *pid, const char *tid,
+				       uid_t uid)
+{
+	if (pid)
+		return thread_map__new_by_pid_str(pid);
+
+	if (!tid && uid != UINT_MAX)
+		return thread_map__new_by_uid(uid);
+
+	return thread_map__new_by_tid_str(tid);
+}
+
 void thread_map__delete(struct thread_map *threads)
 {
 	free(threads);
 }
+
+size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
+{
+	int i;
+	size_t printed = fprintf(fp, "%d thread%s: ",
+				 threads->nr, threads->nr > 1 ? "s" : "");
+	for (i = 0; i < threads->nr; ++i)
+		printed += fprintf(fp, "%s%d", i ? ", " : "", threads->map[i]);
+
+	return printed + fprintf(fp, "\n");
+}
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index 3cb9073..7da80f1 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -2,6 +2,7 @@
 #define __PERF_THREAD_MAP_H
 
 #include <sys/types.h>
+#include <stdio.h>
 
 struct thread_map {
 	int nr;
@@ -10,6 +11,14 @@
 
 struct thread_map *thread_map__new_by_pid(pid_t pid);
 struct thread_map *thread_map__new_by_tid(pid_t tid);
-struct thread_map *thread_map__new(pid_t pid, pid_t tid);
+struct thread_map *thread_map__new_by_uid(uid_t uid);
+struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid);
+
+struct thread_map *thread_map__new_str(const char *pid,
+		const char *tid, uid_t uid);
+
 void thread_map__delete(struct thread_map *threads);
+
+size_t thread_map__fprintf(struct thread_map *threads, FILE *fp);
+
 #endif	/* __PERF_THREAD_MAP_H */
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 500471d..09fe579 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -69,12 +69,15 @@
 
 	ret += SNPRINTF(bf + ret, size - ret, "], ");
 
-	if (top->target_pid != -1)
-		ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %d",
+	if (top->target_pid)
+		ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s",
 				top->target_pid);
-	else if (top->target_tid != -1)
-		ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %d",
+	else if (top->target_tid)
+		ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s",
 				top->target_tid);
+	else if (top->uid_str != NULL)
+		ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
+				top->uid_str);
 	else
 		ret += SNPRINTF(bf + ret, size - ret, " (all");
 
@@ -82,7 +85,7 @@
 		ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
 				top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list);
 	else {
-		if (top->target_tid != -1)
+		if (top->target_tid)
 			ret += SNPRINTF(bf + ret, size - ret, ")");
 		else
 			ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index f2eab81..ce61cb2 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -23,7 +23,8 @@
 	u64		   guest_us_samples, guest_kernel_samples;
 	int		   print_entries, count_filter, delay_secs;
 	int		   freq;
-	pid_t		   target_pid, target_tid;
+	const char	   *target_pid, *target_tid;
+	uid_t		   uid;
 	bool		   hide_kernel_symbols, hide_user_symbols, zero;
 	bool		   system_wide;
 	bool		   use_tui, use_stdio;
@@ -33,7 +34,7 @@
 	bool		   vmlinux_warned;
 	bool		   inherit;
 	bool		   group;
-	bool		   sample_id_all_avail;
+	bool		   sample_id_all_missing;
 	bool		   exclude_guest_missing;
 	bool		   dump_symtab;
 	const char	   *cpu_list;
@@ -46,6 +47,7 @@
 	int		   realtime_prio;
 	int		   sym_pcnt_filter;
 	const char	   *sym_filter;
+	const char	   *uid_str;
 };
 
 size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 1a8d4dc..a4088ce 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -25,7 +25,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
 #include <errno.h>
 
 #include "../perf.h"
@@ -1424,6 +1423,11 @@
 				die("unknown op '%s'", arg->op.op);
 			}
 			break;
+		case '+':
+			left = arg_num_eval(arg->op.left);
+			right = arg_num_eval(arg->op.right);
+			val = left + right;
+			break;
 		default:
 			die("unknown op '%s'", arg->op.op);
 		}
@@ -1484,6 +1488,13 @@
 
 		free_token(token);
 		type = process_arg(event, arg, &token);
+
+		if (type == EVENT_OP)
+			type = process_op(event, arg, &token);
+
+		if (type == EVENT_ERROR)
+			goto out_free;
+
 		if (test_type_token(type, token, EVENT_DELIM, ","))
 			goto out_free;
 
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index f55cc3a..b9592e0 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -33,7 +33,6 @@
 #include <pthread.h>
 #include <fcntl.h>
 #include <unistd.h>
-#include <ctype.h>
 #include <errno.h>
 
 #include "../perf.h"
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index a3fdf55..18ae6c1 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
 #include <errno.h>
 
 #include "../perf.h"
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
index 295a9c9..57a4c6e 100644
--- a/tools/perf/util/ui/browsers/annotate.c
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -69,14 +69,17 @@
 	if (!self->navkeypressed)
 		width += 1;
 
+	if (!ab->hide_src_code && ol->offset != -1)
+		if (!current_entry || (self->use_navkeypressed &&
+				       !self->navkeypressed))
+			ui_browser__set_color(self, HE_COLORSET_CODE);
+
 	if (!*ol->line)
 		slsmg_write_nstring(" ", width - 18);
 	else
 		slsmg_write_nstring(ol->line, width - 18);
 
-	if (!current_entry)
-		ui_browser__set_color(self, HE_COLORSET_CODE);
-	else
+	if (current_entry)
 		ab->selection = ol;
 }
 
@@ -230,9 +233,9 @@
 	struct rb_node *nd = NULL;
 	struct map_symbol *ms = self->b.priv;
 	struct symbol *sym = ms->sym;
-	const char *help = "<-, ESC: exit, TAB/shift+TAB: cycle hottest lines, "
-			   "H: Hottest, -> Line action, S -> Toggle source "
-			   "code view";
+	const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, "
+			   "H: Go to hottest line, ->/ENTER: Line action, "
+			   "S: Toggle source code view";
 	int key;
 
 	if (ui_browser__show(&self->b, sym->name, help) < 0)
@@ -284,9 +287,11 @@
 				nd = self->curr_hot;
 			break;
 		case 'H':
+		case 'h':
 			nd = self->curr_hot;
 			break;
 		case 'S':
+		case 's':
 			if (annotate_browser__toggle_source(self))
 				ui_helpline__puts(help);
 			continue;
@@ -338,6 +343,7 @@
 				pthread_mutex_unlock(&notes->lock);
 				symbol__tui_annotate(target, ms->map, evidx,
 						     timer, arg, delay_secs);
+				ui_browser__show_title(&self->b, sym->name);
 			}
 			continue;
 		case K_LEFT:
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index e81aef1..fa530fc 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -805,8 +805,11 @@
 		self->hists = hists;
 		self->b.refresh = hist_browser__refresh;
 		self->b.seek = ui_browser__hists_seek;
-		self->b.use_navkeypressed = true,
-		self->has_symbols = sort_sym.list.next != NULL;
+		self->b.use_navkeypressed = true;
+		if (sort__branch_mode == 1)
+			self->has_symbols = sort_sym_from.list.next != NULL;
+		else
+			self->has_symbols = sort_sym.list.next != NULL;
 	}
 
 	return self;
@@ -837,19 +840,32 @@
 	unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
 
 	nr_events = convert_unit(nr_events, &unit);
-	printed = snprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
+	printed = scnprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
 
-	if (thread)
+	if (self->uid_filter_str)
 		printed += snprintf(bf + printed, size - printed,
+				    ", UID: %s", self->uid_filter_str);
+	if (thread)
+		printed += scnprintf(bf + printed, size - printed,
 				    ", Thread: %s(%d)",
 				    (thread->comm_set ? thread->comm : ""),
 				    thread->pid);
 	if (dso)
-		printed += snprintf(bf + printed, size - printed,
+		printed += scnprintf(bf + printed, size - printed,
 				    ", DSO: %s", dso->short_name);
 	return printed;
 }
 
+static inline void free_popup_options(char **options, int n)
+{
+	int i;
+
+	for (i = 0; i < n; ++i) {
+		free(options[i]);
+		options[i] = NULL;
+	}
+}
+
 static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
 				    const char *helpline, const char *ev_name,
 				    bool left_exits,
@@ -858,7 +874,10 @@
 {
 	struct hists *self = &evsel->hists;
 	struct hist_browser *browser = hist_browser__new(self);
+	struct branch_info *bi;
 	struct pstack *fstack;
+	char *options[16];
+	int nr_options = 0;
 	int key = -1;
 
 	if (browser == NULL)
@@ -870,13 +889,16 @@
 
 	ui_helpline__push(helpline);
 
+	memset(options, 0, sizeof(options));
+
 	while (1) {
 		const struct thread *thread = NULL;
 		const struct dso *dso = NULL;
-		char *options[16];
-		int nr_options = 0, choice = 0, i,
+		int choice = 0,
 		    annotate = -2, zoom_dso = -2, zoom_thread = -2,
-		    browse_map = -2;
+		    annotate_f = -2, annotate_t = -2, browse_map = -2;
+
+		nr_options = 0;
 
 		key = hist_browser__run(browser, ev_name, timer, arg, delay_secs);
 
@@ -884,7 +906,6 @@
 			thread = hist_browser__selected_thread(browser);
 			dso = browser->selection->map ? browser->selection->map->dso : NULL;
 		}
-
 		switch (key) {
 		case K_TAB:
 		case K_UNTAB:
@@ -899,7 +920,7 @@
 			if (!browser->has_symbols) {
 				ui_browser__warning(&browser->b, delay_secs * 2,
 			"Annotation is only available for symbolic views, "
-			"include \"sym\" in --sort to use it.");
+			"include \"sym*\" in --sort to use it.");
 				continue;
 			}
 
@@ -969,12 +990,34 @@
 		if (!browser->has_symbols)
 			goto add_exit_option;
 
-		if (browser->selection != NULL &&
-		    browser->selection->sym != NULL &&
-		    !browser->selection->map->dso->annotate_warned &&
-		    asprintf(&options[nr_options], "Annotate %s",
-			     browser->selection->sym->name) > 0)
-			annotate = nr_options++;
+		if (sort__branch_mode == 1) {
+			bi = browser->he_selection->branch_info;
+			if (browser->selection != NULL &&
+			    bi &&
+			    bi->from.sym != NULL &&
+			    !bi->from.map->dso->annotate_warned &&
+				asprintf(&options[nr_options], "Annotate %s",
+					 bi->from.sym->name) > 0)
+				annotate_f = nr_options++;
+
+			if (browser->selection != NULL &&
+			    bi &&
+			    bi->to.sym != NULL &&
+			    !bi->to.map->dso->annotate_warned &&
+			    (bi->to.sym != bi->from.sym ||
+			     bi->to.map->dso != bi->from.map->dso) &&
+				asprintf(&options[nr_options], "Annotate %s",
+					 bi->to.sym->name) > 0)
+				annotate_t = nr_options++;
+		} else {
+
+			if (browser->selection != NULL &&
+			    browser->selection->sym != NULL &&
+			    !browser->selection->map->dso->annotate_warned &&
+				asprintf(&options[nr_options], "Annotate %s",
+					 browser->selection->sym->name) > 0)
+				annotate = nr_options++;
+		}
 
 		if (thread != NULL &&
 		    asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
@@ -995,25 +1038,39 @@
 			browse_map = nr_options++;
 add_exit_option:
 		options[nr_options++] = (char *)"Exit";
-
+retry_popup_menu:
 		choice = ui__popup_menu(nr_options, options);
 
-		for (i = 0; i < nr_options - 1; ++i)
-			free(options[i]);
-
 		if (choice == nr_options - 1)
 			break;
 
-		if (choice == -1)
+		if (choice == -1) {
+			free_popup_options(options, nr_options - 1);
 			continue;
+		}
 
-		if (choice == annotate) {
+		if (choice == annotate || choice == annotate_t || choice == annotate_f) {
 			struct hist_entry *he;
 			int err;
 do_annotate:
 			he = hist_browser__selected_entry(browser);
 			if (he == NULL)
 				continue;
+
+			/*
+			 * we stash the branch_info symbol + map into the
+			 * the ms so we don't have to rewrite all the annotation
+			 * code to use branch_info.
+			 * in branch mode, the ms struct is not used
+			 */
+			if (choice == annotate_f) {
+				he->ms.sym = he->branch_info->from.sym;
+				he->ms.map = he->branch_info->from.map;
+			}  else if (choice == annotate_t) {
+				he->ms.sym = he->branch_info->to.sym;
+				he->ms.map = he->branch_info->to.map;
+			}
+
 			/*
 			 * Don't let this be freed, say, by hists__decay_entry.
 			 */
@@ -1021,9 +1078,18 @@
 			err = hist_entry__tui_annotate(he, evsel->idx,
 						       timer, arg, delay_secs);
 			he->used = false;
+			/*
+			 * offer option to annotate the other branch source or target
+			 * (if they exists) when returning from annotate
+			 */
+			if ((err == 'q' || err == CTRL('c'))
+			    && annotate_t != -2 && annotate_f != -2)
+				goto retry_popup_menu;
+
 			ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
 			if (err)
 				ui_browser__handle_resize(&browser->b);
+
 		} else if (choice == browse_map)
 			map__browse(browser->selection->map);
 		else if (choice == zoom_dso) {
@@ -1069,6 +1135,7 @@
 	pstack__delete(fstack);
 out:
 	hist_browser__delete(browser);
+	free_popup_options(options, nr_options - 1);
 	return key;
 }
 
@@ -1095,7 +1162,7 @@
 						       HE_COLORSET_NORMAL);
 
 	nr_events = convert_unit(nr_events, &unit);
-	printed = snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
+	printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
 			   unit, unit == ' ' ? "" : " ", ev_name);
 	slsmg_printf("%s", bf);
 
@@ -1105,8 +1172,8 @@
 		if (!current_entry)
 			ui_browser__set_color(browser, HE_COLORSET_TOP);
 		nr_events = convert_unit(nr_events, &unit);
-		snprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", nr_events,
-			 unit, unit == ' ' ? "" : " ");
+		printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
+				     nr_events, unit, unit == ' ' ? "" : " ");
 		warn = bf;
 	}
 
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c
index 6905bcc..eca6575 100644
--- a/tools/perf/util/ui/browsers/map.c
+++ b/tools/perf/util/ui/browsers/map.c
@@ -3,9 +3,9 @@
 #include <newt.h>
 #include <inttypes.h>
 #include <sys/ttydefaults.h>
-#include <ctype.h>
 #include <string.h>
 #include <linux/bitops.h>
+#include "../../util.h"
 #include "../../debug.h"
 #include "../../symbol.h"
 #include "../browser.h"
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c
index 4f48f59..2f950c2 100644
--- a/tools/perf/util/ui/helpline.c
+++ b/tools/perf/util/ui/helpline.c
@@ -64,7 +64,7 @@
 	static int backlog;
 
 	pthread_mutex_lock(&ui__lock);
-	ret = vsnprintf(ui_helpline__last_msg + backlog,
+	ret = vscnprintf(ui_helpline__last_msg + backlog,
 			sizeof(ui_helpline__last_msg) - backlog, format, ap);
 	backlog += ret;
 
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c
index d76d1c0..52bb07c 100644
--- a/tools/perf/util/usage.c
+++ b/tools/perf/util/usage.c
@@ -7,6 +7,7 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 #include "util.h"
+#include "debug.h"
 
 static void report(const char *prefix, const char *err, va_list params)
 {
@@ -81,3 +82,41 @@
 	warn_routine(warn, params);
 	va_end(params);
 }
+
+uid_t parse_target_uid(const char *str, const char *tid, const char *pid)
+{
+	struct passwd pwd, *result;
+	char buf[1024];
+
+	if (str == NULL)
+		return UINT_MAX;
+
+	/* UID and PID are mutually exclusive */
+	if (tid || pid) {
+		ui__warning("PID/TID switch overriding UID\n");
+		sleep(1);
+		return UINT_MAX;
+	}
+
+	getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
+
+	if (result == NULL) {
+		char *endptr;
+		int uid = strtol(str, &endptr, 10);
+
+		if (*endptr != '\0') {
+			ui__error("Invalid user %s\n", str);
+			return UINT_MAX - 1;
+		}
+
+		getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
+
+		if (result == NULL) {
+			ui__error("Problems obtaining information for user %s\n",
+				  str);
+			return UINT_MAX - 1;
+		}
+	}
+
+	return result->pw_uid;
+}
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index fb25d13..8109a90 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -14,6 +14,8 @@
 		attr->exclude_host  = 1;
 	if (!perf_guest)
 		attr->exclude_guest = 1;
+	/* to capture ABI version */
+	attr->size = sizeof(*attr);
 }
 
 int mkdir_p(char *path, mode_t mode)
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index ecf9898..0f99f39 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -199,6 +199,8 @@
 #undef isalpha
 #undef isprint
 #undef isalnum
+#undef islower
+#undef isupper
 #undef tolower
 #undef toupper
 
@@ -219,6 +221,8 @@
 #define isalpha(x) sane_istest(x,GIT_ALPHA)
 #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
 #define isprint(x) sane_istest(x,GIT_PRINT)
+#define islower(x) (sane_istest(x,GIT_ALPHA) && sane_istest(x,0x20))
+#define isupper(x) (sane_istest(x,GIT_ALPHA) && !sane_istest(x,0x20))
 #define tolower(x) sane_case((unsigned char)(x), 0x20)
 #define toupper(x) sane_case((unsigned char)(x), 0)
 
@@ -245,6 +249,8 @@
 
 void event_attr_init(struct perf_event_attr *attr);
 
+uid_t parse_target_uid(const char *str, const char *tid, const char *pid);
+
 #define _STR(x) #x
 #define STR(x) _STR(x)
 
diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c
index b9c7986..53452c3 100644
--- a/tools/usb/ffs-test.c
+++ b/tools/usb/ffs-test.c
@@ -2,7 +2,7 @@
  * ffs-test.c.c -- user mode filesystem api for usb composite function
  *
  * Copyright (C) 2010 Samsung Electronics
- *                    Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ *                    Author: Michal Nazarewicz <mina86@mina86.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
diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c
index f08e894..6e0f567 100644
--- a/tools/usb/testusb.c
+++ b/tools/usb/testusb.c
@@ -3,7 +3,7 @@
 /*
  * Copyright (c) 2002 by David Brownell
  * Copyright (c) 2010 by Samsung Electronics
- * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ * Author: Michal Nazarewicz <mina86@mina86.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